19

I have a bash script that I want to globally enable set -e.

But rather than disable it and reenable it all the time, I'm wondering if there is a way of selectively disabling error handling just sometimes. For example, commands run from systemd can be preceeded by a minus to ignore errors. Does bash has an equivalent?

e.g.

#!/bin/bash

set -e

WAN_IF=eth2

# Ignore error on next line
tc qdisc del dev ${WAN_IF} root

# I want errors to stop the script on this line
tc qdisc add dev ${WAN_IF} root handle 1: htb default 10

...
etc

Because of the need to enable/disable a lot I don't want to have to keep doing the following:

set +e
tc qdisc del dev ${WAN_IF} root

# I want errors to stop the script on this line
set -e
tc qdisc add dev ${WAN_IF} root handle 1: htb default 10
...
hookenz
  • 36,432
  • 45
  • 177
  • 286
  • 1
    Instead of explicit `set -e`, I would recommend this: `old_set=$-; set +e; ; set -$old_set`. Just in case `set -e` is not already set, you don't want to set it unnecessarily. functions are re-usable. So they may be called in a case when `set -e` is not set. This precaution may not be required in a script, but in interactive shells, it may be relevant. – anishsane Apr 20 '15 at 03:58
  • Thanks @EtanReisner - would you like to put that into an answer so others can see it. It works perfectly. – hookenz Apr 20 '15 at 04:09
  • 4
    The problem with `set -e` isn't that you have to be careful about which commands you want to allow to fail. The problem is that it doesn't compose. If someone else reads this post and uses `source yourfile || :` to source this script while allowing failure, suddenly `yourfile` will no longer stop on errors *anywhere*. Not even on failing lines after an explicit `set -e`. – that other guy Apr 20 '15 at 04:17
  • This thread on [superuser: How to disable set -e for an individual command?](https://superuser.com/a/1458830/317140) has better answers. – sebix Feb 22 '22 at 09:01

2 Answers2

13

Add || : (or anything else that is guaranteed not to fail but that's the simplest) to the end of the command.

Though many people would simply tell you that set -e isn't worth it because it isn't as useful as you might think (and causes issues like this) and manual error checking is a better policy.

(I'm not in that camp yet though the more I run into issues like this the more I think I might get there one day.)

From thatotherguy's comment explaining one of major the issues with set -e:

The problem with set -e isn't that you have to be careful about which commands you want to allow to fail. The problem is that it doesn't compose. If someone else reads this post and uses source yourfile || : to source this script while allowing failure, suddenly yourfile will no longer stop on errors anywhere. Not even on failing lines after an explicit set -e.

Etan Reisner
  • 77,877
  • 8
  • 106
  • 148
  • Seeing as no one will be using my script for anything other than its intended purpose I'm fine with the limitations. Thank you. – hookenz Apr 20 '15 at 19:30
2

||: is ambiguous about what it's doing. Future code readers or future you might be confused. How about an explicit echo:

some_command_allowed_to_fail || (echo "this echo is just to \
    disable the error status" > /dev/null)

(Edit: add >/dev/null to avoid unnecessary showing the message to the user)

Penghe Geng
  • 13,286
  • 5
  • 31
  • 40