739

I am using following options

set -o pipefail
set -e

In bash script to stop execution on error. I have ~100 lines of script executing and I don't want to check return code of every line in the script.

But for one particular command, I want to ignore the error. How can I do that?

Ryan Shillington
  • 23,006
  • 14
  • 93
  • 108
Vivek Goel
  • 22,942
  • 29
  • 114
  • 186

12 Answers12

1200

The solution:

particular_script || true

Example:

$ cat /tmp/1.sh
particular_script()
{
    false
}

set -e

echo one
particular_script || true
echo two
particular_script
echo three

$ bash /tmp/1.sh
one
two

three will be never printed.

Also, I want to add that when pipefail is on, it is enough for shell to think that the entire pipe has non-zero exit code when one of commands in the pipe has non-zero exit code (with pipefail off it must the last one).

$ set -o pipefail
$ false | true ; echo $?
1
$ set +o pipefail
$ false | true ; echo $?
0
R. Oosterholt
  • 7,720
  • 2
  • 53
  • 77
Igor Chubin
  • 61,765
  • 13
  • 122
  • 144
  • 29
    +1. As the Bash Reference Manual [explains](http://www.gnu.org/software/bash/manual/bashref.html#The-Set-Builtin), "The shell does not exit" when the `-e` attribute is set "if the command that fails is part of the command list immediately following a `while` or `until` keyword, part of the test in an `if` statement, part of any command executed in a `&&` or `||` list except the command following the final `&&` or `||`, any command in a pipeline but the last, or if the command's return status is being inverted with `!`." – ruakh Jun 27 '12 at 17:40
  • @IgorChubin I don't know why but this don't work output=`(ldd $2/bin/* || true) | grep "not found" | wc -l` script is terminating after this line when ldd return failure – Vivek Goel Jun 27 '12 at 17:44
  • 3
    `(ldd $2/bin/* || true) | grep "not found" | wc -l || true` – Igor Chubin Jun 27 '12 at 17:45
  • 1
    because of `set -o pipefail`. when `grep` finds nothing, it returns non-zero exit code and it is enough for shell to think that the entire pipe has non-zero exit code. – Igor Chubin Jun 27 '12 at 17:51
  • @VivekGoel: I added explanation to the answer – Igor Chubin Jun 27 '12 at 17:53
  • 6
    If you want the option of preserving the return value (without exiting) you an try mycommand && true. This allows you to check the return code in subsequent steps and handle it programmatically. – Ed Ost Aug 21 '17 at 23:51
  • error catching seems to be easy for the sample case in the lower end: `e=0; || e=$?` – Alexander Stohr May 12 '22 at 13:52
258

Just add || true after the command where you want to ignore the error.

Lars Kotthoff
  • 107,425
  • 16
  • 204
  • 204
  • 19
    I think it's important to add this: this method will allow the response code and error message to persist, whereas the "!" method outlined below will change the response code and thus not generate the error. This is important when using `set -e` and trying to capture an error message: e.g.`set -e; TEST=$(foo 2>&1 || true); echo $TEST` – Spanky Oct 06 '16 at 18:30
  • @Spanky I don't quite understand your example. You `set -e`, redirect the bash command not found from stderr to `$TEST`. How does this preserve the response code? – CervEd Jan 05 '22 at 10:14
  • @Spanky are you trying to do something like this `set -e; TEST=$(foo 2>&1) || printf "ERROR $?: $TEST\n"` – CervEd Jan 05 '22 at 10:30
196

Don't stop and also save exit status

Just in case if you want your script not to stop if a particular command fails and you also want to save error code of failed command:

set -e
EXIT_CODE=0
command || EXIT_CODE=$?
echo $EXIT_CODE
Ciro Santilli OurBigBook.com
  • 347,512
  • 102
  • 1,199
  • 985
Arslan Qadeer
  • 1,969
  • 1
  • 9
  • 5
  • EXIT_CODE is not set to zero when command returns 0. Non zero exit codes are captured though. Any idea why? – Ankita13 Nov 20 '19 at 07:41
  • 2
    @Ankita13 Because if it was zero the first ```command``` was successful and there is need to run what's after ```||```. read it as: if ```command``` fails, do ```EXIT_CODE=$?```. You probably could just do ```command || echo "$?"``` or use "trap" for more verbose debugging. See this -> https://stackoverflow.com/a/6110446/10737630 – tinnick Mar 23 '20 at 08:34
  • 6
    i think this is probably the best answer. it's what i was looking for anyway. i don't want the shell to exit, but i do want to know about the error, so i can respond. thanks a lot! – nathan g Jun 14 '21 at 10:17
  • I have used this technique to force stop a Gitlab CI job manually because the command I was running seemed to hang even if the exit code was 1, so I ended up doing the exit myself. – Patrick.SE Aug 18 '21 at 16:13
  • `set -e` closes the ssh session – alper Dec 31 '22 at 12:24
85

More concisely:

! particular_script

From the POSIX specification regarding set -e (emphasis mine):

When this option is on, if a simple command fails for any of the reasons listed in Consequences of Shell Errors or returns an exit status value >0, and is not part of the compound list following a while, until, or if keyword, and is not a part of an AND or OR list, and is not a pipeline preceded by the ! reserved word, then the shell shall immediately exit.

Lily Finley
  • 2,847
  • 1
  • 16
  • 11
  • 22
    My understanding is that the `!` will prevent the shell from exiting no matter what. [This script](http://pastebin.com/B6aRXGeA) displays the message `Still alive!` when I run it, indicating that the script ran to completion. Are you seeing different behavior? – Lily Finley Jun 24 '15 at 16:59
  • 12
    you are right, it inverts exit status, but doesn't crash script when command ends with both 0 or 1. I was inattentive. Anyway, thank you for quoting the documentation, I put my expression to `if` clause and solved the problem. – Marboni Jun 24 '15 at 18:19
  • This is the best solution IMO because in many situations, I want to ignore the return value of `particular_script`, but if `particular script` is a function I do *not* want to ignore the return values of the statements inside the functions. The `||` solutions will ignore all return codes inside the function body of `particular_script`, which is often not what you want (https://stackoverflow.com/a/37191242/985292). – Johannes Jul 09 '21 at 04:11
  • while `||` does not work in dash, this does. thx! – bernstein Apr 06 '22 at 13:25
  • I find this approach much more readable than `|| true`, it clearly shows the intent (once you know the syntax) and it is also more appropriate since it was designed exactly for this use-case. – Didier L Jul 26 '22 at 13:40
  • 1
    This approach also has the advantage of being able to retrieve the command exit status easily with [PIPESTATUS](https://www.gnu.org/software/bash/manual/bash.html#index-PIPESTATUS): `${PIPESTATUS[0]}`. – pjh Apr 04 '23 at 13:44
  • @pjh Nice one ! – Jon May 31 '23 at 16:56
58

Instead of "returning true", you can also use the "noop" or null utility (as referred in the POSIX specs) : and just "do nothing". You'll save a few letters. :)

#!/usr/bin/env bash
set -e
man nonexistentghing || :
echo "It's ok.."
Timo
  • 3,335
  • 30
  • 25
  • 6
    although ||: is not that clear as || true (which may confuse non expert users), I like it conciseness – David Apr 24 '18 at 09:47
  • This variant doesn't return any text which can be important in CI. – kivagant May 17 '19 at 18:18
  • good, but is there any other way to return null more clearly? – august0490 Apr 05 '21 at 18:11
  • @august0490 `alias null=:` and you can use `null` in place of `:`, if you find it clearer. – Timo Apr 15 '21 at 18:31
  • 1
    ...though, while I do understand the idea that using e.g. `null` in place of `:` can seem more familiar/natural to devs familiar with other languages, I doesn't feel right with shell scripts. Shell scripts don't really return anything (except error number codes or 0 for success) and neither do we here and there is no such type as `null`. Adding aliases like that could lead future devs astray as they might be tempted to think they can do something like `alias null=:; if [[ null != $nonexistentghing ]]; then echo "It's set! (not really)"; fi`, but that's just not how shell works at all. – Timo Nov 15 '22 at 12:18
20

I found another way to solve this:

set +e
find "./csharp/Platform.$REPOSITORY_NAME/obj" -type f -iname "*.cs" -delete
find "./csharp/Platform.$REPOSITORY_NAME.Tests/obj" -type f -iname "*.cs" -delete
set -e

You can turn off failing on errors by set +e this will now ignore all errors after that line. Once you are done, and you want the script to fail again on any error, you can use set -e.

After applying set +e the find does not fail the whole script anymore, when files are not found. At the same time, error messages from find are still printed, but the whole script continues to execute. So it is easy to debug if that causes the problem.

This is useful for CI & CD (for example in GitHub Actions).

Konard
  • 2,298
  • 28
  • 21
  • 1
    This is what worked for me in github actions – paltaa Jul 18 '22 at 15:17
  • I find it hard to believe that the other solutions here didn't work. Perhaps you are not using a Bourne-compatible shell then? – tripleee Aug 03 '22 at 15:28
  • @tripleee it is true, that my statement can be confusing, so I have updated it. To be honest, I don’t remember anymore why other solutions did’t work for me, or did I try all of them at all. – Konard Sep 27 '22 at 16:29
16

Thanks for the simple solution here from above:

<particular_script/command> || true

The following construction could be used for additional actions/troubleshooting of script steps and additional flow control options:

if <particular_script/command>
then
   echo "<particular_script/command> is fine!"
else
   echo "<particular_script/command> failed!"
   #exit 1
fi

We can brake the further actions and exit 1 if required.

Almaz Gareev
  • 181
  • 1
  • 4
13

If you want to prevent your script failing and collect the return code:

command () {
    return 1  # or 0 for success
}

set -e

command && returncode=$? || returncode=$?
echo $returncode

returncode is collected no matter whether command succeeds or fails.

volingas
  • 1,023
  • 9
  • 21
5
output=$(*command* 2>&1) && exit_status=$? || exit_status=$?
echo $output
echo $exit_status

Example of using this to create a log file

log_event(){
timestamp=$(date '+%D %T') #mm/dd/yy HH:MM:SS
echo -e "($timestamp) $event" >> "$log_file"
}

output=$(*command* 2>&1) && exit_status=$? || exit_status=$?

if [ "$exit_status" = 0 ]
    then
        event="$output"
        log_event
    else
        event="ERROR $output"
        log_event
fi
Robert.C
  • 51
  • 1
  • 1
2

I have been using the snippet below when working with CLI tools and I want to know if some resource exist or not, but I don't care about the output.

if [ -z "$(cat no_exist 2>&1 >/dev/null)" ]; then
    echo "none exist actually exist!"
fi
Payman
  • 2,630
  • 1
  • 12
  • 18
1

while || true is preferred one, but you can also do

var=$(echo $(exit 1)) # it shouldn't fail
Foto Blysk
  • 344
  • 2
  • 11
0

I kind of like this solution :

: `particular_script`

The command/script between the back ticks is executed and its output is fed to the command ":" (which is the equivalent of "true")

$ false
$ echo $?
1
$ : `false`
$ echo $?
0

edit: Fixed ugly typo

Q-life
  • 74
  • 6
  • This is basically equivalent to the earlier answer by @FotoBlysk except this one uses obsolescent command substitution syntax. – tripleee Aug 03 '22 at 15:32