fpsvogel
fpsvogel

Reputation: 264

bash: rename files in indeterminate sub-subfolders based on grandparent directory name

Bash newbie here trying to insert the name of a folder into certain files inside that folder.

The problem is that these files are in subfolders of subfolders of the main directory, and the names of each level are different in each case.

For example, the main folder interviews may contain John Doe and under John Doe is a directory Images with a file Screenshot.jpg. But there might also be John Smith with a folder Etc in which is 12_Screenshot 2.jpg.

I want to rename all these files containing Screenshot inserting John Doe or John Smith before the filename.

I tried adapting a couple of scripts I found and ran them from the interviews directory:

for i in `ls -l | egrep '^d'| awk '{print $10}'`; do  find . -type f -name "*Screenshot*" -exec sh -c 'mv "$0" "${i}${0}"' '{}' \; done

after which the terminal gives the caret prompt, as if I'm missing something. I also tried

find -regex '\./*' -type d -exec mv -- {}/*/*Screenshot* {}/{}.jpg \; -empty -delete

which returns find: illegal option -- r

The fact that the second one theoretically moves the file up to the parent folder is not a problem since I'll have to do this eventually anyways.

Upvotes: 1

Views: 439

Answers (2)

buydadip
buydadip

Reputation: 9407

The following script will work as desired :

dir=$1
find $dir -name "*Screenshot*" -type f | while read file
do
    base=$(basename $file)
    dirpath=$(dirname $file)
    extr=$(echo $file | awk -F/ '{print $(NF-2)}') #extracts the grandparent directory
    mv $file $dirpath/$extr-$base
done

As @loneswap mentioned, this must be invoked as a script. So if your main directory is mainDir, then you would invoke it as so...

./script mainDir

Upvotes: 1

lonewasp
lonewasp

Reputation: 106

For each directory in current working directory, recursively find files containing string "screenshot" (case insensitive due to OSX). Split the found path into parent part (always present at least in form './') and file name, produce two lines one original file path, second one original folder + modified target file name. Execute mv command via xargs using two arguments (separate by newline to allow whitespaces in paths):

for i in `ls -l | sed -n '/^d\([^[:space:]]\+[[:space:]]\+\)\+\([^[:space:]]\+\)$/s//\2/p'`; do
    find "$i" -type f -iname "*Screenshot*" \
        | sed -n '\!^\(\([^/]\+/\)\+\)\([^/]\+\)$!s!!\1\3\n\1'$i'\3!p' \
        | xargs -d '\n' -n 2 mv;
done

Drawback: xargs on OSX does not know --no-run-if-empty, so for directories that do not contain files with "screenshot" string empty mv is invoked. Proper option needs to be added (don't have access to OSX man pages) or xargs ... 2>&/dev/null to ignore all errors...

Upvotes: 0

Related Questions