One common way is:
die() {
IFS=' ' # make sure "$*" is joined with spaces
# output the arguments if any on stderr:
[ "$#" -eq 0 ] || printf '%s\n' "$*" 1>&2
exit 1
}
then you use it like this:
mkdir -p some/path || die "mkdir failed with status $?"
Or if you want it to include the exit status, you could change it to:
die() {
last_exit_status=$?
IFS=' '
printf '%s\n' "FATAL ERROR: $* (status $last_exit_status)" 1>&2
exit 1
}
and then using it is a bit easier:
mkdir -p some/path || die "mkdir failed"
When it fails, mkdir
will likely already have issued an error message, so that second one may be seen as redundant, and you could just do:
mkdir -p some/path || exit # with the same (failing) exit status as mkdir's
mkdir -p some/path || exit 1 # with exit status 1 always
(or use the first variant of die
above without argument)
Just in case you haven't seen command1 || command2
before, it runs command1
, and if command1
fails, it runs command2
.
So you can read it like "make the directory or die".
Your example would look like:
mkdir -p some/path || die "mkdir failed"
cd some/path || die "cd failed"
some_command || die "some_command failed"
Or you can align the dies
further on the right so that the main code is more obvious.
mkdir -p some/path || die "mkdir failed"
cd some/path || die "cd failed"
some_command || die "some_command failed"
Or on the following line when the command lines are long:
mkdir -p some/path ||
die "mkdir failed"
cd some/path ||
die "cd failed"
some_command ||
die "some_command failed"
Also, if you are going to use the name some/path
multiple times, store it in a variable so you don't have to keep typing it, and can easily change it if you need to. And when passing variable arguments to commands, make sure to use the --
option delimiter so that the argument is not taken as an option if it starts with -
.
dir=some/path
mkdir -p -- "$dir" || die "Cannot make $dir"
cd -P -- "$dir" || die "Cannot cd to $dir"
some_command || die "Cannot run some_command"
Running sudo
is a bad idea because you don't know what will happen and if it's really necessary:
Will a password prompt be shown? If so, who is going to type a password? Remember: your script may be run in a shell by a human, but could also be run in background, at startup, by cron or in other situations where a terminal is not available.
Will the user type her password if she sees the prompt? Personally, I would immediately stop scripts asking me for a password. Also, I may not even notice the prompt if your script produces a lot of output.
Is sudo
available and configured? Can the current user run sudo
? The answer to one of these question may be 'no', in which case you should let the user choose how to give your script the necessary privileges.
Are you sure you need to be superuser? Maybe I configured my system so that your script does not need root privileges at all, in which case sudo
is totally unnecessary and can be very disturbing.
Please let me decide what privileges you need and how to give them to you.
Running sudo
may be a good idea if you're root and you want to drop your privileges. For example, you may open a file that is owned by root and then immediately switch to nobody:nogroup
for security reasons. Still, the problem that sudo
may not be available or may not be configured remains.
Best Answer
Just set a variable to anything but not-null for the above to work, though
[ -n "$var" ]
would be shorter, if not as obvious.In general when a script interprets an environment variable to be either true or false, it will interpret any value at all to be true (and sometimes use said value to configure some option) or else a null value as false.
The above returns the boolean
!not
value of its first argument's len - if the argument contains any number of characters other than 0 it returns 0, else, if no characters at all, it returns 1. This is the same test you can perform with[ -n "$var" ]
, basically, but it just wraps it in a little function namedbool()
.This is typically how a flag variable works. For example:
Where other parts of a script need only look for any value at all in
$dir
to gauge its usefulness. This also comes in handy where parameter substitution is concerned - as parameters can be expanded to default values to fill in for empty or unset ones, but will otherwise expand to a preset value like......which would print...
Of course, it is also possible to do the opposite with
:+
but that can only ever give you a preset default or nothing at all, whereas the above form can give you a value or a default value.And so regarding the three choices - any one could work depending on how you choose to implement it. The function's return is self-testing, but, if that return needs saving for any reason, will need to be put in a variable. It depends on the use case - is the boolean value you wish to evaluate a test once and done type? If so, do the function, else either of the other two is probably necessary.