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.

10
  • 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, 2015 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, 2015 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, 2015 at 11:53
  • Just jpgs contained in folders called 'photos'. Any other jpgs should not be moved. May 27, 2015 at 11:59
  • 1
    Check my answer then..
    – heemayl
    May 27, 2015 at 12:48

4 Answers 4

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)
8
  • I presume you can modify this to only look for specific folders, presumably another condition in the if len(next... statement. May 27, 2015 at 12:56
  • @JohnnyBizzle absolutely, what do you have in mind? May 27, 2015 at 12:57
  • I get the error... /usr/bin/python3: can't find 'main' module in '/<my folder>' May 27, 2015 at 17:54
  • @JohnnyBizzle What is your Ubuntu version? May 27, 2015 at 17:57
  • My ubuntu version is 12.04. It said install python3 which I did. May 28, 2015 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.

2
  • I got the error find: paths must precede expression: -execdir presumably because of the slash after jpg'. No files moved after removing this slash. May 27, 2015 at 17:41
  • @JohnnyBizzle You might have removed quotes..quotes are important..use exactly as i did..
    – heemayl
    May 27, 2015 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.

4
  • Why is the directory name not in quotes? PS. Didn't work. May 27, 2015 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, 2015 at 17:53
  • The command ran without errors, it just didn't move any files. May 28, 2015 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, 2015 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

You must log in to answer this question.

Not the answer you're looking for? Browse other questions tagged .