bash scripting: how to find the absolute path of "symlink/.."?
Asked Answered
R

6

8

Given two files:

generic/scripts/hello.sh
parent/scripts -> generic/scripts

Upon calling parent/scripts/hello.sh from any location, I would like (in the script) to find the full path of the parent directory. In this case parent.

The main issue is that parent/scripts/.. refers to generic in unix. On the other hand, everything involving regexes is not generic and may be error prone.

Solutions that don't work:

`dirname $0`/..
realpath  `dirname $0`/..
readlink -f `dirname $0`/..
`cd *something*/..; pwd`
`perl ... abs_path(...)`

All these will point to generic and not parent because of the symbolic link.

Everything involving regular expressions are not adaptable/generic, may fail for more complexes paths. There might be other .. and symlinks in the path, you want the grand-parent, it's a directory name involving .., you call it via $PATH...

Moreover, I would like it to work in any case, even when it is called via $PATH.

Any simple safe solution for this simple problem? I mean it's just getting the parent directory after all!

What I used:

dir=$( dirname $( cd `dirname $0` >/dev/null; pwd ) )

Dunno if it is perfect but it seems to behave as expected.

Roomette answered 7/6, 2011 at 15:35 Comment(5)
how are you calling these scripts?Ontologism
ideally, no restrictions should be put on how they can be called.Roomette
Your first solution works as long as you are actually using the parent/scripts/hello.sh to call the script.Ias
"...it's just getting the parent directory after all" generic is hello's parent directory, that's why all the tools you use give you that. If parent/scripts is not visible in $0, you'll not get it. On linux, cd to parent/scripts and do ls -l /proc/$$ to see what the OS knows about where you are.Ontologism
...well ...somehow you have the information. It's either in $0 (when calling it from "outside" or $PATH), or to be combined with pwd if you are calling it within one of the subdirectories using a relative path. I just have the feeling that you have to manually handle several different cases and that you have to resolve the path using regular expressions ...which I personally think is fairly ugly ...just to get the parent.Roomette
B
5

Try this:

basename $(dirname $(dirname $0))

or perhaps just

$(dirname $(dirname $0))

It is unclear if you want parent alone or its full path.

Bravura answered 7/6, 2011 at 16:24 Comment(3)
double dirname does the trick ...the only to add is concatenating it with pwd when $0 is a relative path to also take into account the case when we are in one of the sub directories.Roomette
double dirname does not do the trick: dirname $(dirname ../../../) results in '..'.Shrug
@Shrug $0 is quite unlikely to be equal to ../../../Bravura
L
1

I would recommend 1) use pwd -P which will always give you the physical path, and then navigate with relative path to the other palce This is most safe.

2) use pwd -L

Logbook answered 7/6, 2011 at 16:22 Comment(0)
G
1
pushd $(dirname $0)
FOO=$(pwd)
popd

That gives you the absolute path of the directory that the script is running in.

Glynisglynn answered 6/3, 2013 at 5:28 Comment(0)
F
0

I call my scipt with this: ../script1 and it has a relative call to ../relative/script2

`(cd $0/.. && pwd)`/relative/script2

is in script1

Feel answered 6/1, 2014 at 19:52 Comment(0)
M
0

in bash you could do some string manipulation on $PWD if that variable is available.

For pathname of parent directory, use:

${PWD%/*}

Other examples :

me@host:/tmp/bash_string/ma ni-pu_la/tion$ echo -e \
"\$PWD or \${PWD} : " $PWD \
"\n\${PWD##/*}     : " ${PWD##/*} \
"\n\${PWD##*/}     : " ${PWD##*/} \
"\n\${PWD#/*}      : " ${PWD#/*} \
"\n\${PWD#*/}      : " ${PWD#*/} \
"\n\${PWD%%/*}     : " ${PWD%%/*} \
"\n\${PWD%%*/}     : " ${PWD%%*/} \
"\n\${PWD%/*}      : " ${PWD%/*} \
"\n\${PWD%*/}      : " ${PWD%*/} \
"\n" # Gives :
$PWD or ${PWD} :  /tmp/bash_string/ma ni-pu_la/tion 
${PWD##/*}     :  
${PWD##*/}     :  tion 
${PWD#/*}      :  tmp/bash_string/ma ni-pu_la/tion 
${PWD#*/}      :  tmp/bash_string/ma ni-pu_la/tion 
${PWD%%/*}     :  
${PWD%%*/}     :  /tmp/bash_string/ma ni-pu_la/tion 
${PWD%/*}      :  /tmp/bash_string/ma ni-pu_la 
${PWD%*/}      :  /tmp/bash_string/ma ni-pu_la/tion
Maleficence answered 16/7, 2015 at 15:10 Comment(0)
S
-3

What about this:

echo `cd .. && pwd`
Sunstroke answered 7/6, 2011 at 16:7 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.