I have the following script, which I normally use when I get a bunch of files that need to be renamed to the directory name which contains them.
The problem now is I need to rename the file to the directory two levels up. How can I get the grandparent directory to make this work?
With the following I get errors like this example:
"mv: cannot move ./48711/zoom/zoom.jpg
to ./48711/zoom/./48711/zoom.jpg
: No such file or directory". This is running on CentOS 5.6.
I want the final file to be named: 48711.jpg
#!/bin/bash
function dirnametofilename() {
for f in $*; do
bn=$(basename "$f")
ext="${bn##*.}"
filepath=$(dirname "$f")
dirname=$(basename "$filepath")
mv "$f" "$filepath/$dirname.$ext"
done
}
export -f dirnametofilename
find . -name "*.jpg" -exec bash -c 'dirnametofilename "{}"' \;
find .
Note:
* This answer solves the OP's specific problem, in whose context "grandparent directory" means: the parent directory of the directory containing a file (it is the grandparent path from the file's perspective).
* By contrast, given the question's generic title, other answers here focus (only) on getting a directory's grandparent directory; the succinct answer to the generic question is: grandParentDir=$(cd ../..; printf %s "$PWD")
to get the full path, and grandParentDirName=$(cd ../..; basename -- "$PWD")
to get the dir. name only.
Try the following:
find . -name '*.jpg' \
-execdir bash -c \
'old="$1"; new="$(cd ..; basename -- "$PWD").${old##*.}"; echo mv "$old" "$new"' - {} \;
Note: echo
was prepended to mv
to be safe - remove it to perform the actual renaming.
-execdir ..\;
executes the specified command in the specific directory that contains a given matching file and expands {}
to the filename of each.
bash -c
is used to execute a small ad-hoc script:
$(cd ..; basename -- "$PWD")
determines the parent directory name of the directory containing the file, which is the grandparent path from the file's perspective.
${old##*.}
is a Bash parameter expansion that returns the input filename's suffix (extension).
Note how {}
- the filename at hand - is passed as the 2nd argument to the command in order to bind to $1
, because bash -c
uses the 1st one to set $0
(which is set to dummy value _
here).
Note that each file is merely renamed, i.e., it stays in its original directory.
Caveat: