user2480690
user2480690

Reputation: 155

How to move and rename files based on parent folder in Linux?

I have a folder named photos with the following structure:

00001/photo.jpg
00002/photo.jpg
00003/photo.jpg

I want to:

  1. Rename the file within the folder (which called photo.jpg) to parent folder.
  2. Move it a folder up.
  3. Remove the parent folder.

So the photos folder would be something like this:

00001.jpg
00002.jpg
00003.jpg

How can I do this in Terminal in Linux?

Note. There are 100000+ such folders in photos.

Upvotes: 5

Views: 5297

Answers (6)

axon
axon

Reputation: 1200

A simple way that I've used takes the output from something like ls */*.jpg (or just ls */*) and process the output to form a move command like mv 00001/photo.jpg ./00001.jpg, and you can then easily clean-up the empty folders with a similar approach using rmdir 00001.

To do it this using awk at the bash terminal type:

ls */* | awk -F'/' '{print "mv " $0 " ./" $1 "_" $2 }' | bash
ls */ | awk -F'/' '{print "rmdir " $1 }' | bash

You can easily preview your commands before running them by leaving off the | bash at the end of the line (to see what the generated commands are and fix syntax errors before you pipe them into bash to have them executed).

Unfortunately, the output of ls */ includes empty lines that will mess with your rmdir, but won't stop it from having the required effect.

I find that this approach is quite powerful/flexible and easier than scripting a loop. Use the method that makes sense to you.

Upvotes: 1

Joachim Isaksson
Joachim Isaksson

Reputation: 180887

As far as I understand, this should do what you want.

# Setup test data according to your structure
$ mkdir 00001 00002 00003 
$ touch 00001/photo.jpg 00002/photo.jpg 00003/photo.jpg

# Rename, these are the commands you'll want to run to rename
$ ls ?????/photo.jpg | xargs -I {} sh -c 'mv {} $(echo {} | sed "s,/photo,,")'
$ rmdir  ?????

# Verify that the renames went ok
$ ls
00001.jpg   00002.jpg   00003.jpg

Upvotes: 0

mrz
mrz

Reputation: 1872

cd $toTheRootFolderWhichYouHaveALLtheFolders #00001, 00002
mv 00001/photo.jpg 00001.jpg

Or you can use this bash script in the "photos" directory:

for entry in ./*; 
 do  
    mv "$entry"/photo.jpg "$entry".jpg ;
    rm -rf "$entry";
 done

Upvotes: 2

gniourf_gniourf
gniourf_gniourf

Reputation: 46813

Post edited since I've read in a comment that you have 100000+ such directories.

Do not use any method that involves bash globbing, it would be terribly slow and inefficient. Instead, use this find command, from within the photos directory:

find -regex '\./[0-9]+' -type d -exec mv -n -- {}/photo.jpg {}.jpg \; -empty -delete

I've use the -n option to mv so that we don't overwrite existing files. Use it if your version of mv supports it. You can also use the -v option so that mv is verbose and you see what's happening:

find -regex '\./[0-9]+' -type d -exec mv -nv -- {}/photo.jpg {}.jpg \; -empty -delete

Read the previous command as:

  • -regex '\./[0-9]+': find everything in current directory that has only digits in its name
  • -type d: and it must be a directory
  • -exec mv -n -- {}/photo.jpg {}.jpg \;: move the photo.jpg file in this directory into the parent directory, with name: dirname.jpg
  • -empty: if the directory is now empty...
  • -delete: ...delete it.

After that, you might want to see which directories have not been deleted (because e.g., it contained more files than just the photo.jpg file):

find -regex '\./[0-9]+' -type d

Enjoy!

Upvotes: 5

jaypal singh
jaypal singh

Reputation: 77085

You can do something like:

find . -type f | while read -r file; do mv "$file" "${file%/*}"".jpg" ; done

Once you have all the files renamed and moved up to the parent folder, you can run the following command to delete all empty folders.

find . -type d -empty -exec rm -rf {} +

Please remember that the above solution is only for the structure you have presented. If you have multiple files in any of the sub-folder and you want it to rename it to parent directory name it will get overwritten.

Upvotes: 1

user000001
user000001

Reputation: 33317

Use a for loop, and printf -v to zero pad the counter. Example:

for ((i=1;i<4;i++))
do 
    printf -v num "%05d" "$i"; 
    mv "$num"/photo.jpg "$num".jpg
done

Upvotes: 0

Related Questions