72

I need to get the path of the script. I can do that using pwd if I am already in the same directory, I searched online and I found this

DIR="$( cd "$( dirname "${BASH_SOURCE[0]}" )" && pwd )"

But I don't know how to use that.

Chen Dachao
  • 1,736
  • 2
  • 21
  • 36
Alex Bloomberg
  • 855
  • 1
  • 7
  • 14
  • did you try it, i.e. `echo "script=$0 dirForScript=$DIR"` ? You should show what you have tried to solve your problem. If you put your `DIR=...` code and my `echo script=...` in a script and call the main script from different directories you should see the same result. If not, then that is an interesting Q and you can update your Q with why it "isn't working" . Good luck. – shellter Sep 06 '16 at 03:28
  • So, I have the below code in my script file now: #!/usr/bin/env bash DIR="$( cd "$( dirname "${BASH_SOURCE[0]}" )" && pwd )" echo "script=$0 dirForScript=$DIR and im trying to run it from a differetn directory and it says: -bash: Send-Transaction.sh: command not found – Alex Bloomberg Sep 06 '16 at 03:35
  • to run I'm using sh filename.sh . am i doing anything wrong or everything wrong ? – Alex Bloomberg Sep 06 '16 at 03:37
  • try `sh /full/path/to/filename.sh`. That should work. Then you have to add `/full/path/to` to your PATH env variable. For something so simple, it can be very confusing at first. Don't give up, but find a good linux tutorial and read thru about how/why of PATH. Good luck. (Going to bed ;-) . – shellter Sep 06 '16 at 03:40
  • but when I already know the full path to filename, what is the use of that ? – Alex Bloomberg Sep 06 '16 at 03:46

2 Answers2

97

Bash maintains a number of variables including BASH_SOURCE which is an array of source file pathnames.

${} acts as a kind of quoting for variables.

$() acts as a kind of quoting for commands but they're run in their own context.

dirname gives you the path portion of the provided argument.

cd changes the current directory.

pwd gives the current path.

&& is a logical and but is used in this instance for its side effect of running commands one after another.

In summary, that command gets the script's source file pathname, strips it to just the path portion, cds to that path, then uses pwd to return the (effectively) full path of the script. This is assigned to DIR. After all of that, the context is unwound so you end up back in the directory you started at but with an environment variable DIR containing the script's path.

Ouroborus
  • 16,237
  • 4
  • 39
  • 62
  • thanks for the answer, so does this tell me where my script file is located if I just run it with filename.sh in some random directory ? – Alex Bloomberg Sep 06 '16 at 03:47
  • @Anirudh Indirectly. It stores it in an environment variable rather than just displaying it on the console. It'd be up to the script as to what happens to the information. – Ouroborus Sep 06 '16 at 03:54
  • my script contains the following code: #!/usr/bin/env bash DIR="$( cd "$( dirname "${BASH_SOURCE[0]}" )" && pwd )" echo "script=$0 dirForScript=$DIR" source Demo-Commons.sh sendTransaction < Send-Transaction.json and im trying to run it from a different directory but it says filename.sh not found in directory, why is it so ? – Alex Bloomberg Sep 06 '16 at 04:00
  • @Anirudh What's the command you're using to try to run the script? – Ouroborus Sep 06 '16 at 04:12
  • @Anirudh You'd need to be in the same directory as the script for that to work. Try using the script's full pathname. – Ouroborus Sep 08 '16 at 20:31
  • But then what is the use of having that piece of code ? Isn't it supposed to make my script run from any directory ? PS: I also want you to know that I really appreciate your help bro. – Alex Bloomberg Sep 08 '16 at 22:01
  • Also, I know that if we add that path to Env variable it works from anywhere, but I just can't understand what this particular code does. – Alex Bloomberg Sep 08 '16 at 22:03
  • 4
    @Anirudh It just lets the script know its own location, not your current location. If you just need the location that you are currently in when you run the script it's a lot simpler: `DIR="$( pwd )"` – Ouroborus Sep 08 '16 at 22:40
  • 1
    What advantage does that have, if a script knows it location ? Is there a difference if it does not know ? The script still worked. – Alex Bloomberg Sep 08 '16 at 23:15
  • 1
    That's my last question, promise! – Alex Bloomberg Sep 08 '16 at 23:16
  • @Anirudh I can't think of a reason why it would be needed. I'm only able to find examples of how to do it, not why it would be necessary. Perhaps that's another question for Stackoverflow =P – Ouroborus Sep 09 '16 at 14:53
  • @Anirudh a script might have dependencies on some files (for example) that are stored in the same directory as the script, but maybe you want to make it so the script can be run from *any* directory. e.g. `cd /foo ; /bar/myScript.sh` means myScript.sh can `cd ${DIR}` and never care that it was run from somewhere else. – Robert Mark Bram Jul 17 '17 at 01:47
  • 3
    I think this answer should also explain why `${BASH_SOURCE[0]}` instead of `${BASH_SOURCE}`. Otherwise it is perfect. – Bruno Bronosky Feb 20 '18 at 21:28
  • 5
    https://www.electrictoolbox.com/bash-script-directory/ adds the useful context of how this kind of approach differs from the basic option of running `dirname $0` (i.e. it ensures the path is absolute with only shell builtin commands, as discussed in https://stackoverflow.com/a/3915420/597742 and other answers to that question). – ncoghlan Mar 09 '18 at 03:44
  • This is useful to import a "lib" script in the same folder. And the "cd ... pwd" part handle the case when you have a link to your script (in which case, the BASH_SOURCE would resolve to the link, not your script). – jehon Sep 29 '22 at 08:25
0

Let's break it down:

DIR="$( cd "$( dirname "${BASH_SOURCE[0]}" )" && pwd )"

  • ${BASH_SOURCE[0]}: will resolve to the script name as it was called from the command line (you need ${} to access the array cleanly)
  • "$( dirname "${BASH_SOURCE[0]}" )": will resolve to the dir part of it
    • dirname "/foo/bar" give "/foo"
    • " (quotes) handle the case when you have space in it (both in filename and in path)
    • $(command) will call the command and return the stdout in a variable

This first part has some limitation. If your script is called through a link, you will receive the dir name of the link, not of the script. That can be fine. But if you want to source another file (let's say a lib), this file is located aside of your real script. To find the real path, you need a bit more:

  • $( cd "$( dirname "${BASH_SOURCE[0]}" )" && pwd ): will resolve to the real path of your script.

How to use it?

DIR="$( cd "$( dirname "${BASH_SOURCE[0]}" )" && pwd )"
. "$DIR"/lib.sh

What not to do?

pwd: This does work only if you always launch your script from it's current folder. This can work for some system script, but usually, you don't do that.

jehon
  • 1,404
  • 15
  • 21