Unix shell script find out which directory the script file resides?
Basically I need to run the script with paths related to the shell script file location, how can I change the current directory to the same directory as where the script file resides?
shell unix
|
show 2 more comments
Basically I need to run the script with paths related to the shell script file location, how can I change the current directory to the same directory as where the script file resides?
shell unix
9
Is that really a duplicate? This question is about a "unix shell script", the other specifically about Bash.
– michaeljt
Jun 23 '15 at 9:45
2
@BoltClock: This question was improperly closed. The linked question is about Bash. This question is about Unix shell programming. Notice that the accepted answers are quite different!
– Dietrich Epp
Jun 16 '16 at 7:56
@Dietrich Epp: You're right. It seems the asker's choice of accepted answer and the addition of the [bash] tag (probably in response to that) led me to marking the question as a duplicate in response to a flag.
– BoltClock♦
Jun 16 '16 at 8:03
2
I think this answer is better: Getting the source directory of a Bash script from within
– Alan Zhiliang Feng
Jun 2 '17 at 7:50
1
Possible duplicate of Getting the source directory of a Bash script from within
– dulgan
Jul 3 '17 at 13:53
|
show 2 more comments
Basically I need to run the script with paths related to the shell script file location, how can I change the current directory to the same directory as where the script file resides?
shell unix
Basically I need to run the script with paths related to the shell script file location, how can I change the current directory to the same directory as where the script file resides?
shell unix
shell unix
edited Jun 16 '16 at 8:31
user3378165
2,34682657
2,34682657
asked Oct 28 '08 at 8:19
William YeungWilliam Yeung
3,90673141
3,90673141
9
Is that really a duplicate? This question is about a "unix shell script", the other specifically about Bash.
– michaeljt
Jun 23 '15 at 9:45
2
@BoltClock: This question was improperly closed. The linked question is about Bash. This question is about Unix shell programming. Notice that the accepted answers are quite different!
– Dietrich Epp
Jun 16 '16 at 7:56
@Dietrich Epp: You're right. It seems the asker's choice of accepted answer and the addition of the [bash] tag (probably in response to that) led me to marking the question as a duplicate in response to a flag.
– BoltClock♦
Jun 16 '16 at 8:03
2
I think this answer is better: Getting the source directory of a Bash script from within
– Alan Zhiliang Feng
Jun 2 '17 at 7:50
1
Possible duplicate of Getting the source directory of a Bash script from within
– dulgan
Jul 3 '17 at 13:53
|
show 2 more comments
9
Is that really a duplicate? This question is about a "unix shell script", the other specifically about Bash.
– michaeljt
Jun 23 '15 at 9:45
2
@BoltClock: This question was improperly closed. The linked question is about Bash. This question is about Unix shell programming. Notice that the accepted answers are quite different!
– Dietrich Epp
Jun 16 '16 at 7:56
@Dietrich Epp: You're right. It seems the asker's choice of accepted answer and the addition of the [bash] tag (probably in response to that) led me to marking the question as a duplicate in response to a flag.
– BoltClock♦
Jun 16 '16 at 8:03
2
I think this answer is better: Getting the source directory of a Bash script from within
– Alan Zhiliang Feng
Jun 2 '17 at 7:50
1
Possible duplicate of Getting the source directory of a Bash script from within
– dulgan
Jul 3 '17 at 13:53
9
9
Is that really a duplicate? This question is about a "unix shell script", the other specifically about Bash.
– michaeljt
Jun 23 '15 at 9:45
Is that really a duplicate? This question is about a "unix shell script", the other specifically about Bash.
– michaeljt
Jun 23 '15 at 9:45
2
2
@BoltClock: This question was improperly closed. The linked question is about Bash. This question is about Unix shell programming. Notice that the accepted answers are quite different!
– Dietrich Epp
Jun 16 '16 at 7:56
@BoltClock: This question was improperly closed. The linked question is about Bash. This question is about Unix shell programming. Notice that the accepted answers are quite different!
– Dietrich Epp
Jun 16 '16 at 7:56
@Dietrich Epp: You're right. It seems the asker's choice of accepted answer and the addition of the [bash] tag (probably in response to that) led me to marking the question as a duplicate in response to a flag.
– BoltClock♦
Jun 16 '16 at 8:03
@Dietrich Epp: You're right. It seems the asker's choice of accepted answer and the addition of the [bash] tag (probably in response to that) led me to marking the question as a duplicate in response to a flag.
– BoltClock♦
Jun 16 '16 at 8:03
2
2
I think this answer is better: Getting the source directory of a Bash script from within
– Alan Zhiliang Feng
Jun 2 '17 at 7:50
I think this answer is better: Getting the source directory of a Bash script from within
– Alan Zhiliang Feng
Jun 2 '17 at 7:50
1
1
Possible duplicate of Getting the source directory of a Bash script from within
– dulgan
Jul 3 '17 at 13:53
Possible duplicate of Getting the source directory of a Bash script from within
– dulgan
Jul 3 '17 at 13:53
|
show 2 more comments
15 Answers
15
active
oldest
votes
In Bash, you should get what you need like this:
#!/usr/bin/env bash
BASEDIR=$(dirname "$0")
echo "$BASEDIR"
52
This will not work if the script is in your path.
– Bill Lynch
Aug 20 '09 at 19:14
12
This doesn't work if you've called the script via a symbolic link in a different directory. To make that work you need to usereadlink
as well (see al's answer below)
– AndrewR
Mar 17 '10 at 23:26
32
In bash it is safer to use$BASH_SOURCE
in lieu of$0
, because$0
doesn't always contain the path of the script being invoked, such as when 'sourcing' a script.
– mklement0
Jul 19 '12 at 19:32
5
@auraham:CUR_PATH=$(pwd)
orpwd
do return the current directory (which does not have to be the scripts parent dir)!
– Andreas Dietrich
Jul 24 '14 at 7:58
3
I tried the method @mklement0 recommended, using$BASH_SOURCE
, and it returns what I needed. My script is being called from another script, and$0
returns.
while$BASH_SOURCE
returns the right subdirectory (in my casescripts
).
– David Rissato Cruz
Dec 3 '15 at 16:28
|
show 12 more comments
The original post contains the solution (ignore the responses, they don't add anything useful). The interesting work is done by the mentioned unix command readlink
with option -f
. Works when the script is called by an absolute as well as by a relative path.
For bash, sh, ksh:
#!/bin/bash
# Absolute path to this script, e.g. /home/user/bin/foo.sh
SCRIPT=$(readlink -f "$0")
# Absolute path this script is in, thus /home/user/bin
SCRIPTPATH=$(dirname "$SCRIPT")
echo $SCRIPTPATH
For tcsh, csh:
#!/bin/tcsh
# Absolute path to this script, e.g. /home/user/bin/foo.csh
set SCRIPT=`readlink -f "$0"`
# Absolute path this script is in, thus /home/user/bin
set SCRIPTPATH=`dirname "$SCRIPT"`
echo $SCRIPTPATH
See also: https://stackoverflow.com/a/246128/59087
11
Note: Not all systems havereadlink
. That's why I recommended using pushd/popd (built-ins for bash).
– docwhat
May 20 '11 at 14:29
18
The-f
option toreadlink
does something different on OS X (Lion) and possibly BSD. stackoverflow.com/questions/1055671/…
– Ergwun
Jun 29 '12 at 1:33
7
To clarify @Ergwun's comment:-f
is not supported on OS X at all (as of Lion); there you can either drop the-f
to make do with resolving at most one level of indirection, e.g.pushd "$(dirname "$(readlink "$BASH_SOURCE" || echo "$BASH_SOURCE")")"
, or you can roll your own recursive symlink-following script as demonstrated in the linked post.
– mklement0
Jul 19 '12 at 19:37
2
I still don't understand, why the OP would need the absolute path. Reporting "." should work alright if you want to access files relative to the scripts path and you called the script like ./myscript.sh
– Stefan Haberl
Mar 12 '14 at 8:25
9
@StefanHaberl I think it would be an issue if you ran the script while your present working directory was different from the script's location (e.g.sh /some/other/directory/script.sh)
, in this case.
would be your pwd, not/some/other/directory
– Jon z
Oct 9 '14 at 11:18
|
show 8 more comments
An earlier comment on an answer said it, but it is easy to miss among all the other answers.
When using bash:
echo this file: "$BASH_SOURCE"
echo this dir: "$(dirname "$BASH_SOURCE")"
Bash Reference Manual, 5.2 Bash Variables
4
This is what I was looking for. I needed to get the absolute path of the currently executing script.
– Aaron Blenkush
Nov 15 '13 at 17:09
2
Only this one works with script in environment path, the most voted ones do not work. thank you!
– July
Sep 22 '16 at 5:20
1
Best solution of all
– Alexandro de Oliveira
Jun 20 '17 at 5:23
You should usedirname "$BASH_SOURCE"
instead to handle spaces in $BASH_SOURCE.
– Mygod
Jan 8 '18 at 12:16
A more explicit way to print the directory would, according to tool ShellCheck, be: "$(dirname "${BASH_SOURCE{0}}")" because BASH_SOURCE is an array, and without the subscript, the first element is taken by default.
– Adrian M.
Dec 2 '18 at 3:55
add a comment |
Assuming you're using bash
#!/bin/bash
current_dir=$(pwd)
script_dir=$(dirname $0)
echo $current_dir
echo $script_dir
This script should print the directory that you're in, and then the directory the script is in. For example, when calling it from /
with the script in /home/mez/
, it outputs
/
/home/mez
Remember, when assigning variables from the output of a command, wrap the command in $(
and )
- or you won't get the desired output.
2
This won't work when I invoke the script from current dir.
– Eric Wang
Mar 13 '17 at 7:17
Does not work when there run from symlink.
– ctrl-alt-delor
Sep 22 '17 at 12:18
1
@EricWang you are always in current directory.
– ctrl-alt-delor
Sep 22 '17 at 12:19
add a comment |
If you're using bash....
#!/bin/bash
pushd $(dirname "${0}") > /dev/null
basedir=$(pwd -L)
# Use "pwd -P" for the path without links. man bash for more info.
popd > /dev/null
echo "${basedir}"
3
You can replace thepushd
/popd
withcd $(dirname "${0}")
andcd -
to make it work on other shells, if they have apwd -L
.
– docwhat
May 20 '11 at 14:30
why would you use pushd and popd here?
– qodeninja
Mar 25 '14 at 23:17
1
So I don't have to store the original directory in a variable. It's a pattern I use a lot in functions and such. It nests really well, which is good.
– docwhat
Mar 27 '14 at 3:06
It is still being stored in memory -- in a variable -- whether a variable is referenced in your script or not. Also, I believe the cost of executing pushd and popd far outweighs the savings of not creating a local Bash variable in your script, both in CPU cycles and readability.
– ingyhere
Jan 6 '16 at 21:07
this is the first answer which actually works
– Blauhirn
Dec 5 '16 at 14:45
add a comment |
As theMarko suggests:
BASEDIR=$(dirname $0)
echo $BASEDIR
This works unless you execute the script from the same directory where the script resides, in which case you get a value of '.'
To get around that issue use:
current_dir=$(pwd)
script_dir=$(dirname $0)
if [ $script_dir = '.' ]
then
script_dir="$current_dir"
fi
You can now use the variable current_dir throughout your script to refer to the script directory. However this may still have the symlink issue.
script_dir=$(dirname $0) could also return ..
– Rooster242
Jul 1 '18 at 1:46
add a comment |
The best answer for this question was answered here:
Getting the source directory of a Bash script from within
And is:
DIR="$( cd "$( dirname "${BASH_SOURCE[0]}" )" && pwd )"
One-liner which will give you the full directory name of the script no matter where it is being called from.
To understand how it works you can execute the following script:
#!/bin/bash
SOURCE="${BASH_SOURCE[0]}"
while [ -h "$SOURCE" ]; do # resolve $SOURCE until the file is no longer a symlink
TARGET="$(readlink "$SOURCE")"
if [[ $TARGET == /* ]]; then
echo "SOURCE '$SOURCE' is an absolute symlink to '$TARGET'"
SOURCE="$TARGET"
else
DIR="$( dirname "$SOURCE" )"
echo "SOURCE '$SOURCE' is a relative symlink to '$TARGET' (relative to '$DIR')"
SOURCE="$DIR/$TARGET" # if $SOURCE was a relative symlink, we need to resolve it relative to the path where the symlink file was located
fi
done
echo "SOURCE is '$SOURCE'"
RDIR="$( dirname "$SOURCE" )"
DIR="$( cd -P "$( dirname "$SOURCE" )" && pwd )"
if [ "$DIR" != "$RDIR" ]; then
echo "DIR '$RDIR' resolves to '$DIR'"
fi
echo "DIR is '$DIR'"
add a comment |
cd $(dirname $(readlink -f $0))
add a comment |
Let's make it a POSIX oneliner:
a="/$0"; a=${a%/*}; a=${a#/}; a=${a:-.}; BASEDIR=$(cd "$a"; pwd)
Tested on many Bourne-compatible shells including the BSD ones.
As far as I know I am the author and I put it into public domain. For more info see:
https://www.jasan.tk/posts/2017-05-11-posix_shell_dirname_replacement/
1
as written,cd: too many arguments
if spaces in the path, and returns$PWD
. (an obvious fix, but just shows how many edge cases there actually are)
– michael
Jul 29 '17 at 19:02
1
Would upvote. Except for the comment from @michael that it fails with spaces in path... Is there a fix for that?
– spechter
Feb 20 '18 at 4:13
@spechter see: stackoverflow.com/a/45392962/127971
– michael
Feb 21 '18 at 19:00
1
@spechter yes, there's a fix for that. See updated jasan.tk/posix/2017/05/11/posix_shell_dirname_replacement
– Ján Sáreník
Apr 4 '18 at 17:16
1
ln -s /home/der/1/test /home/der/2/test && /home/der/2/test => /home/der/2 (should show path to the original script instead)
– Der_Meister
Oct 23 '18 at 7:41
|
show 4 more comments
BASE_DIR="$(cd "$(dirname "$0")"; pwd)";
echo "BASE_DIR => $BASE_DIR"
1
most reliable non-bash-specific way I know.
– eddygeek
Oct 2 '18 at 9:35
add a comment |
Inspired by blueyed’s answer
read < <(readlink -f $0 | xargs dirname)
cd $REPLY
add a comment |
So many answers, all plausible, each with pro's and con's & slightly differeing objectives (which should probably be stated for each). Here's another solution that meets a primary objective of both being clear and working across all systems, on all bash (no assumptions about bash versions, or readlink
or pwd
options), and reasonably does what you'd expect to happen (eg, resolving symlinks is an interesting problem, but isn't usually what you actually want), handle edge cases like spaces in paths, etc., ignores any errors and uses a sane default if there are any issues.
Each component is stored in a separate variable that you can use individually:
# script path, filename, directory
PROG_PATH=${BASH_SOURCE[0]} # this script's name
PROG_NAME=${PROG_PATH##*/} # basename of script (strip path)
PROG_DIR="$(cd "$(dirname "${PROG_PATH:-$PWD}")" 2>/dev/null 1>&2 && pwd)"
add a comment |
INTRODUCTION
This answer corrects the very broken but shockingly top voted answer of this thread (written by TheMarko):
#!/usr/bin/env bash
BASEDIR=$(dirname "$0")
echo "$BASEDIR"
WHY DOES USING dirname "$0" ON IT'S OWN NOT WORK?
dirname $0 will only work if user launches script in a very specific way. I was able to find several situations where this answer fails and crashes the script.
First of all, let's understand how this answer works. He's getting the script directory by doing
dirname "$0"
$0 represents the first part of the command calling the script (it's basically the inputted command without the arguments:
/some/path/./script argument1 argument2
$0="/some/path/./script"
dirname basically finds the last / in a string and truncates it there. So if you do:
dirname /usr/bin/sha256sum
you'll get: /usr/bin
This example works well because /usr/bin/sha256sum is a properly formatted path but
dirname "/some/path/./script"
wouldn't work well and would give you:
BASENAME="/some/path/." #which would crash your script if you try to use it as a path
Say you're in the same dir as your script and you launch it with this command
./script
$0 in this situation will be ./script and dirname $0 will give:
. #or BASEDIR=".", again this will crash your script
Using:
sh script
Without inputting the full path will also give a BASEDIR="."
Using relative directories:
../some/path/./script
Gives a dirname $0 of:
../some/path/.
If you're in the /some directory and you call the script in this manner (note the absence of / in the beginning, again a relative path):
path/./script.sh
You'll get this value for dirname $0:
path/.
and ./path/./script (another form of the relative path) gives:
./path/.
The only two situations where basedir $0 will work is if the user use sh or touch to launch a script because both will result in $0:
$0=/some/path/script
which will give you a path you can use with dirname.
THE SOLUTION
You'd have account for and detect every one of the above mentioned situations and apply a fix for it if it arises:
#!/bin/bash
#this script will only work in bash, make sure it's installed on your system.
#set to false to not see all the echos
debug=true
if [ "$debug" = true ]; then echo "$0=$0";fi
#The line below detect script's parent directory. $0 is the part of the launch command that doesn't contain the arguments
BASEDIR=$(dirname "$0") #3 situations will cause dirname $0 to fail: #situation1: user launches script while in script dir ( $0=./script)
#situation2: different dir but ./ is used to launch script (ex. $0=/path_to/./script)
#situation3: different dir but relative path used to launch script
if [ "$debug" = true ]; then echo 'BASEDIR=$(dirname "$0") gives: '"$BASEDIR";fi
if [ "$BASEDIR" = "." ]; then BASEDIR="$(pwd)";fi # fix for situation1
_B2=${BASEDIR:$((${#BASEDIR}-2))}; B_=${BASEDIR::1}; B_2=${BASEDIR::2}; B_3=${BASEDIR::3} # <- bash only
if [ "$_B2" = "/." ]; then BASEDIR=${BASEDIR::$((${#BASEDIR}-1))};fi #fix for situation2 # <- bash only
if [ "$B_" != "/" ]; then #fix for situation3 #<- bash only
if [ "$B_2" = "./" ]; then
#covers ./relative_path/(./)script
if [ "$(pwd)" != "/" ]; then BASEDIR="$(pwd)/${BASEDIR:2}"; else BASEDIR="/${BASEDIR:2}";fi
else
#covers relative_path/(./)script and ../relative_path/(./)script, using ../relative_path fails if current path is a symbolic link
if [ "$(pwd)" != "/" ]; then BASEDIR="$(pwd)/$BASEDIR"; else BASEDIR="/$BASEDIR";fi
fi
fi
if [ "$debug" = true ]; then echo "fixed BASEDIR=$BASEDIR";fi
add a comment |
This one-liner tells where the shell script is, does not matter if you ran it or if you sourced it. Also, it resolves any symbolic links involved, if that is the case:
dir=$(dirname $(test -L "$BASH_SOURCE" && readlink -f "$BASH_SOURCE" || echo "$BASH_SOURCE"))
By the way, I suppose you are using /bin/bash.
add a comment |
That should do the trick:
echo `pwd`/`dirname $0`
It might look ugly depending on how it was invoked and the cwd but should get you where you need to go (or you can tweak the string if you care how it looks).
1
stackoverflow escape problem here: it surely should look like this:`pwd`/`dirname $0`
but may still fail on symlinks
– Andreas Dietrich
Jul 24 '14 at 8:12
add a comment |
protected by Community♦ Jul 26 '11 at 11:14
Thank you for your interest in this question.
Because it has attracted low-quality or spam answers that had to be removed, posting an answer now requires 10 reputation on this site (the association bonus does not count).
Would you like to answer one of these unanswered questions instead?
15 Answers
15
active
oldest
votes
15 Answers
15
active
oldest
votes
active
oldest
votes
active
oldest
votes
In Bash, you should get what you need like this:
#!/usr/bin/env bash
BASEDIR=$(dirname "$0")
echo "$BASEDIR"
52
This will not work if the script is in your path.
– Bill Lynch
Aug 20 '09 at 19:14
12
This doesn't work if you've called the script via a symbolic link in a different directory. To make that work you need to usereadlink
as well (see al's answer below)
– AndrewR
Mar 17 '10 at 23:26
32
In bash it is safer to use$BASH_SOURCE
in lieu of$0
, because$0
doesn't always contain the path of the script being invoked, such as when 'sourcing' a script.
– mklement0
Jul 19 '12 at 19:32
5
@auraham:CUR_PATH=$(pwd)
orpwd
do return the current directory (which does not have to be the scripts parent dir)!
– Andreas Dietrich
Jul 24 '14 at 7:58
3
I tried the method @mklement0 recommended, using$BASH_SOURCE
, and it returns what I needed. My script is being called from another script, and$0
returns.
while$BASH_SOURCE
returns the right subdirectory (in my casescripts
).
– David Rissato Cruz
Dec 3 '15 at 16:28
|
show 12 more comments
In Bash, you should get what you need like this:
#!/usr/bin/env bash
BASEDIR=$(dirname "$0")
echo "$BASEDIR"
52
This will not work if the script is in your path.
– Bill Lynch
Aug 20 '09 at 19:14
12
This doesn't work if you've called the script via a symbolic link in a different directory. To make that work you need to usereadlink
as well (see al's answer below)
– AndrewR
Mar 17 '10 at 23:26
32
In bash it is safer to use$BASH_SOURCE
in lieu of$0
, because$0
doesn't always contain the path of the script being invoked, such as when 'sourcing' a script.
– mklement0
Jul 19 '12 at 19:32
5
@auraham:CUR_PATH=$(pwd)
orpwd
do return the current directory (which does not have to be the scripts parent dir)!
– Andreas Dietrich
Jul 24 '14 at 7:58
3
I tried the method @mklement0 recommended, using$BASH_SOURCE
, and it returns what I needed. My script is being called from another script, and$0
returns.
while$BASH_SOURCE
returns the right subdirectory (in my casescripts
).
– David Rissato Cruz
Dec 3 '15 at 16:28
|
show 12 more comments
In Bash, you should get what you need like this:
#!/usr/bin/env bash
BASEDIR=$(dirname "$0")
echo "$BASEDIR"
In Bash, you should get what you need like this:
#!/usr/bin/env bash
BASEDIR=$(dirname "$0")
echo "$BASEDIR"
edited Feb 28 '16 at 3:37
James Ko
11.9k1154119
11.9k1154119
answered Oct 28 '08 at 8:26
TheMarkoTheMarko
5,4281136
5,4281136
52
This will not work if the script is in your path.
– Bill Lynch
Aug 20 '09 at 19:14
12
This doesn't work if you've called the script via a symbolic link in a different directory. To make that work you need to usereadlink
as well (see al's answer below)
– AndrewR
Mar 17 '10 at 23:26
32
In bash it is safer to use$BASH_SOURCE
in lieu of$0
, because$0
doesn't always contain the path of the script being invoked, such as when 'sourcing' a script.
– mklement0
Jul 19 '12 at 19:32
5
@auraham:CUR_PATH=$(pwd)
orpwd
do return the current directory (which does not have to be the scripts parent dir)!
– Andreas Dietrich
Jul 24 '14 at 7:58
3
I tried the method @mklement0 recommended, using$BASH_SOURCE
, and it returns what I needed. My script is being called from another script, and$0
returns.
while$BASH_SOURCE
returns the right subdirectory (in my casescripts
).
– David Rissato Cruz
Dec 3 '15 at 16:28
|
show 12 more comments
52
This will not work if the script is in your path.
– Bill Lynch
Aug 20 '09 at 19:14
12
This doesn't work if you've called the script via a symbolic link in a different directory. To make that work you need to usereadlink
as well (see al's answer below)
– AndrewR
Mar 17 '10 at 23:26
32
In bash it is safer to use$BASH_SOURCE
in lieu of$0
, because$0
doesn't always contain the path of the script being invoked, such as when 'sourcing' a script.
– mklement0
Jul 19 '12 at 19:32
5
@auraham:CUR_PATH=$(pwd)
orpwd
do return the current directory (which does not have to be the scripts parent dir)!
– Andreas Dietrich
Jul 24 '14 at 7:58
3
I tried the method @mklement0 recommended, using$BASH_SOURCE
, and it returns what I needed. My script is being called from another script, and$0
returns.
while$BASH_SOURCE
returns the right subdirectory (in my casescripts
).
– David Rissato Cruz
Dec 3 '15 at 16:28
52
52
This will not work if the script is in your path.
– Bill Lynch
Aug 20 '09 at 19:14
This will not work if the script is in your path.
– Bill Lynch
Aug 20 '09 at 19:14
12
12
This doesn't work if you've called the script via a symbolic link in a different directory. To make that work you need to use
readlink
as well (see al's answer below)– AndrewR
Mar 17 '10 at 23:26
This doesn't work if you've called the script via a symbolic link in a different directory. To make that work you need to use
readlink
as well (see al's answer below)– AndrewR
Mar 17 '10 at 23:26
32
32
In bash it is safer to use
$BASH_SOURCE
in lieu of $0
, because $0
doesn't always contain the path of the script being invoked, such as when 'sourcing' a script.– mklement0
Jul 19 '12 at 19:32
In bash it is safer to use
$BASH_SOURCE
in lieu of $0
, because $0
doesn't always contain the path of the script being invoked, such as when 'sourcing' a script.– mklement0
Jul 19 '12 at 19:32
5
5
@auraham:
CUR_PATH=$(pwd)
or pwd
do return the current directory (which does not have to be the scripts parent dir)!– Andreas Dietrich
Jul 24 '14 at 7:58
@auraham:
CUR_PATH=$(pwd)
or pwd
do return the current directory (which does not have to be the scripts parent dir)!– Andreas Dietrich
Jul 24 '14 at 7:58
3
3
I tried the method @mklement0 recommended, using
$BASH_SOURCE
, and it returns what I needed. My script is being called from another script, and $0
returns .
while $BASH_SOURCE
returns the right subdirectory (in my case scripts
).– David Rissato Cruz
Dec 3 '15 at 16:28
I tried the method @mklement0 recommended, using
$BASH_SOURCE
, and it returns what I needed. My script is being called from another script, and $0
returns .
while $BASH_SOURCE
returns the right subdirectory (in my case scripts
).– David Rissato Cruz
Dec 3 '15 at 16:28
|
show 12 more comments
The original post contains the solution (ignore the responses, they don't add anything useful). The interesting work is done by the mentioned unix command readlink
with option -f
. Works when the script is called by an absolute as well as by a relative path.
For bash, sh, ksh:
#!/bin/bash
# Absolute path to this script, e.g. /home/user/bin/foo.sh
SCRIPT=$(readlink -f "$0")
# Absolute path this script is in, thus /home/user/bin
SCRIPTPATH=$(dirname "$SCRIPT")
echo $SCRIPTPATH
For tcsh, csh:
#!/bin/tcsh
# Absolute path to this script, e.g. /home/user/bin/foo.csh
set SCRIPT=`readlink -f "$0"`
# Absolute path this script is in, thus /home/user/bin
set SCRIPTPATH=`dirname "$SCRIPT"`
echo $SCRIPTPATH
See also: https://stackoverflow.com/a/246128/59087
11
Note: Not all systems havereadlink
. That's why I recommended using pushd/popd (built-ins for bash).
– docwhat
May 20 '11 at 14:29
18
The-f
option toreadlink
does something different on OS X (Lion) and possibly BSD. stackoverflow.com/questions/1055671/…
– Ergwun
Jun 29 '12 at 1:33
7
To clarify @Ergwun's comment:-f
is not supported on OS X at all (as of Lion); there you can either drop the-f
to make do with resolving at most one level of indirection, e.g.pushd "$(dirname "$(readlink "$BASH_SOURCE" || echo "$BASH_SOURCE")")"
, or you can roll your own recursive symlink-following script as demonstrated in the linked post.
– mklement0
Jul 19 '12 at 19:37
2
I still don't understand, why the OP would need the absolute path. Reporting "." should work alright if you want to access files relative to the scripts path and you called the script like ./myscript.sh
– Stefan Haberl
Mar 12 '14 at 8:25
9
@StefanHaberl I think it would be an issue if you ran the script while your present working directory was different from the script's location (e.g.sh /some/other/directory/script.sh)
, in this case.
would be your pwd, not/some/other/directory
– Jon z
Oct 9 '14 at 11:18
|
show 8 more comments
The original post contains the solution (ignore the responses, they don't add anything useful). The interesting work is done by the mentioned unix command readlink
with option -f
. Works when the script is called by an absolute as well as by a relative path.
For bash, sh, ksh:
#!/bin/bash
# Absolute path to this script, e.g. /home/user/bin/foo.sh
SCRIPT=$(readlink -f "$0")
# Absolute path this script is in, thus /home/user/bin
SCRIPTPATH=$(dirname "$SCRIPT")
echo $SCRIPTPATH
For tcsh, csh:
#!/bin/tcsh
# Absolute path to this script, e.g. /home/user/bin/foo.csh
set SCRIPT=`readlink -f "$0"`
# Absolute path this script is in, thus /home/user/bin
set SCRIPTPATH=`dirname "$SCRIPT"`
echo $SCRIPTPATH
See also: https://stackoverflow.com/a/246128/59087
11
Note: Not all systems havereadlink
. That's why I recommended using pushd/popd (built-ins for bash).
– docwhat
May 20 '11 at 14:29
18
The-f
option toreadlink
does something different on OS X (Lion) and possibly BSD. stackoverflow.com/questions/1055671/…
– Ergwun
Jun 29 '12 at 1:33
7
To clarify @Ergwun's comment:-f
is not supported on OS X at all (as of Lion); there you can either drop the-f
to make do with resolving at most one level of indirection, e.g.pushd "$(dirname "$(readlink "$BASH_SOURCE" || echo "$BASH_SOURCE")")"
, or you can roll your own recursive symlink-following script as demonstrated in the linked post.
– mklement0
Jul 19 '12 at 19:37
2
I still don't understand, why the OP would need the absolute path. Reporting "." should work alright if you want to access files relative to the scripts path and you called the script like ./myscript.sh
– Stefan Haberl
Mar 12 '14 at 8:25
9
@StefanHaberl I think it would be an issue if you ran the script while your present working directory was different from the script's location (e.g.sh /some/other/directory/script.sh)
, in this case.
would be your pwd, not/some/other/directory
– Jon z
Oct 9 '14 at 11:18
|
show 8 more comments
The original post contains the solution (ignore the responses, they don't add anything useful). The interesting work is done by the mentioned unix command readlink
with option -f
. Works when the script is called by an absolute as well as by a relative path.
For bash, sh, ksh:
#!/bin/bash
# Absolute path to this script, e.g. /home/user/bin/foo.sh
SCRIPT=$(readlink -f "$0")
# Absolute path this script is in, thus /home/user/bin
SCRIPTPATH=$(dirname "$SCRIPT")
echo $SCRIPTPATH
For tcsh, csh:
#!/bin/tcsh
# Absolute path to this script, e.g. /home/user/bin/foo.csh
set SCRIPT=`readlink -f "$0"`
# Absolute path this script is in, thus /home/user/bin
set SCRIPTPATH=`dirname "$SCRIPT"`
echo $SCRIPTPATH
See also: https://stackoverflow.com/a/246128/59087
The original post contains the solution (ignore the responses, they don't add anything useful). The interesting work is done by the mentioned unix command readlink
with option -f
. Works when the script is called by an absolute as well as by a relative path.
For bash, sh, ksh:
#!/bin/bash
# Absolute path to this script, e.g. /home/user/bin/foo.sh
SCRIPT=$(readlink -f "$0")
# Absolute path this script is in, thus /home/user/bin
SCRIPTPATH=$(dirname "$SCRIPT")
echo $SCRIPTPATH
For tcsh, csh:
#!/bin/tcsh
# Absolute path to this script, e.g. /home/user/bin/foo.csh
set SCRIPT=`readlink -f "$0"`
# Absolute path this script is in, thus /home/user/bin
set SCRIPTPATH=`dirname "$SCRIPT"`
echo $SCRIPTPATH
See also: https://stackoverflow.com/a/246128/59087
edited May 23 '17 at 11:55
Community♦
11
11
answered Oct 28 '09 at 16:28
al.al.
3,4251113
3,4251113
11
Note: Not all systems havereadlink
. That's why I recommended using pushd/popd (built-ins for bash).
– docwhat
May 20 '11 at 14:29
18
The-f
option toreadlink
does something different on OS X (Lion) and possibly BSD. stackoverflow.com/questions/1055671/…
– Ergwun
Jun 29 '12 at 1:33
7
To clarify @Ergwun's comment:-f
is not supported on OS X at all (as of Lion); there you can either drop the-f
to make do with resolving at most one level of indirection, e.g.pushd "$(dirname "$(readlink "$BASH_SOURCE" || echo "$BASH_SOURCE")")"
, or you can roll your own recursive symlink-following script as demonstrated in the linked post.
– mklement0
Jul 19 '12 at 19:37
2
I still don't understand, why the OP would need the absolute path. Reporting "." should work alright if you want to access files relative to the scripts path and you called the script like ./myscript.sh
– Stefan Haberl
Mar 12 '14 at 8:25
9
@StefanHaberl I think it would be an issue if you ran the script while your present working directory was different from the script's location (e.g.sh /some/other/directory/script.sh)
, in this case.
would be your pwd, not/some/other/directory
– Jon z
Oct 9 '14 at 11:18
|
show 8 more comments
11
Note: Not all systems havereadlink
. That's why I recommended using pushd/popd (built-ins for bash).
– docwhat
May 20 '11 at 14:29
18
The-f
option toreadlink
does something different on OS X (Lion) and possibly BSD. stackoverflow.com/questions/1055671/…
– Ergwun
Jun 29 '12 at 1:33
7
To clarify @Ergwun's comment:-f
is not supported on OS X at all (as of Lion); there you can either drop the-f
to make do with resolving at most one level of indirection, e.g.pushd "$(dirname "$(readlink "$BASH_SOURCE" || echo "$BASH_SOURCE")")"
, or you can roll your own recursive symlink-following script as demonstrated in the linked post.
– mklement0
Jul 19 '12 at 19:37
2
I still don't understand, why the OP would need the absolute path. Reporting "." should work alright if you want to access files relative to the scripts path and you called the script like ./myscript.sh
– Stefan Haberl
Mar 12 '14 at 8:25
9
@StefanHaberl I think it would be an issue if you ran the script while your present working directory was different from the script's location (e.g.sh /some/other/directory/script.sh)
, in this case.
would be your pwd, not/some/other/directory
– Jon z
Oct 9 '14 at 11:18
11
11
Note: Not all systems have
readlink
. That's why I recommended using pushd/popd (built-ins for bash).– docwhat
May 20 '11 at 14:29
Note: Not all systems have
readlink
. That's why I recommended using pushd/popd (built-ins for bash).– docwhat
May 20 '11 at 14:29
18
18
The
-f
option to readlink
does something different on OS X (Lion) and possibly BSD. stackoverflow.com/questions/1055671/…– Ergwun
Jun 29 '12 at 1:33
The
-f
option to readlink
does something different on OS X (Lion) and possibly BSD. stackoverflow.com/questions/1055671/…– Ergwun
Jun 29 '12 at 1:33
7
7
To clarify @Ergwun's comment:
-f
is not supported on OS X at all (as of Lion); there you can either drop the -f
to make do with resolving at most one level of indirection, e.g. pushd "$(dirname "$(readlink "$BASH_SOURCE" || echo "$BASH_SOURCE")")"
, or you can roll your own recursive symlink-following script as demonstrated in the linked post.– mklement0
Jul 19 '12 at 19:37
To clarify @Ergwun's comment:
-f
is not supported on OS X at all (as of Lion); there you can either drop the -f
to make do with resolving at most one level of indirection, e.g. pushd "$(dirname "$(readlink "$BASH_SOURCE" || echo "$BASH_SOURCE")")"
, or you can roll your own recursive symlink-following script as demonstrated in the linked post.– mklement0
Jul 19 '12 at 19:37
2
2
I still don't understand, why the OP would need the absolute path. Reporting "." should work alright if you want to access files relative to the scripts path and you called the script like ./myscript.sh
– Stefan Haberl
Mar 12 '14 at 8:25
I still don't understand, why the OP would need the absolute path. Reporting "." should work alright if you want to access files relative to the scripts path and you called the script like ./myscript.sh
– Stefan Haberl
Mar 12 '14 at 8:25
9
9
@StefanHaberl I think it would be an issue if you ran the script while your present working directory was different from the script's location (e.g.
sh /some/other/directory/script.sh)
, in this case .
would be your pwd, not /some/other/directory
– Jon z
Oct 9 '14 at 11:18
@StefanHaberl I think it would be an issue if you ran the script while your present working directory was different from the script's location (e.g.
sh /some/other/directory/script.sh)
, in this case .
would be your pwd, not /some/other/directory
– Jon z
Oct 9 '14 at 11:18
|
show 8 more comments
An earlier comment on an answer said it, but it is easy to miss among all the other answers.
When using bash:
echo this file: "$BASH_SOURCE"
echo this dir: "$(dirname "$BASH_SOURCE")"
Bash Reference Manual, 5.2 Bash Variables
4
This is what I was looking for. I needed to get the absolute path of the currently executing script.
– Aaron Blenkush
Nov 15 '13 at 17:09
2
Only this one works with script in environment path, the most voted ones do not work. thank you!
– July
Sep 22 '16 at 5:20
1
Best solution of all
– Alexandro de Oliveira
Jun 20 '17 at 5:23
You should usedirname "$BASH_SOURCE"
instead to handle spaces in $BASH_SOURCE.
– Mygod
Jan 8 '18 at 12:16
A more explicit way to print the directory would, according to tool ShellCheck, be: "$(dirname "${BASH_SOURCE{0}}")" because BASH_SOURCE is an array, and without the subscript, the first element is taken by default.
– Adrian M.
Dec 2 '18 at 3:55
add a comment |
An earlier comment on an answer said it, but it is easy to miss among all the other answers.
When using bash:
echo this file: "$BASH_SOURCE"
echo this dir: "$(dirname "$BASH_SOURCE")"
Bash Reference Manual, 5.2 Bash Variables
4
This is what I was looking for. I needed to get the absolute path of the currently executing script.
– Aaron Blenkush
Nov 15 '13 at 17:09
2
Only this one works with script in environment path, the most voted ones do not work. thank you!
– July
Sep 22 '16 at 5:20
1
Best solution of all
– Alexandro de Oliveira
Jun 20 '17 at 5:23
You should usedirname "$BASH_SOURCE"
instead to handle spaces in $BASH_SOURCE.
– Mygod
Jan 8 '18 at 12:16
A more explicit way to print the directory would, according to tool ShellCheck, be: "$(dirname "${BASH_SOURCE{0}}")" because BASH_SOURCE is an array, and without the subscript, the first element is taken by default.
– Adrian M.
Dec 2 '18 at 3:55
add a comment |
An earlier comment on an answer said it, but it is easy to miss among all the other answers.
When using bash:
echo this file: "$BASH_SOURCE"
echo this dir: "$(dirname "$BASH_SOURCE")"
Bash Reference Manual, 5.2 Bash Variables
An earlier comment on an answer said it, but it is easy to miss among all the other answers.
When using bash:
echo this file: "$BASH_SOURCE"
echo this dir: "$(dirname "$BASH_SOURCE")"
Bash Reference Manual, 5.2 Bash Variables
edited Nov 6 '18 at 1:21
0az
264414
264414
answered Apr 5 '13 at 2:35
DanielDaniel
99511120
99511120
4
This is what I was looking for. I needed to get the absolute path of the currently executing script.
– Aaron Blenkush
Nov 15 '13 at 17:09
2
Only this one works with script in environment path, the most voted ones do not work. thank you!
– July
Sep 22 '16 at 5:20
1
Best solution of all
– Alexandro de Oliveira
Jun 20 '17 at 5:23
You should usedirname "$BASH_SOURCE"
instead to handle spaces in $BASH_SOURCE.
– Mygod
Jan 8 '18 at 12:16
A more explicit way to print the directory would, according to tool ShellCheck, be: "$(dirname "${BASH_SOURCE{0}}")" because BASH_SOURCE is an array, and without the subscript, the first element is taken by default.
– Adrian M.
Dec 2 '18 at 3:55
add a comment |
4
This is what I was looking for. I needed to get the absolute path of the currently executing script.
– Aaron Blenkush
Nov 15 '13 at 17:09
2
Only this one works with script in environment path, the most voted ones do not work. thank you!
– July
Sep 22 '16 at 5:20
1
Best solution of all
– Alexandro de Oliveira
Jun 20 '17 at 5:23
You should usedirname "$BASH_SOURCE"
instead to handle spaces in $BASH_SOURCE.
– Mygod
Jan 8 '18 at 12:16
A more explicit way to print the directory would, according to tool ShellCheck, be: "$(dirname "${BASH_SOURCE{0}}")" because BASH_SOURCE is an array, and without the subscript, the first element is taken by default.
– Adrian M.
Dec 2 '18 at 3:55
4
4
This is what I was looking for. I needed to get the absolute path of the currently executing script.
– Aaron Blenkush
Nov 15 '13 at 17:09
This is what I was looking for. I needed to get the absolute path of the currently executing script.
– Aaron Blenkush
Nov 15 '13 at 17:09
2
2
Only this one works with script in environment path, the most voted ones do not work. thank you!
– July
Sep 22 '16 at 5:20
Only this one works with script in environment path, the most voted ones do not work. thank you!
– July
Sep 22 '16 at 5:20
1
1
Best solution of all
– Alexandro de Oliveira
Jun 20 '17 at 5:23
Best solution of all
– Alexandro de Oliveira
Jun 20 '17 at 5:23
You should use
dirname "$BASH_SOURCE"
instead to handle spaces in $BASH_SOURCE.– Mygod
Jan 8 '18 at 12:16
You should use
dirname "$BASH_SOURCE"
instead to handle spaces in $BASH_SOURCE.– Mygod
Jan 8 '18 at 12:16
A more explicit way to print the directory would, according to tool ShellCheck, be: "$(dirname "${BASH_SOURCE{0}}")" because BASH_SOURCE is an array, and without the subscript, the first element is taken by default.
– Adrian M.
Dec 2 '18 at 3:55
A more explicit way to print the directory would, according to tool ShellCheck, be: "$(dirname "${BASH_SOURCE{0}}")" because BASH_SOURCE is an array, and without the subscript, the first element is taken by default.
– Adrian M.
Dec 2 '18 at 3:55
add a comment |
Assuming you're using bash
#!/bin/bash
current_dir=$(pwd)
script_dir=$(dirname $0)
echo $current_dir
echo $script_dir
This script should print the directory that you're in, and then the directory the script is in. For example, when calling it from /
with the script in /home/mez/
, it outputs
/
/home/mez
Remember, when assigning variables from the output of a command, wrap the command in $(
and )
- or you won't get the desired output.
2
This won't work when I invoke the script from current dir.
– Eric Wang
Mar 13 '17 at 7:17
Does not work when there run from symlink.
– ctrl-alt-delor
Sep 22 '17 at 12:18
1
@EricWang you are always in current directory.
– ctrl-alt-delor
Sep 22 '17 at 12:19
add a comment |
Assuming you're using bash
#!/bin/bash
current_dir=$(pwd)
script_dir=$(dirname $0)
echo $current_dir
echo $script_dir
This script should print the directory that you're in, and then the directory the script is in. For example, when calling it from /
with the script in /home/mez/
, it outputs
/
/home/mez
Remember, when assigning variables from the output of a command, wrap the command in $(
and )
- or you won't get the desired output.
2
This won't work when I invoke the script from current dir.
– Eric Wang
Mar 13 '17 at 7:17
Does not work when there run from symlink.
– ctrl-alt-delor
Sep 22 '17 at 12:18
1
@EricWang you are always in current directory.
– ctrl-alt-delor
Sep 22 '17 at 12:19
add a comment |
Assuming you're using bash
#!/bin/bash
current_dir=$(pwd)
script_dir=$(dirname $0)
echo $current_dir
echo $script_dir
This script should print the directory that you're in, and then the directory the script is in. For example, when calling it from /
with the script in /home/mez/
, it outputs
/
/home/mez
Remember, when assigning variables from the output of a command, wrap the command in $(
and )
- or you won't get the desired output.
Assuming you're using bash
#!/bin/bash
current_dir=$(pwd)
script_dir=$(dirname $0)
echo $current_dir
echo $script_dir
This script should print the directory that you're in, and then the directory the script is in. For example, when calling it from /
with the script in /home/mez/
, it outputs
/
/home/mez
Remember, when assigning variables from the output of a command, wrap the command in $(
and )
- or you won't get the desired output.
edited Feb 19 '18 at 22:26
Nathan Vērzemnieks
2,7651616
2,7651616
answered Oct 28 '08 at 8:29
MezMez
16.5k136290
16.5k136290
2
This won't work when I invoke the script from current dir.
– Eric Wang
Mar 13 '17 at 7:17
Does not work when there run from symlink.
– ctrl-alt-delor
Sep 22 '17 at 12:18
1
@EricWang you are always in current directory.
– ctrl-alt-delor
Sep 22 '17 at 12:19
add a comment |
2
This won't work when I invoke the script from current dir.
– Eric Wang
Mar 13 '17 at 7:17
Does not work when there run from symlink.
– ctrl-alt-delor
Sep 22 '17 at 12:18
1
@EricWang you are always in current directory.
– ctrl-alt-delor
Sep 22 '17 at 12:19
2
2
This won't work when I invoke the script from current dir.
– Eric Wang
Mar 13 '17 at 7:17
This won't work when I invoke the script from current dir.
– Eric Wang
Mar 13 '17 at 7:17
Does not work when there run from symlink.
– ctrl-alt-delor
Sep 22 '17 at 12:18
Does not work when there run from symlink.
– ctrl-alt-delor
Sep 22 '17 at 12:18
1
1
@EricWang you are always in current directory.
– ctrl-alt-delor
Sep 22 '17 at 12:19
@EricWang you are always in current directory.
– ctrl-alt-delor
Sep 22 '17 at 12:19
add a comment |
If you're using bash....
#!/bin/bash
pushd $(dirname "${0}") > /dev/null
basedir=$(pwd -L)
# Use "pwd -P" for the path without links. man bash for more info.
popd > /dev/null
echo "${basedir}"
3
You can replace thepushd
/popd
withcd $(dirname "${0}")
andcd -
to make it work on other shells, if they have apwd -L
.
– docwhat
May 20 '11 at 14:30
why would you use pushd and popd here?
– qodeninja
Mar 25 '14 at 23:17
1
So I don't have to store the original directory in a variable. It's a pattern I use a lot in functions and such. It nests really well, which is good.
– docwhat
Mar 27 '14 at 3:06
It is still being stored in memory -- in a variable -- whether a variable is referenced in your script or not. Also, I believe the cost of executing pushd and popd far outweighs the savings of not creating a local Bash variable in your script, both in CPU cycles and readability.
– ingyhere
Jan 6 '16 at 21:07
this is the first answer which actually works
– Blauhirn
Dec 5 '16 at 14:45
add a comment |
If you're using bash....
#!/bin/bash
pushd $(dirname "${0}") > /dev/null
basedir=$(pwd -L)
# Use "pwd -P" for the path without links. man bash for more info.
popd > /dev/null
echo "${basedir}"
3
You can replace thepushd
/popd
withcd $(dirname "${0}")
andcd -
to make it work on other shells, if they have apwd -L
.
– docwhat
May 20 '11 at 14:30
why would you use pushd and popd here?
– qodeninja
Mar 25 '14 at 23:17
1
So I don't have to store the original directory in a variable. It's a pattern I use a lot in functions and such. It nests really well, which is good.
– docwhat
Mar 27 '14 at 3:06
It is still being stored in memory -- in a variable -- whether a variable is referenced in your script or not. Also, I believe the cost of executing pushd and popd far outweighs the savings of not creating a local Bash variable in your script, both in CPU cycles and readability.
– ingyhere
Jan 6 '16 at 21:07
this is the first answer which actually works
– Blauhirn
Dec 5 '16 at 14:45
add a comment |
If you're using bash....
#!/bin/bash
pushd $(dirname "${0}") > /dev/null
basedir=$(pwd -L)
# Use "pwd -P" for the path without links. man bash for more info.
popd > /dev/null
echo "${basedir}"
If you're using bash....
#!/bin/bash
pushd $(dirname "${0}") > /dev/null
basedir=$(pwd -L)
# Use "pwd -P" for the path without links. man bash for more info.
popd > /dev/null
echo "${basedir}"
answered Mar 18 '10 at 20:09
docwhatdocwhat
8,60854647
8,60854647
3
You can replace thepushd
/popd
withcd $(dirname "${0}")
andcd -
to make it work on other shells, if they have apwd -L
.
– docwhat
May 20 '11 at 14:30
why would you use pushd and popd here?
– qodeninja
Mar 25 '14 at 23:17
1
So I don't have to store the original directory in a variable. It's a pattern I use a lot in functions and such. It nests really well, which is good.
– docwhat
Mar 27 '14 at 3:06
It is still being stored in memory -- in a variable -- whether a variable is referenced in your script or not. Also, I believe the cost of executing pushd and popd far outweighs the savings of not creating a local Bash variable in your script, both in CPU cycles and readability.
– ingyhere
Jan 6 '16 at 21:07
this is the first answer which actually works
– Blauhirn
Dec 5 '16 at 14:45
add a comment |
3
You can replace thepushd
/popd
withcd $(dirname "${0}")
andcd -
to make it work on other shells, if they have apwd -L
.
– docwhat
May 20 '11 at 14:30
why would you use pushd and popd here?
– qodeninja
Mar 25 '14 at 23:17
1
So I don't have to store the original directory in a variable. It's a pattern I use a lot in functions and such. It nests really well, which is good.
– docwhat
Mar 27 '14 at 3:06
It is still being stored in memory -- in a variable -- whether a variable is referenced in your script or not. Also, I believe the cost of executing pushd and popd far outweighs the savings of not creating a local Bash variable in your script, both in CPU cycles and readability.
– ingyhere
Jan 6 '16 at 21:07
this is the first answer which actually works
– Blauhirn
Dec 5 '16 at 14:45
3
3
You can replace the
pushd
/popd
with cd $(dirname "${0}")
and cd -
to make it work on other shells, if they have a pwd -L
.– docwhat
May 20 '11 at 14:30
You can replace the
pushd
/popd
with cd $(dirname "${0}")
and cd -
to make it work on other shells, if they have a pwd -L
.– docwhat
May 20 '11 at 14:30
why would you use pushd and popd here?
– qodeninja
Mar 25 '14 at 23:17
why would you use pushd and popd here?
– qodeninja
Mar 25 '14 at 23:17
1
1
So I don't have to store the original directory in a variable. It's a pattern I use a lot in functions and such. It nests really well, which is good.
– docwhat
Mar 27 '14 at 3:06
So I don't have to store the original directory in a variable. It's a pattern I use a lot in functions and such. It nests really well, which is good.
– docwhat
Mar 27 '14 at 3:06
It is still being stored in memory -- in a variable -- whether a variable is referenced in your script or not. Also, I believe the cost of executing pushd and popd far outweighs the savings of not creating a local Bash variable in your script, both in CPU cycles and readability.
– ingyhere
Jan 6 '16 at 21:07
It is still being stored in memory -- in a variable -- whether a variable is referenced in your script or not. Also, I believe the cost of executing pushd and popd far outweighs the savings of not creating a local Bash variable in your script, both in CPU cycles and readability.
– ingyhere
Jan 6 '16 at 21:07
this is the first answer which actually works
– Blauhirn
Dec 5 '16 at 14:45
this is the first answer which actually works
– Blauhirn
Dec 5 '16 at 14:45
add a comment |
As theMarko suggests:
BASEDIR=$(dirname $0)
echo $BASEDIR
This works unless you execute the script from the same directory where the script resides, in which case you get a value of '.'
To get around that issue use:
current_dir=$(pwd)
script_dir=$(dirname $0)
if [ $script_dir = '.' ]
then
script_dir="$current_dir"
fi
You can now use the variable current_dir throughout your script to refer to the script directory. However this may still have the symlink issue.
script_dir=$(dirname $0) could also return ..
– Rooster242
Jul 1 '18 at 1:46
add a comment |
As theMarko suggests:
BASEDIR=$(dirname $0)
echo $BASEDIR
This works unless you execute the script from the same directory where the script resides, in which case you get a value of '.'
To get around that issue use:
current_dir=$(pwd)
script_dir=$(dirname $0)
if [ $script_dir = '.' ]
then
script_dir="$current_dir"
fi
You can now use the variable current_dir throughout your script to refer to the script directory. However this may still have the symlink issue.
script_dir=$(dirname $0) could also return ..
– Rooster242
Jul 1 '18 at 1:46
add a comment |
As theMarko suggests:
BASEDIR=$(dirname $0)
echo $BASEDIR
This works unless you execute the script from the same directory where the script resides, in which case you get a value of '.'
To get around that issue use:
current_dir=$(pwd)
script_dir=$(dirname $0)
if [ $script_dir = '.' ]
then
script_dir="$current_dir"
fi
You can now use the variable current_dir throughout your script to refer to the script directory. However this may still have the symlink issue.
As theMarko suggests:
BASEDIR=$(dirname $0)
echo $BASEDIR
This works unless you execute the script from the same directory where the script resides, in which case you get a value of '.'
To get around that issue use:
current_dir=$(pwd)
script_dir=$(dirname $0)
if [ $script_dir = '.' ]
then
script_dir="$current_dir"
fi
You can now use the variable current_dir throughout your script to refer to the script directory. However this may still have the symlink issue.
edited Jun 7 '11 at 14:57
answered Jun 6 '11 at 16:26
ranamaloranamalo
16414
16414
script_dir=$(dirname $0) could also return ..
– Rooster242
Jul 1 '18 at 1:46
add a comment |
script_dir=$(dirname $0) could also return ..
– Rooster242
Jul 1 '18 at 1:46
script_dir=$(dirname $0) could also return ..
– Rooster242
Jul 1 '18 at 1:46
script_dir=$(dirname $0) could also return ..
– Rooster242
Jul 1 '18 at 1:46
add a comment |
The best answer for this question was answered here:
Getting the source directory of a Bash script from within
And is:
DIR="$( cd "$( dirname "${BASH_SOURCE[0]}" )" && pwd )"
One-liner which will give you the full directory name of the script no matter where it is being called from.
To understand how it works you can execute the following script:
#!/bin/bash
SOURCE="${BASH_SOURCE[0]}"
while [ -h "$SOURCE" ]; do # resolve $SOURCE until the file is no longer a symlink
TARGET="$(readlink "$SOURCE")"
if [[ $TARGET == /* ]]; then
echo "SOURCE '$SOURCE' is an absolute symlink to '$TARGET'"
SOURCE="$TARGET"
else
DIR="$( dirname "$SOURCE" )"
echo "SOURCE '$SOURCE' is a relative symlink to '$TARGET' (relative to '$DIR')"
SOURCE="$DIR/$TARGET" # if $SOURCE was a relative symlink, we need to resolve it relative to the path where the symlink file was located
fi
done
echo "SOURCE is '$SOURCE'"
RDIR="$( dirname "$SOURCE" )"
DIR="$( cd -P "$( dirname "$SOURCE" )" && pwd )"
if [ "$DIR" != "$RDIR" ]; then
echo "DIR '$RDIR' resolves to '$DIR'"
fi
echo "DIR is '$DIR'"
add a comment |
The best answer for this question was answered here:
Getting the source directory of a Bash script from within
And is:
DIR="$( cd "$( dirname "${BASH_SOURCE[0]}" )" && pwd )"
One-liner which will give you the full directory name of the script no matter where it is being called from.
To understand how it works you can execute the following script:
#!/bin/bash
SOURCE="${BASH_SOURCE[0]}"
while [ -h "$SOURCE" ]; do # resolve $SOURCE until the file is no longer a symlink
TARGET="$(readlink "$SOURCE")"
if [[ $TARGET == /* ]]; then
echo "SOURCE '$SOURCE' is an absolute symlink to '$TARGET'"
SOURCE="$TARGET"
else
DIR="$( dirname "$SOURCE" )"
echo "SOURCE '$SOURCE' is a relative symlink to '$TARGET' (relative to '$DIR')"
SOURCE="$DIR/$TARGET" # if $SOURCE was a relative symlink, we need to resolve it relative to the path where the symlink file was located
fi
done
echo "SOURCE is '$SOURCE'"
RDIR="$( dirname "$SOURCE" )"
DIR="$( cd -P "$( dirname "$SOURCE" )" && pwd )"
if [ "$DIR" != "$RDIR" ]; then
echo "DIR '$RDIR' resolves to '$DIR'"
fi
echo "DIR is '$DIR'"
add a comment |
The best answer for this question was answered here:
Getting the source directory of a Bash script from within
And is:
DIR="$( cd "$( dirname "${BASH_SOURCE[0]}" )" && pwd )"
One-liner which will give you the full directory name of the script no matter where it is being called from.
To understand how it works you can execute the following script:
#!/bin/bash
SOURCE="${BASH_SOURCE[0]}"
while [ -h "$SOURCE" ]; do # resolve $SOURCE until the file is no longer a symlink
TARGET="$(readlink "$SOURCE")"
if [[ $TARGET == /* ]]; then
echo "SOURCE '$SOURCE' is an absolute symlink to '$TARGET'"
SOURCE="$TARGET"
else
DIR="$( dirname "$SOURCE" )"
echo "SOURCE '$SOURCE' is a relative symlink to '$TARGET' (relative to '$DIR')"
SOURCE="$DIR/$TARGET" # if $SOURCE was a relative symlink, we need to resolve it relative to the path where the symlink file was located
fi
done
echo "SOURCE is '$SOURCE'"
RDIR="$( dirname "$SOURCE" )"
DIR="$( cd -P "$( dirname "$SOURCE" )" && pwd )"
if [ "$DIR" != "$RDIR" ]; then
echo "DIR '$RDIR' resolves to '$DIR'"
fi
echo "DIR is '$DIR'"
The best answer for this question was answered here:
Getting the source directory of a Bash script from within
And is:
DIR="$( cd "$( dirname "${BASH_SOURCE[0]}" )" && pwd )"
One-liner which will give you the full directory name of the script no matter where it is being called from.
To understand how it works you can execute the following script:
#!/bin/bash
SOURCE="${BASH_SOURCE[0]}"
while [ -h "$SOURCE" ]; do # resolve $SOURCE until the file is no longer a symlink
TARGET="$(readlink "$SOURCE")"
if [[ $TARGET == /* ]]; then
echo "SOURCE '$SOURCE' is an absolute symlink to '$TARGET'"
SOURCE="$TARGET"
else
DIR="$( dirname "$SOURCE" )"
echo "SOURCE '$SOURCE' is a relative symlink to '$TARGET' (relative to '$DIR')"
SOURCE="$DIR/$TARGET" # if $SOURCE was a relative symlink, we need to resolve it relative to the path where the symlink file was located
fi
done
echo "SOURCE is '$SOURCE'"
RDIR="$( dirname "$SOURCE" )"
DIR="$( cd -P "$( dirname "$SOURCE" )" && pwd )"
if [ "$DIR" != "$RDIR" ]; then
echo "DIR '$RDIR' resolves to '$DIR'"
fi
echo "DIR is '$DIR'"
edited Jun 20 '17 at 6:20
answered Jun 20 '17 at 5:59
Alexandro de OliveiraAlexandro de Oliveira
6341114
6341114
add a comment |
add a comment |
cd $(dirname $(readlink -f $0))
add a comment |
cd $(dirname $(readlink -f $0))
add a comment |
cd $(dirname $(readlink -f $0))
cd $(dirname $(readlink -f $0))
answered Jan 14 '11 at 16:50
blueyedblueyed
20.4k35860
20.4k35860
add a comment |
add a comment |
Let's make it a POSIX oneliner:
a="/$0"; a=${a%/*}; a=${a#/}; a=${a:-.}; BASEDIR=$(cd "$a"; pwd)
Tested on many Bourne-compatible shells including the BSD ones.
As far as I know I am the author and I put it into public domain. For more info see:
https://www.jasan.tk/posts/2017-05-11-posix_shell_dirname_replacement/
1
as written,cd: too many arguments
if spaces in the path, and returns$PWD
. (an obvious fix, but just shows how many edge cases there actually are)
– michael
Jul 29 '17 at 19:02
1
Would upvote. Except for the comment from @michael that it fails with spaces in path... Is there a fix for that?
– spechter
Feb 20 '18 at 4:13
@spechter see: stackoverflow.com/a/45392962/127971
– michael
Feb 21 '18 at 19:00
1
@spechter yes, there's a fix for that. See updated jasan.tk/posix/2017/05/11/posix_shell_dirname_replacement
– Ján Sáreník
Apr 4 '18 at 17:16
1
ln -s /home/der/1/test /home/der/2/test && /home/der/2/test => /home/der/2 (should show path to the original script instead)
– Der_Meister
Oct 23 '18 at 7:41
|
show 4 more comments
Let's make it a POSIX oneliner:
a="/$0"; a=${a%/*}; a=${a#/}; a=${a:-.}; BASEDIR=$(cd "$a"; pwd)
Tested on many Bourne-compatible shells including the BSD ones.
As far as I know I am the author and I put it into public domain. For more info see:
https://www.jasan.tk/posts/2017-05-11-posix_shell_dirname_replacement/
1
as written,cd: too many arguments
if spaces in the path, and returns$PWD
. (an obvious fix, but just shows how many edge cases there actually are)
– michael
Jul 29 '17 at 19:02
1
Would upvote. Except for the comment from @michael that it fails with spaces in path... Is there a fix for that?
– spechter
Feb 20 '18 at 4:13
@spechter see: stackoverflow.com/a/45392962/127971
– michael
Feb 21 '18 at 19:00
1
@spechter yes, there's a fix for that. See updated jasan.tk/posix/2017/05/11/posix_shell_dirname_replacement
– Ján Sáreník
Apr 4 '18 at 17:16
1
ln -s /home/der/1/test /home/der/2/test && /home/der/2/test => /home/der/2 (should show path to the original script instead)
– Der_Meister
Oct 23 '18 at 7:41
|
show 4 more comments
Let's make it a POSIX oneliner:
a="/$0"; a=${a%/*}; a=${a#/}; a=${a:-.}; BASEDIR=$(cd "$a"; pwd)
Tested on many Bourne-compatible shells including the BSD ones.
As far as I know I am the author and I put it into public domain. For more info see:
https://www.jasan.tk/posts/2017-05-11-posix_shell_dirname_replacement/
Let's make it a POSIX oneliner:
a="/$0"; a=${a%/*}; a=${a#/}; a=${a:-.}; BASEDIR=$(cd "$a"; pwd)
Tested on many Bourne-compatible shells including the BSD ones.
As far as I know I am the author and I put it into public domain. For more info see:
https://www.jasan.tk/posts/2017-05-11-posix_shell_dirname_replacement/
edited Oct 18 '18 at 7:04
community wiki
6 revs
Ján Sáreník
1
as written,cd: too many arguments
if spaces in the path, and returns$PWD
. (an obvious fix, but just shows how many edge cases there actually are)
– michael
Jul 29 '17 at 19:02
1
Would upvote. Except for the comment from @michael that it fails with spaces in path... Is there a fix for that?
– spechter
Feb 20 '18 at 4:13
@spechter see: stackoverflow.com/a/45392962/127971
– michael
Feb 21 '18 at 19:00
1
@spechter yes, there's a fix for that. See updated jasan.tk/posix/2017/05/11/posix_shell_dirname_replacement
– Ján Sáreník
Apr 4 '18 at 17:16
1
ln -s /home/der/1/test /home/der/2/test && /home/der/2/test => /home/der/2 (should show path to the original script instead)
– Der_Meister
Oct 23 '18 at 7:41
|
show 4 more comments
1
as written,cd: too many arguments
if spaces in the path, and returns$PWD
. (an obvious fix, but just shows how many edge cases there actually are)
– michael
Jul 29 '17 at 19:02
1
Would upvote. Except for the comment from @michael that it fails with spaces in path... Is there a fix for that?
– spechter
Feb 20 '18 at 4:13
@spechter see: stackoverflow.com/a/45392962/127971
– michael
Feb 21 '18 at 19:00
1
@spechter yes, there's a fix for that. See updated jasan.tk/posix/2017/05/11/posix_shell_dirname_replacement
– Ján Sáreník
Apr 4 '18 at 17:16
1
ln -s /home/der/1/test /home/der/2/test && /home/der/2/test => /home/der/2 (should show path to the original script instead)
– Der_Meister
Oct 23 '18 at 7:41
1
1
as written,
cd: too many arguments
if spaces in the path, and returns $PWD
. (an obvious fix, but just shows how many edge cases there actually are)– michael
Jul 29 '17 at 19:02
as written,
cd: too many arguments
if spaces in the path, and returns $PWD
. (an obvious fix, but just shows how many edge cases there actually are)– michael
Jul 29 '17 at 19:02
1
1
Would upvote. Except for the comment from @michael that it fails with spaces in path... Is there a fix for that?
– spechter
Feb 20 '18 at 4:13
Would upvote. Except for the comment from @michael that it fails with spaces in path... Is there a fix for that?
– spechter
Feb 20 '18 at 4:13
@spechter see: stackoverflow.com/a/45392962/127971
– michael
Feb 21 '18 at 19:00
@spechter see: stackoverflow.com/a/45392962/127971
– michael
Feb 21 '18 at 19:00
1
1
@spechter yes, there's a fix for that. See updated jasan.tk/posix/2017/05/11/posix_shell_dirname_replacement
– Ján Sáreník
Apr 4 '18 at 17:16
@spechter yes, there's a fix for that. See updated jasan.tk/posix/2017/05/11/posix_shell_dirname_replacement
– Ján Sáreník
Apr 4 '18 at 17:16
1
1
ln -s /home/der/1/test /home/der/2/test && /home/der/2/test => /home/der/2 (should show path to the original script instead)
– Der_Meister
Oct 23 '18 at 7:41
ln -s /home/der/1/test /home/der/2/test && /home/der/2/test => /home/der/2 (should show path to the original script instead)
– Der_Meister
Oct 23 '18 at 7:41
|
show 4 more comments
BASE_DIR="$(cd "$(dirname "$0")"; pwd)";
echo "BASE_DIR => $BASE_DIR"
1
most reliable non-bash-specific way I know.
– eddygeek
Oct 2 '18 at 9:35
add a comment |
BASE_DIR="$(cd "$(dirname "$0")"; pwd)";
echo "BASE_DIR => $BASE_DIR"
1
most reliable non-bash-specific way I know.
– eddygeek
Oct 2 '18 at 9:35
add a comment |
BASE_DIR="$(cd "$(dirname "$0")"; pwd)";
echo "BASE_DIR => $BASE_DIR"
BASE_DIR="$(cd "$(dirname "$0")"; pwd)";
echo "BASE_DIR => $BASE_DIR"
edited Nov 14 '18 at 17:35
kvantour
8,87331330
8,87331330
answered Sep 12 '18 at 11:14
searchromesearchrome
512
512
1
most reliable non-bash-specific way I know.
– eddygeek
Oct 2 '18 at 9:35
add a comment |
1
most reliable non-bash-specific way I know.
– eddygeek
Oct 2 '18 at 9:35
1
1
most reliable non-bash-specific way I know.
– eddygeek
Oct 2 '18 at 9:35
most reliable non-bash-specific way I know.
– eddygeek
Oct 2 '18 at 9:35
add a comment |
Inspired by blueyed’s answer
read < <(readlink -f $0 | xargs dirname)
cd $REPLY
add a comment |
Inspired by blueyed’s answer
read < <(readlink -f $0 | xargs dirname)
cd $REPLY
add a comment |
Inspired by blueyed’s answer
read < <(readlink -f $0 | xargs dirname)
cd $REPLY
Inspired by blueyed’s answer
read < <(readlink -f $0 | xargs dirname)
cd $REPLY
edited May 23 '17 at 12:10
Community♦
11
11
answered Dec 19 '12 at 18:30
Steven PennySteven Penny
1
1
add a comment |
add a comment |
So many answers, all plausible, each with pro's and con's & slightly differeing objectives (which should probably be stated for each). Here's another solution that meets a primary objective of both being clear and working across all systems, on all bash (no assumptions about bash versions, or readlink
or pwd
options), and reasonably does what you'd expect to happen (eg, resolving symlinks is an interesting problem, but isn't usually what you actually want), handle edge cases like spaces in paths, etc., ignores any errors and uses a sane default if there are any issues.
Each component is stored in a separate variable that you can use individually:
# script path, filename, directory
PROG_PATH=${BASH_SOURCE[0]} # this script's name
PROG_NAME=${PROG_PATH##*/} # basename of script (strip path)
PROG_DIR="$(cd "$(dirname "${PROG_PATH:-$PWD}")" 2>/dev/null 1>&2 && pwd)"
add a comment |
So many answers, all plausible, each with pro's and con's & slightly differeing objectives (which should probably be stated for each). Here's another solution that meets a primary objective of both being clear and working across all systems, on all bash (no assumptions about bash versions, or readlink
or pwd
options), and reasonably does what you'd expect to happen (eg, resolving symlinks is an interesting problem, but isn't usually what you actually want), handle edge cases like spaces in paths, etc., ignores any errors and uses a sane default if there are any issues.
Each component is stored in a separate variable that you can use individually:
# script path, filename, directory
PROG_PATH=${BASH_SOURCE[0]} # this script's name
PROG_NAME=${PROG_PATH##*/} # basename of script (strip path)
PROG_DIR="$(cd "$(dirname "${PROG_PATH:-$PWD}")" 2>/dev/null 1>&2 && pwd)"
add a comment |
So many answers, all plausible, each with pro's and con's & slightly differeing objectives (which should probably be stated for each). Here's another solution that meets a primary objective of both being clear and working across all systems, on all bash (no assumptions about bash versions, or readlink
or pwd
options), and reasonably does what you'd expect to happen (eg, resolving symlinks is an interesting problem, but isn't usually what you actually want), handle edge cases like spaces in paths, etc., ignores any errors and uses a sane default if there are any issues.
Each component is stored in a separate variable that you can use individually:
# script path, filename, directory
PROG_PATH=${BASH_SOURCE[0]} # this script's name
PROG_NAME=${PROG_PATH##*/} # basename of script (strip path)
PROG_DIR="$(cd "$(dirname "${PROG_PATH:-$PWD}")" 2>/dev/null 1>&2 && pwd)"
So many answers, all plausible, each with pro's and con's & slightly differeing objectives (which should probably be stated for each). Here's another solution that meets a primary objective of both being clear and working across all systems, on all bash (no assumptions about bash versions, or readlink
or pwd
options), and reasonably does what you'd expect to happen (eg, resolving symlinks is an interesting problem, but isn't usually what you actually want), handle edge cases like spaces in paths, etc., ignores any errors and uses a sane default if there are any issues.
Each component is stored in a separate variable that you can use individually:
# script path, filename, directory
PROG_PATH=${BASH_SOURCE[0]} # this script's name
PROG_NAME=${PROG_PATH##*/} # basename of script (strip path)
PROG_DIR="$(cd "$(dirname "${PROG_PATH:-$PWD}")" 2>/dev/null 1>&2 && pwd)"
answered Jul 29 '17 at 18:58
michaelmichael
4,40013139
4,40013139
add a comment |
add a comment |
INTRODUCTION
This answer corrects the very broken but shockingly top voted answer of this thread (written by TheMarko):
#!/usr/bin/env bash
BASEDIR=$(dirname "$0")
echo "$BASEDIR"
WHY DOES USING dirname "$0" ON IT'S OWN NOT WORK?
dirname $0 will only work if user launches script in a very specific way. I was able to find several situations where this answer fails and crashes the script.
First of all, let's understand how this answer works. He's getting the script directory by doing
dirname "$0"
$0 represents the first part of the command calling the script (it's basically the inputted command without the arguments:
/some/path/./script argument1 argument2
$0="/some/path/./script"
dirname basically finds the last / in a string and truncates it there. So if you do:
dirname /usr/bin/sha256sum
you'll get: /usr/bin
This example works well because /usr/bin/sha256sum is a properly formatted path but
dirname "/some/path/./script"
wouldn't work well and would give you:
BASENAME="/some/path/." #which would crash your script if you try to use it as a path
Say you're in the same dir as your script and you launch it with this command
./script
$0 in this situation will be ./script and dirname $0 will give:
. #or BASEDIR=".", again this will crash your script
Using:
sh script
Without inputting the full path will also give a BASEDIR="."
Using relative directories:
../some/path/./script
Gives a dirname $0 of:
../some/path/.
If you're in the /some directory and you call the script in this manner (note the absence of / in the beginning, again a relative path):
path/./script.sh
You'll get this value for dirname $0:
path/.
and ./path/./script (another form of the relative path) gives:
./path/.
The only two situations where basedir $0 will work is if the user use sh or touch to launch a script because both will result in $0:
$0=/some/path/script
which will give you a path you can use with dirname.
THE SOLUTION
You'd have account for and detect every one of the above mentioned situations and apply a fix for it if it arises:
#!/bin/bash
#this script will only work in bash, make sure it's installed on your system.
#set to false to not see all the echos
debug=true
if [ "$debug" = true ]; then echo "$0=$0";fi
#The line below detect script's parent directory. $0 is the part of the launch command that doesn't contain the arguments
BASEDIR=$(dirname "$0") #3 situations will cause dirname $0 to fail: #situation1: user launches script while in script dir ( $0=./script)
#situation2: different dir but ./ is used to launch script (ex. $0=/path_to/./script)
#situation3: different dir but relative path used to launch script
if [ "$debug" = true ]; then echo 'BASEDIR=$(dirname "$0") gives: '"$BASEDIR";fi
if [ "$BASEDIR" = "." ]; then BASEDIR="$(pwd)";fi # fix for situation1
_B2=${BASEDIR:$((${#BASEDIR}-2))}; B_=${BASEDIR::1}; B_2=${BASEDIR::2}; B_3=${BASEDIR::3} # <- bash only
if [ "$_B2" = "/." ]; then BASEDIR=${BASEDIR::$((${#BASEDIR}-1))};fi #fix for situation2 # <- bash only
if [ "$B_" != "/" ]; then #fix for situation3 #<- bash only
if [ "$B_2" = "./" ]; then
#covers ./relative_path/(./)script
if [ "$(pwd)" != "/" ]; then BASEDIR="$(pwd)/${BASEDIR:2}"; else BASEDIR="/${BASEDIR:2}";fi
else
#covers relative_path/(./)script and ../relative_path/(./)script, using ../relative_path fails if current path is a symbolic link
if [ "$(pwd)" != "/" ]; then BASEDIR="$(pwd)/$BASEDIR"; else BASEDIR="/$BASEDIR";fi
fi
fi
if [ "$debug" = true ]; then echo "fixed BASEDIR=$BASEDIR";fi
add a comment |
INTRODUCTION
This answer corrects the very broken but shockingly top voted answer of this thread (written by TheMarko):
#!/usr/bin/env bash
BASEDIR=$(dirname "$0")
echo "$BASEDIR"
WHY DOES USING dirname "$0" ON IT'S OWN NOT WORK?
dirname $0 will only work if user launches script in a very specific way. I was able to find several situations where this answer fails and crashes the script.
First of all, let's understand how this answer works. He's getting the script directory by doing
dirname "$0"
$0 represents the first part of the command calling the script (it's basically the inputted command without the arguments:
/some/path/./script argument1 argument2
$0="/some/path/./script"
dirname basically finds the last / in a string and truncates it there. So if you do:
dirname /usr/bin/sha256sum
you'll get: /usr/bin
This example works well because /usr/bin/sha256sum is a properly formatted path but
dirname "/some/path/./script"
wouldn't work well and would give you:
BASENAME="/some/path/." #which would crash your script if you try to use it as a path
Say you're in the same dir as your script and you launch it with this command
./script
$0 in this situation will be ./script and dirname $0 will give:
. #or BASEDIR=".", again this will crash your script
Using:
sh script
Without inputting the full path will also give a BASEDIR="."
Using relative directories:
../some/path/./script
Gives a dirname $0 of:
../some/path/.
If you're in the /some directory and you call the script in this manner (note the absence of / in the beginning, again a relative path):
path/./script.sh
You'll get this value for dirname $0:
path/.
and ./path/./script (another form of the relative path) gives:
./path/.
The only two situations where basedir $0 will work is if the user use sh or touch to launch a script because both will result in $0:
$0=/some/path/script
which will give you a path you can use with dirname.
THE SOLUTION
You'd have account for and detect every one of the above mentioned situations and apply a fix for it if it arises:
#!/bin/bash
#this script will only work in bash, make sure it's installed on your system.
#set to false to not see all the echos
debug=true
if [ "$debug" = true ]; then echo "$0=$0";fi
#The line below detect script's parent directory. $0 is the part of the launch command that doesn't contain the arguments
BASEDIR=$(dirname "$0") #3 situations will cause dirname $0 to fail: #situation1: user launches script while in script dir ( $0=./script)
#situation2: different dir but ./ is used to launch script (ex. $0=/path_to/./script)
#situation3: different dir but relative path used to launch script
if [ "$debug" = true ]; then echo 'BASEDIR=$(dirname "$0") gives: '"$BASEDIR";fi
if [ "$BASEDIR" = "." ]; then BASEDIR="$(pwd)";fi # fix for situation1
_B2=${BASEDIR:$((${#BASEDIR}-2))}; B_=${BASEDIR::1}; B_2=${BASEDIR::2}; B_3=${BASEDIR::3} # <- bash only
if [ "$_B2" = "/." ]; then BASEDIR=${BASEDIR::$((${#BASEDIR}-1))};fi #fix for situation2 # <- bash only
if [ "$B_" != "/" ]; then #fix for situation3 #<- bash only
if [ "$B_2" = "./" ]; then
#covers ./relative_path/(./)script
if [ "$(pwd)" != "/" ]; then BASEDIR="$(pwd)/${BASEDIR:2}"; else BASEDIR="/${BASEDIR:2}";fi
else
#covers relative_path/(./)script and ../relative_path/(./)script, using ../relative_path fails if current path is a symbolic link
if [ "$(pwd)" != "/" ]; then BASEDIR="$(pwd)/$BASEDIR"; else BASEDIR="/$BASEDIR";fi
fi
fi
if [ "$debug" = true ]; then echo "fixed BASEDIR=$BASEDIR";fi
add a comment |
INTRODUCTION
This answer corrects the very broken but shockingly top voted answer of this thread (written by TheMarko):
#!/usr/bin/env bash
BASEDIR=$(dirname "$0")
echo "$BASEDIR"
WHY DOES USING dirname "$0" ON IT'S OWN NOT WORK?
dirname $0 will only work if user launches script in a very specific way. I was able to find several situations where this answer fails and crashes the script.
First of all, let's understand how this answer works. He's getting the script directory by doing
dirname "$0"
$0 represents the first part of the command calling the script (it's basically the inputted command without the arguments:
/some/path/./script argument1 argument2
$0="/some/path/./script"
dirname basically finds the last / in a string and truncates it there. So if you do:
dirname /usr/bin/sha256sum
you'll get: /usr/bin
This example works well because /usr/bin/sha256sum is a properly formatted path but
dirname "/some/path/./script"
wouldn't work well and would give you:
BASENAME="/some/path/." #which would crash your script if you try to use it as a path
Say you're in the same dir as your script and you launch it with this command
./script
$0 in this situation will be ./script and dirname $0 will give:
. #or BASEDIR=".", again this will crash your script
Using:
sh script
Without inputting the full path will also give a BASEDIR="."
Using relative directories:
../some/path/./script
Gives a dirname $0 of:
../some/path/.
If you're in the /some directory and you call the script in this manner (note the absence of / in the beginning, again a relative path):
path/./script.sh
You'll get this value for dirname $0:
path/.
and ./path/./script (another form of the relative path) gives:
./path/.
The only two situations where basedir $0 will work is if the user use sh or touch to launch a script because both will result in $0:
$0=/some/path/script
which will give you a path you can use with dirname.
THE SOLUTION
You'd have account for and detect every one of the above mentioned situations and apply a fix for it if it arises:
#!/bin/bash
#this script will only work in bash, make sure it's installed on your system.
#set to false to not see all the echos
debug=true
if [ "$debug" = true ]; then echo "$0=$0";fi
#The line below detect script's parent directory. $0 is the part of the launch command that doesn't contain the arguments
BASEDIR=$(dirname "$0") #3 situations will cause dirname $0 to fail: #situation1: user launches script while in script dir ( $0=./script)
#situation2: different dir but ./ is used to launch script (ex. $0=/path_to/./script)
#situation3: different dir but relative path used to launch script
if [ "$debug" = true ]; then echo 'BASEDIR=$(dirname "$0") gives: '"$BASEDIR";fi
if [ "$BASEDIR" = "." ]; then BASEDIR="$(pwd)";fi # fix for situation1
_B2=${BASEDIR:$((${#BASEDIR}-2))}; B_=${BASEDIR::1}; B_2=${BASEDIR::2}; B_3=${BASEDIR::3} # <- bash only
if [ "$_B2" = "/." ]; then BASEDIR=${BASEDIR::$((${#BASEDIR}-1))};fi #fix for situation2 # <- bash only
if [ "$B_" != "/" ]; then #fix for situation3 #<- bash only
if [ "$B_2" = "./" ]; then
#covers ./relative_path/(./)script
if [ "$(pwd)" != "/" ]; then BASEDIR="$(pwd)/${BASEDIR:2}"; else BASEDIR="/${BASEDIR:2}";fi
else
#covers relative_path/(./)script and ../relative_path/(./)script, using ../relative_path fails if current path is a symbolic link
if [ "$(pwd)" != "/" ]; then BASEDIR="$(pwd)/$BASEDIR"; else BASEDIR="/$BASEDIR";fi
fi
fi
if [ "$debug" = true ]; then echo "fixed BASEDIR=$BASEDIR";fi
INTRODUCTION
This answer corrects the very broken but shockingly top voted answer of this thread (written by TheMarko):
#!/usr/bin/env bash
BASEDIR=$(dirname "$0")
echo "$BASEDIR"
WHY DOES USING dirname "$0" ON IT'S OWN NOT WORK?
dirname $0 will only work if user launches script in a very specific way. I was able to find several situations where this answer fails and crashes the script.
First of all, let's understand how this answer works. He's getting the script directory by doing
dirname "$0"
$0 represents the first part of the command calling the script (it's basically the inputted command without the arguments:
/some/path/./script argument1 argument2
$0="/some/path/./script"
dirname basically finds the last / in a string and truncates it there. So if you do:
dirname /usr/bin/sha256sum
you'll get: /usr/bin
This example works well because /usr/bin/sha256sum is a properly formatted path but
dirname "/some/path/./script"
wouldn't work well and would give you:
BASENAME="/some/path/." #which would crash your script if you try to use it as a path
Say you're in the same dir as your script and you launch it with this command
./script
$0 in this situation will be ./script and dirname $0 will give:
. #or BASEDIR=".", again this will crash your script
Using:
sh script
Without inputting the full path will also give a BASEDIR="."
Using relative directories:
../some/path/./script
Gives a dirname $0 of:
../some/path/.
If you're in the /some directory and you call the script in this manner (note the absence of / in the beginning, again a relative path):
path/./script.sh
You'll get this value for dirname $0:
path/.
and ./path/./script (another form of the relative path) gives:
./path/.
The only two situations where basedir $0 will work is if the user use sh or touch to launch a script because both will result in $0:
$0=/some/path/script
which will give you a path you can use with dirname.
THE SOLUTION
You'd have account for and detect every one of the above mentioned situations and apply a fix for it if it arises:
#!/bin/bash
#this script will only work in bash, make sure it's installed on your system.
#set to false to not see all the echos
debug=true
if [ "$debug" = true ]; then echo "$0=$0";fi
#The line below detect script's parent directory. $0 is the part of the launch command that doesn't contain the arguments
BASEDIR=$(dirname "$0") #3 situations will cause dirname $0 to fail: #situation1: user launches script while in script dir ( $0=./script)
#situation2: different dir but ./ is used to launch script (ex. $0=/path_to/./script)
#situation3: different dir but relative path used to launch script
if [ "$debug" = true ]; then echo 'BASEDIR=$(dirname "$0") gives: '"$BASEDIR";fi
if [ "$BASEDIR" = "." ]; then BASEDIR="$(pwd)";fi # fix for situation1
_B2=${BASEDIR:$((${#BASEDIR}-2))}; B_=${BASEDIR::1}; B_2=${BASEDIR::2}; B_3=${BASEDIR::3} # <- bash only
if [ "$_B2" = "/." ]; then BASEDIR=${BASEDIR::$((${#BASEDIR}-1))};fi #fix for situation2 # <- bash only
if [ "$B_" != "/" ]; then #fix for situation3 #<- bash only
if [ "$B_2" = "./" ]; then
#covers ./relative_path/(./)script
if [ "$(pwd)" != "/" ]; then BASEDIR="$(pwd)/${BASEDIR:2}"; else BASEDIR="/${BASEDIR:2}";fi
else
#covers relative_path/(./)script and ../relative_path/(./)script, using ../relative_path fails if current path is a symbolic link
if [ "$(pwd)" != "/" ]; then BASEDIR="$(pwd)/$BASEDIR"; else BASEDIR="/$BASEDIR";fi
fi
fi
if [ "$debug" = true ]; then echo "fixed BASEDIR=$BASEDIR";fi
edited Apr 22 '18 at 10:05
answered Apr 22 '18 at 9:53
thebunnyrulesthebunnyrules
622516
622516
add a comment |
add a comment |
This one-liner tells where the shell script is, does not matter if you ran it or if you sourced it. Also, it resolves any symbolic links involved, if that is the case:
dir=$(dirname $(test -L "$BASH_SOURCE" && readlink -f "$BASH_SOURCE" || echo "$BASH_SOURCE"))
By the way, I suppose you are using /bin/bash.
add a comment |
This one-liner tells where the shell script is, does not matter if you ran it or if you sourced it. Also, it resolves any symbolic links involved, if that is the case:
dir=$(dirname $(test -L "$BASH_SOURCE" && readlink -f "$BASH_SOURCE" || echo "$BASH_SOURCE"))
By the way, I suppose you are using /bin/bash.
add a comment |
This one-liner tells where the shell script is, does not matter if you ran it or if you sourced it. Also, it resolves any symbolic links involved, if that is the case:
dir=$(dirname $(test -L "$BASH_SOURCE" && readlink -f "$BASH_SOURCE" || echo "$BASH_SOURCE"))
By the way, I suppose you are using /bin/bash.
This one-liner tells where the shell script is, does not matter if you ran it or if you sourced it. Also, it resolves any symbolic links involved, if that is the case:
dir=$(dirname $(test -L "$BASH_SOURCE" && readlink -f "$BASH_SOURCE" || echo "$BASH_SOURCE"))
By the way, I suppose you are using /bin/bash.
answered Jun 9 '18 at 8:41
Richard GomesRichard Gomes
3,4702631
3,4702631
add a comment |
add a comment |
That should do the trick:
echo `pwd`/`dirname $0`
It might look ugly depending on how it was invoked and the cwd but should get you where you need to go (or you can tweak the string if you care how it looks).
1
stackoverflow escape problem here: it surely should look like this:`pwd`/`dirname $0`
but may still fail on symlinks
– Andreas Dietrich
Jul 24 '14 at 8:12
add a comment |
That should do the trick:
echo `pwd`/`dirname $0`
It might look ugly depending on how it was invoked and the cwd but should get you where you need to go (or you can tweak the string if you care how it looks).
1
stackoverflow escape problem here: it surely should look like this:`pwd`/`dirname $0`
but may still fail on symlinks
– Andreas Dietrich
Jul 24 '14 at 8:12
add a comment |
That should do the trick:
echo `pwd`/`dirname $0`
It might look ugly depending on how it was invoked and the cwd but should get you where you need to go (or you can tweak the string if you care how it looks).
That should do the trick:
echo `pwd`/`dirname $0`
It might look ugly depending on how it was invoked and the cwd but should get you where you need to go (or you can tweak the string if you care how it looks).
edited Sep 15 '14 at 19:32
kenorb
68k29405404
68k29405404
answered Jan 14 '09 at 19:32
foo
1
stackoverflow escape problem here: it surely should look like this:`pwd`/`dirname $0`
but may still fail on symlinks
– Andreas Dietrich
Jul 24 '14 at 8:12
add a comment |
1
stackoverflow escape problem here: it surely should look like this:`pwd`/`dirname $0`
but may still fail on symlinks
– Andreas Dietrich
Jul 24 '14 at 8:12
1
1
stackoverflow escape problem here: it surely should look like this:
`pwd`/`dirname $0`
but may still fail on symlinks– Andreas Dietrich
Jul 24 '14 at 8:12
stackoverflow escape problem here: it surely should look like this:
`pwd`/`dirname $0`
but may still fail on symlinks– Andreas Dietrich
Jul 24 '14 at 8:12
add a comment |
protected by Community♦ Jul 26 '11 at 11:14
Thank you for your interest in this question.
Because it has attracted low-quality or spam answers that had to be removed, posting an answer now requires 10 reputation on this site (the association bonus does not count).
Would you like to answer one of these unanswered questions instead?
9
Is that really a duplicate? This question is about a "unix shell script", the other specifically about Bash.
– michaeljt
Jun 23 '15 at 9:45
2
@BoltClock: This question was improperly closed. The linked question is about Bash. This question is about Unix shell programming. Notice that the accepted answers are quite different!
– Dietrich Epp
Jun 16 '16 at 7:56
@Dietrich Epp: You're right. It seems the asker's choice of accepted answer and the addition of the [bash] tag (probably in response to that) led me to marking the question as a duplicate in response to a flag.
– BoltClock♦
Jun 16 '16 at 8:03
2
I think this answer is better: Getting the source directory of a Bash script from within
– Alan Zhiliang Feng
Jun 2 '17 at 7:50
1
Possible duplicate of Getting the source directory of a Bash script from within
– dulgan
Jul 3 '17 at 13:53