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?
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.
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
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)