110

I am currently exploring Debian packages, and I have been reading some code samples. And on every line in, for example, the postinst script is a pattern.

some command || true
another command || true

So if some command fails, then the line returns true but I don't see how this affects the output of the program.

carpenter
  • 1,221
  • 7
    FYI, ||: is another idiomatic way of writing this (: being another entry in the builtin table pointing to true -- but guaranteed to be a builtin even back to Bourne; that said, for POSIX sh, true is likewise guaranteed to be a builtin -- so it's more terseness than efficiency in even-remotely-modern times). – Charles Duffy Nov 26 '16 at 06:09
  • 1
    Read more about ||: in https://unix.stackexchange.com/questions/78408/which-is-more-idiomatic-in-a-bash-script-true-or – Michael Freidgeim Jun 06 '21 at 00:20

2 Answers2

189

The reason for this pattern is that maintainer scripts in Debian packages tend to start with set -e, which causes the shell to exit as soon as any command (strictly speaking, pipeline, list or compound command) exits with a non-zero status. This ensures that errors don't accumulate: as soon as something goes wrong, the script aborts.

In cases where a command in the script is allowed to fail, adding || true ensures that the resulting compound command always exits with status zero, so the script doesn't abort. For example, removing a directory shouldn't be a fatal error (preventing a package from being removed); so we'd use

rmdir ... || true

since rmdir doesn't have an option to tell it to ignore errors.

Stephen Kitt
  • 434,908
  • ah - not knowing debian I did not know of this 'debian installer' convention (-e). Your answer improves on context! And may help me understand why things finish with no error status - while things actually were not error free (and effect stability and/or conflicts with what is documented as 'expected results' when I play 'sandbox' with Debian on Power. – Michael Felt Nov 24 '16 at 12:21
  • 5
    Well, without set -e there's no need for || true at all, I thought it important to provide the context. If you notice odd things on POWER, I strongly encourage you to file bugs (reportbug)! – Stephen Kitt Nov 24 '16 at 12:34
  • 21
    @MichaelFelt, actually set -e is not only "Debian convention", but a good programming pattern one should always use. See. e.g. http://www.davidpashley.com/articles/writing-robust-shell-scripts/ – Kijewski Nov 24 '16 at 13:57
  • 2
    per the question here - why use || true set -e is the likely context and likely the most common. I bow to this answer! Literally though, it is useful anytime exit status is deemed irrelevant AND (as you article link adds) I am not using exit status as part of my script control. I see utility (in set -e) but would not go so far as the article does and say "Every script you write should include set -e at the top". It is a style of programming. "ALWAYS | Every" includes it own set of traps - aka - absolutes re: wild-card solutions will ALWAYS backfire eventually aka - no free rides. – Michael Felt Nov 24 '16 at 14:58
  • 1
    @Kay That's a currently popular perspective but is ultimately mired with numerous assumptions which limit the script's portability. There are historical inconsistencies with set -e behavior. It might not matter to you, if your only targets are bash and the other relatively recent shells that live at /bin/sh, but the situation is more nuanced when you want to support old shells/systems. – mtraceur Nov 25 '16 at 19:58
  • @mtraceur That's very interesting, do you have any pointers to more detailed info on the inconsistencies? I found useful analyses in the BashFAQ and FVue, but that's Bash-specific — which I guess reinforces your point actually. (And I'm glad I only referred to the practice in the context of Debian!) – Stephen Kitt Nov 26 '16 at 09:30
  • 2
    @StephenKitt Sure thing. There is a very thorough page documenting different shells' set -e behaviors by Sven Mascheck, though this page also documents a lot of historical/ancient shells irrelevant today. There's also these two pages with a narrower modern focus (search for "set -e"): "lintsh" page, autoconf's portable shell documentation -> Limitation of Builtins subpage – mtraceur Nov 26 '16 at 22:50
  • @Kay I never use set -e due to inconsistencies among shells (ksh88, ksh93, bash) and postmortem debugging difficulties caused by the lack of any error message whatsoever in some situations. – jrw32982 Nov 30 '16 at 19:56
  • @Stephen Kitt - wouldn't it be more straightforward to omit set -e at the beginning, and use command || exit instead ? – Martin Vegter Dec 23 '16 at 10:05
  • 1
    @400theCat I don't think so. The idea here is that by default (with set -e), non-zero exit codes cause the script to stop (remember, we're in the context of package maintainer scripts, so it's important to stop early when errors are detected). Then if you add a command without thinking too much about it, you're "protected"; you can special-case commands whose exit code is ignored using || true, and that jumps out at you when you read the script. With your approach, we'd end up with || exit everywhere. (The OP was exaggerating, you don't see || true everywhere in these scripts.) – Stephen Kitt Dec 23 '16 at 10:21
36

While it does not affect the output of the program just run - it permits the caller to proceed as if all is okay aka affects future logic.

Rephrased: it masks the error status of the previous command.

michael@x071:[/usr/sbin]cat /tmp/false.sh
#!/bin/sh
false

michael@x071:[/usr/sbin]cat /tmp/true.sh 
#!/bin/sh
false || true

michael@x071:[/usr/sbin]sh /tmp/false.sh; echo $?
1
michael@x071:[/usr/sbin]sh /tmp/true.sh; echo $? 
0
muru
  • 72,889
Michael Felt
  • 1,218
  • 7
    That's true, but it doesn't answer why masking a command's exit status is useful. – moopet Nov 24 '16 at 15:47
  • 5
    set -e means that the script will instantly terminate upon a non-zero return. You might, in that localized spot, not want that happening! – rackandboneman Nov 24 '16 at 16:33
  • I am a simple person - and for me the only reason to mask the error status is because it is "in the way". set -e makes any error "in the way" if before you did not care. I like the discussion because I see it as a nice way to help me debug my scripts and write additional logic to respond to an error (e.g., || print -- "xxx existed non-zero here". More likely though I have a shell function 'fatal' and I have "something || fatal "unhappy me". imho a script should report a failed status, or not care. -e plus || true is masking errors. If that is what I want - fine, if not, I am missing errors – Michael Felt Nov 24 '16 at 16:48
  • what I have to ask myself is: is || true - a coding crutch (lazy way to get around/past an error I do not want to deal with now; a debug tool (-e but no || true) or just someone's dogma about what good coding practice is. In other words - I see it as a feature - with potential benefit. I do not see it as a magic wand to cure all. In short - just as beauty is in the eye of the beholder - set -e and || true utility will be defined by the traits and goals of the programmer. – Michael Felt Nov 24 '16 at 16:53
  • 6
    @MichaelFelt Consider: git remote remove foo || true git remote add foo http://blah - we want to ignore the error if the remote doesn't exist. – user253751 Nov 25 '16 at 02:04