6
votes

I have several folders with different images sharing file names, with a folder structure like this:

/parent/folder001/img001.jpg
/parent/folder001/img002.jpg
/parent/folder002/img001.jpg
/parent/folder002/img002.jpg
/parent/folder003/img001.jpg
/parent/folder003/img002.jpg
...

and would like to copy/rename these files into a new folder, like this:

/newfolder/folder001_img001.jpg
/newfolder/folder001_img002.jpg
/newfolder/folder002_img001.jpg
/newfolder/folder002_img002.jpg
/newfolder/folder003_img001.jpg
/newfolder/folder003_img002.jpg
...

(It's probably better if newfolder isn't a subfolder of parent, since that might end up causing really weird recursion.)

None of the folders containing images have any subfolders.

Ideally, I'd like to be able to reuse the script to "update" newfolder, since I might need to add more folders-containing-images later along the line.

How can I accomplish this with a shell script?

3
Well, renaming them all manually isn't really an option, there's hundreds. I'm afraid I'm not terribly adept at the shell myself yet, but looking for solutions only turned up results for different problems/directory structures entirely.Nekkowe
Does it take as input the source folder (in this case "/parent/"), and destination folder (in this case "/newfolder") then grab all the folders within the source folder to merge into the destination folder?Jose Martinez
While renaming the files in the folders within the source folder accordingly, yeah. That would be very helpful! Though I suppose it might be enough if the script works from inside the parent folder and merges the image folders in a folder that's in the same directory as the parent folder is?Nekkowe
I see. So no input into the script. Source and destination dir are the current directory. And you can rerun it to update. Also, do updates cause deletions of files no longer in a sub-directory?Jose Martinez
Aah, no, that's not really necessary. Just it copy-renaming over the files currently present in the image folders would be enough. (Since all it'd take for that, should it ever become necessary, is to delete all files in the destination folder before executing the script and stuff.)Nekkowe

3 Answers

3
votes

I would use something like this:

find -type f -exec sh -c 'f={}; fnew=$(rev <<< "$f" | sed 's~/~_~' | rev); echo "mv $f $fnew"' \;

This looks for files within the current directory structure and perform the following:

  • get the file name
  • replace the last / with _.
  • write echo "cp $old_file $new_file"

Once you have run this and seen it prints the proper command, remove the echo so that it effectively does the mv command.

I know the fnew=$(rev <<< "$f" | sed 's~/~_~' | rev) is a bit ugly trick, but I couldn't find a better way to replace the last / with _. Maybe sed -r 's~/([^/]*)$~_\1~' could also be appropiate, but I always like using rev :)


Since your find does not behave well with the -sh c expression, let's use a while loop for it:

while read -r file
do
    new_file=$(rev <<< "$file" | sed 's~/~_~' | rev)
    echo "mv $file $new_file"; done < <(find . -type f)
done < <(find . -type f)

As a one-liner:

while read -r file; do new_file=$(rev <<< "$file" | sed 's~/~_~' | rev); echo "mv $file $new_file"; done < <(find . -type f)
3
votes

functions to the rescue, updating Jahid's script:

function updateFolder
{
    mkdir "$2"
    for folder in "$1"/*; do
    if [[ -d $folder ]]; then
        foldername="${folder##*/}"
        for file in "$1"/"$foldername"/*; do
            filename="${file##*/}"
            newfilename="$foldername"_"$filename"
            cp "$file" "$2"/"$newfilename"
        done
    fi
    done
}

used:

$ updateFolder /parent /newfolder
3
votes

This is a bit tedious but will do:

#!/bin/bash
parent=/parent
newfolder=/newfolder
mkdir "$newfolder"
for folder in "$parent"/*; do
  if [[ -d "$folder" ]]; then
    foldername="${folder##*/}"
    for file in "$parent"/"$foldername"/*; do
      filename="${file##*/}"
      newfilename="$foldername"_"$filename"
      cp "$file" "$newfolder"/"$newfilename"
    done
  fi
done

Put the parent path to parent variable and newfolder path to newfolder variable.