Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How to ignore failure of command called through command builtin?

I have a shell script (running on macOS with GNU bash, version 3.2.57(1)-release) where I set -e at the beginning, but I also want to ignore some of the potential failures, so that they don't end the execution of the script. I'm doing that by appending || ... to the relevant commands:

#!/bin/sh
set -e
false || echo ignore failure

The above works and outputs ignore failure, as expected.

However, if I call the false command through the command builtin, this strategy doesn't work -- the following version of the script exits as soon as false fails, without printing anything:

#!/bin/sh
set -e
command false || echo ignore failure

Why is that? How can I get the desired behavior of ignoring the failure even in the second case?

(In this simplified example, I could of course just delete the command builtin, but in my actual use case, it's part of a function that I don't control.)

like image 486
dlukes Avatar asked Jun 26 '21 15:06

dlukes


1 Answers

Why does command false || echo fail?

Seems like this is a bug in bash versions below 4.0.

I downloaded the old versions 3.2.57 and 4.0, compiled them on Linux, and ran your script. I could reproduce your problem in 3.2.57. In 4.0 everything worked as expected.

Strangely, I couldn't find an according note in bash's lists list of changes, but if you search for set -e you find multiple other bugfixes regarding the behavior of set -ein other versions, for instance:

This document details the changes between this version, bash-4.4-rc1, and the previous version, bash-4.4-beta.
[...]
o. Fixed a bug that caused set -e to be honored in cases of builtins invoking other builtins when it should be ignored.

How to fix the problem?

The best way would be to use more recent version of bash. Even on macOS this shouldn't be a problem. You can compile it yourself or install it from something like brew.

Other than that, you can use workarounds like leaving out command or adding a subshell ( command false; ) || echo ignore failure (courtesy of Nate Eldredge). In either case, things get quite cumbersome. As you don't know when exactly the bug happens you cannot be sure that you correctly worked around it every time.

like image 87
Socowi Avatar answered Oct 16 '22 10:10

Socowi