3

The goals is to move files out of the lowest level folder, back up one directory.

This does a great job but moves files higher up the folder hierarchy as well.

find . -name '*.jpg' -type f -execdir mv '{}' ../ \;

So if these jpgs were sat in a folder called 'photos', I want to move them up one level eg)

../

I've tried changing the '*.jpg' parameter to include the folder and tried using the folder instead of the dot after file. Also tried -maxdepth and -mindepth but they had no effect.

EDIT: This is for multiple folders i.e. it needs to recurse through an entire drive.

  • If all .jpg's are in the same folder you can use mv -t ../ *.jpg ....if they on different folders then your command will move each of them to their respective parent directories.do you want to move them to the same directory? – heemayl May 26 '15 at 22:48
  • I don't understand. What do you need that cd photos; mv *jpg ../ or mv /path/to/photos/*jpg /path/to won't do? Do you have multiple directories? – terdon May 26 '15 at 23:12
  • So, you want to traverse whole directory tree and move each file to its respective parent directory? Is that precise ? – heemayl May 27 '15 at 11:53
  • Just jpgs contained in folders called 'photos'. Any other jpgs should not be moved. – JohnnyBizzle May 27 '15 at 11:59
  • 1
    Check my answer then.. – heemayl May 27 '15 at 12:48
1

Move files from the lowest sub directory up one level

The script below searches a directory for the lowest sub directory (= without sub directories) recursively and moves all found files in the folder(s) up one level, as literally asked for in The goals is to move files out of the lowest level folder, back up one directory:

#!/usr/bin/env python2
import shutil
import os
import sys

directory = sys.argv[1] 

for root, dirs, files in os.walk(directory):
    for dr in dirs:
        dr = root+"/"+dr
        # find folders without subfolders (= lowest level)
        if len(next(os.walk(dr))[1]) == 0:
            # direct superior directory
            up = dr[:dr.rfind("/")]
            # move files from lowest level one level up
            for f in os.listdir(dr):
                shutil.move(dr+"/"+f, up+"/"+f)

To use:

  1. Copy the script into an empty file, save it as reorganize.py
  2. Run it by the command:

    python /path/to/reorganize.py <directory_to_reorganize>
    

    If the name of your directory (to reorganize) contains spaces, use quotes:

    python /path/to/reorganize.py '<directory_to_reorganize>'
    

EDIT

As mentioned in a comment, with a little change, the script can be used to only move files from a folder name up one level. The moste efficient way is to do that directly after

for dr in dirs:

Then the script would be:

#!/usr/bin/env python3
import shutil
import os
import sys

directory = sys.argv[1]

for root, dirs, files in os.walk(directory):
    for dr in dirs:
        if dr == "<folder_name>":
            dr = root+"/"+dr
            # direct superior directory
            up = dr[:dr.rfind("/")]
            # move files from lowest level one level up
            for f in os.listdir(dr):
                shutil.move(dr+"/"+f, up+"/"+f)
  • I presume you can modify this to only look for specific folders, presumably another condition in the if len(next... statement. – JohnnyBizzle May 27 '15 at 12:56
  • @JohnnyBizzle absolutely, what do you have in mind? – Jacob Vlijm May 27 '15 at 12:57
  • I get the error... /usr/bin/python3: can't find 'main' module in '/<my folder>' – JohnnyBizzle May 27 '15 at 17:54
  • @JohnnyBizzle What is your Ubuntu version? – Jacob Vlijm May 27 '15 at 17:57
  • My ubuntu version is 12.04. It said install python3 which I did. – JohnnyBizzle May 28 '15 at 7:31
1

The following will move all .jpg files to their respective parent directories if the .jpg files are only under the directory named photos (there can be multiple directory named photos):

find . -type f -path '*/photos/*' -not -path '*/photos/*/*' -name '*.jpg' \
-execdir mv -i {} .. \;

-path '*/photos/*' will ensure that the path will contain photos but the files can only be under the the photos directory (-not -path '*/photos/*/*').

Also note that, if the directories not to travel (not photos) are fixed and smaller in numbers or has specific patterns then you might be interested in -prune too.

  • I got the error find: paths must precede expression: -execdir presumably because of the slash after jpg'. No files moved after removing this slash. – JohnnyBizzle May 27 '15 at 17:41
  • @JohnnyBizzle You might have removed quotes..quotes are important..use exactly as i did.. – heemayl May 27 '15 at 17:46
1

If all your target files are in directories named photos, you could do something like:

find . -type d -name photos -exec bash -c 'cd {} && mv *jpg ../' \;

That will look for directories names photos, then launch a bash shell that will cd into each of them and move all .jpg files to the parent directory.

  • Why is the directory name not in quotes? PS. Didn't work. – JohnnyBizzle May 27 '15 at 17:48
  • @JohnnyBizzle no need for quotes, there's no wildcard and it's not a variable, just a simple string. How did it fail? You need to run it from the parent directory of the photos dirs. It will work as long as all the target folders are named exactly photos – terdon May 27 '15 at 17:53
  • The command ran without errors, it just didn't move any files. – JohnnyBizzle May 28 '15 at 7:33
  • @JohnnyBizzle could the directories be named Photos instead? Did you run it from the correct directory? Try running find /home/terdon/foo/ -type d -name photos -exec bash -c "ls {}/*" \;, does that return anything? If not, you are in the wrong place or the directories have different names. Feel free to ping me in chat, I'd be happy to help. – terdon May 28 '15 at 14:03
0

Will find the lowest level in every directory branch and use it as a base for your find and move '*.jpg' up one level.

#!/bin/bash

treedir="."
mapfile -d '' < <(find "$treedir" -depth -type d -print0)

L=""
A=()
for D in "${MAPFILE[@]}"; do
    [[ $L != $D/* ]] && A+=("$D"); L="$D"
done

for basedir in "${A[@]}"; do
    find "$basedir" -name '*.jpg' -type f -execdir mv -i -t .. '{}' \;
done

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.