Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Get grandparent directory in bash script - rename files for a directory in their paths

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 .
like image 628
user1201155 Avatar asked Jan 21 '14 22:01

user1201155


3 Answers

Another method could be to use

(cd ../../; pwd)

If this were executed in any top-level paths such as /, /usr/, or /usr/share/, you would get a valid directory of /, but when you get one level deeper, you would start seeing results: /usr/share/man/ would return /usr, /my/super/deep/path/is/awesome/ would return /my/super/deep/path, and so on.

You could store this in a variable as well:

GRANDDADDY="$(cd ../../; pwd)"

and then use it for the rest of your script.

like image 183
OnlineCop Avatar answered Nov 19 '22 12:11

OnlineCop


Assuming filepath doesn't end in /, which it shouldn't if you use dirname, you can do

Parent = "${filepath%/*}"
Grandparent = "${filepath%/*/*}"

So do something like this

[[ "${filepath%/*/*}" == "" ]] && echo "Path isn't long enough" || echo "${filepath%/*/*}"

Also this likely won't work if you're using relative paths (like find .). In which case you will want to use

filepath=$(dirname "$f")
filepath=$(readlink -f "$filepath")

instead of

filepath=$(dirname "$f")

Also you're never stripping the extension, so there is no reason to get it from the file and then append it again.

like image 28
Reinstate Monica Please Avatar answered Nov 19 '22 12:11

Reinstate Monica Please


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:

  • Each directory with a matching file should only contain 1 matching file, otherwise multiple files will be renamed to the same target name in sequence - effectively, only the last file renamed will survive.
like image 3
mklement0 Avatar answered Nov 19 '22 13:11

mklement0