Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Execute a line in Bash without aborting if it fails?

Tags:

bash

Is there a generic way in a bash script to "try" something but continue if it fails? The analogue in other languages would be wrapping it in a try/catch and ignoring the exception.

Specifically I am trying to source an optional satellite script file:

. $OPTIONAL_PATH

But when executing this, if $OPTIONAL_PATH doesn't exist, the whole script screeches to a halt.

I realize I could check to see if the file exists before sourcing it, but I'm curious if there is a generic reusable mechanism I can use that will ignore the error without halting.

Update: Apparently this is not normal behavior. I'm not sure why this is happening. I'm not explicitly calling set -e anywhere ($- is hB), yet it halts on the error. Here is the output I see:

./script.sh: line 36: projects/mobile.sh: No such file or directory

I added an echo "test" immediately after the source line, but it never prints, so it's not anything after that line that is exiting. I am running Mac OS 10.9.

Update 2: Nevermind, it was indeed shebanged as #!/bin/sh instead of #!/bin/bash. Thanks for the informative answer, Kaz.

like image 445
devios1 Avatar asked Jan 12 '23 21:01

devios1


1 Answers

Failed commands do not abort the script unless you explicitly configure that mode with set -e.

With regard to Bash's dot command, things are tricky. If we invoke bash as /bin/sh then it bails the script if the . command does not find the file. If we invoke bash as /bin/bash then it doesn't fail!

$ cat source.sh 
#!/bin/sh

. nonexistent
echo here
$ ./source.sh 
./source.sh: 3: .: nonexistent: not found
$ ed source.sh 
35
1s/sh/bash/
wq
37
$ ./source.sh 
./source.sh: line 3: nonexistent: No such file or directory
here

It does respond to set -e; if we have #!/bin/bash, and use set -e, then the echo is not reached. So one solution is to invoke bash this way.

If you want to keep the script maximally portable, it looks like you have to do the test.

The behavior of the dot command aborting the script is required by POSIX. Search for the "dot" keyword here. Quote:

If no readable file is found, a non-interactive shell shall abort; an interactive shell shall write a diagnostic message to standard error, but this condition shall not be considered a syntax error.

Arguably, this is the right thing to do, because dot is used for including pieces of the script. How can the script continue when a whole chunk of it has not been found?

Otherwise arguably, this is braindamaged behavior inconsistent with the treatment of other commands, and so Bash makes it consistent in its non-POSIX-conforming mode. If programmers want a command to fail, they can use set -e.

I tend to agree with Bash. The POSIX behavior is actually more broken than initially meets the eye, because this also doesn't work the way you want:

if . nonexistent ; then
  echo loaded
fi

Even if the command is tested, it still aborts the script when it bails.

Thank GNU-deness we have alternative utilities, with source code.

like image 64
Kaz Avatar answered Jan 21 '23 10:01

Kaz