How can I set the current working directory to the directory of the script in Bash?
bash, path, scripting
Solution
TL;DR
#!/bin/bash
cd "$(dirname "$0")"
The long winded explanation
How does this work and how does it deal with edge and corner cases?
You type a command launching the script in your interactive shell. That interactive shell calls `bash` with some name which tells `bash` the script to run. That `bash` then calls `dirname` with the bash argument which points to the script. Finally, that `bash` then calls `cd` with the output of `dirname` as its argument.
script invocation command `bash` argument `dirname` argument `cd` argument
`foo` (found in `$PATH` at `/path/to/foo`) `/path/to/foo` `/path/to/foo` `/path/to`
`bash foo` `foo` `foo` `.`
`/foo` `/foo` `/foo` `/`
`./foo` `./foo` `./foo` `.`
`"/pa th/to/foo"` `/pa th/to/foo` `/pa th/to/foo` `/pa th/to`
`"./pa th/to/foo"` `./pa th/to/foo` `./pa th/to/foo` `./pa th/to`
`"../pa th/to/foo"` `../pa th/to/foo` `../pa th/to/foo` `../pa th/to`
`"../../pa th/to/foo"` `../../pa th/to/foo` `../../pa th/to/foo` `../../pa th/to`
`"pa th/to/foo"` `pa th/to/foo` `pa th/to/foo` `pa th/to`
`--help/foo` `--help/foo` * N/A N/A
`--help` N/A ** N/A N/A
On symlinks
The `cd` command will follow symlinks if they are involved. A symlink usually exists to be followed, so in most situations following the symlink is the correct thing to do. Why would it be a problem for the code in the script to follow a symlink when it was just fine to follow that same symlink a few microseconds ago when loading the script?
On command arguments starting with hyphens
* There is only one case where the argument to the `dirname` could begin with a `-`, and that is the relative path case `--help/foo`. If the script is in a subdirectory called `--help`, the script execution will run `bash --help/foo`, and bash does not know that option `--help/foo` and will therefore abort with an error message. The script will never execute, so it does not matter what the `cd "$(dirname "$0")"` would have executed.
** Note that calling the script `--help` makes the shell not find the command when you are typing `--help` in the same directory. Alternatively, with `$PATH` containing the current directory, the script will be run as `/path/to/--help` or `./--help`, always with something in front of the `-` character.
Unless bash introduces command line arguments with a parameter separated by a `=`, it is unlikely that you could pass a `-` argument to bash which contains a `/` later, and which is accepted by bash.
If you can rely on `dirname` accepting `--` argument (bash builtin `cd` will certainly accept `--`), you can change the script snippet to
cd -- "$(dirname -- "$0")"
Please do comment if you can figure out a way to construct an argument beginning with `-` which can be sneaked past bash.
Nota bene
The above snippet also works with non-bash `/bin/sh`.
Problem
I'm writing a Bash script. I need the current working directory to always be the directory that the script is located in. The default behavior is that the current working directory in the script is that of the shell from which I run it, but I do not want this behavior.
Related problems
- Bash script absolute path with OS X
- How do I get the directory where a Bash script is located from within the script itself?
- What is the meaning of ${0%/*} in a bash script?
- How can I get the behavior of GNU's readlink -f on a Mac?
- Reliable way for a Bash script to get the full path to itself
- How to detect the current directory in which I run my shell script?
- Get the name of the directory where a script is executed