When in doubt, always consider adding set -e and cd $(dirname $0) at the beginning of a shellscript. Why? Let’s find out:

When to use cd $(dirname $0)

$0 is the currently executing script, so what the command does is to change current directory into the same directory as where the script resides.

If you don’t do this, any references to other files next to your script will be incorrect if you run the script from another directory.

What’s worse you might end up writing files in unintended places.

That said, independent utility scripts that interact with stuff in the current directory regardless of where that is, are very common too. So the advice to use cd $(dirname $0) mainly applies if you’re adding a script to a larger thing with its own directory struture etc.

When to use set -e

test.sh

#!/bin/bash

ls does-not-exist.txt

echo "Do something with the file"

execution log:

% ./test.sh
ls: does-not-exist.txt: No such file or directory
do something with the file
%

This could end badly depending on what “do something” really does.

What if it intends to read the file and then produces something useful. Without -e it tries to do its thing despite a prior step going wrong.

If nothing else, a script that outputs handfuls of failures is not user friendly at all.

A more robust approach is to fail the script if any of its parts fail, and this is what set -e accomplishes:

test.sh

#!/bin/bash

set -e

ls does-not-exist.txt

echo "Do something with the file"

execution log:

% ./test.sh
ls: does-not-exist.txt: No such file or directory
do something with the file
%

That’s way more managable!

Also, if you decide to use both set -e and cd $(dirname $0), be sure to do set -e first so that the script fails if changing dirs fail. The mess that would occur otherwise if dir change failed but you kept going, is a perfect example of the benefit of set -e, actually.

Bonus tip, set -ex:

set -ex can be a super useful debug tool while writing a script. x verbosely outputs all the subcommands used by the script, which makes it easier to verify that the script works as expected. The visual overload quickly gets out of hand though, so consider removing x when done debugging. Make sure to keep e around though!

test.sh

#!/bin/bash

set -ex

echo "script name is: $0"

echo "dirname of script name before is: $(dirname $0)"

cd $(dirname $0)

echo "dirname of script name after is: $(dirname $0)"

echo "PWD is now: $PWD"

ls does-not-exist.txt

execution log:

% ./test/test.sh
++ dirname ./test/test.sh
+ cd ./test
+ echo 'script name is: ./test/test.sh'
script name is: ./test/test.sh
++ dirname ./test/test.sh
+ echo 'dirname of script name is: ./test'
dirname of script name is: ./test
+ echo 'PWD is: /home/purefun/projects/test'
PWD is: /home/purefun/projects/test
+ ls does-not-exist.txt
ls: does-not-exist.txt: No such file or directory
%

Messy indeed. But if you’re in the mode of sanity-checking what the script does at every step, then you might find what you’re looking for.




sponsor

Need private photo sharing that's not tied up in the social media circus? Photoroll is a good way to share photos with your clients.
Or privately gather media from participants of weddings and other small to medium-sized events.