73

This Bash snippet works as expected:

$ fun1() { x=$(false); echo "exit code: $?"; }
$ fun1
exit code: 1

But this one, using local, does not as I would have expected:

$ fun2() { local x=$(false); echo "exit code: $?"; }
$ fun2
exit code: 0

Can anyone explain why does local sweep the return code of the command?

tokland
  • 66,169
  • 13
  • 144
  • 170

2 Answers2

84

The reason the code with local returns 0 is because $? "Expands to the exit status of the most recently executed foreground pipeline." Thus $? is returning the success of local

You can fix this behavior by separating the declaration of x from the initialization of x like so:

$ fun() { local x; x=$(false); echo "exit code: $?"; }; fun
exit code: 1
SiegeX
  • 135,741
  • 24
  • 144
  • 154
  • 8
    For the record, the problem is discussed in the BashPitfalls wiki: http://mywiki.wooledge.org/BashPitfalls#local_varname.3D.24.28command.29 – tokland Apr 10 '11 at 14:01
  • 2
    also covered by google-styleguide for bash: https://google.github.io/styleguide/shell.xml?showone=Use_Local_Variables#Use_Local_Variables – Trevor Boyd Smith Nov 15 '18 at 15:29
6

The return code of the local command obscures the return code of false

Ignacio Vazquez-Abrams
  • 776,304
  • 153
  • 1,341
  • 1,358
  • 1
    Yeah, I understand it, but local being a special keyword I would expect not to obscure it. I guess it was a false assumption. – tokland Dec 12 '10 at 10:57
  • 4
    It's not a "special keyword", it's a shell builtin. Even builtins have return values. – Ignacio Vazquez-Abrams Dec 12 '10 at 10:58
  • 3
    [Shellcheck](https://github.com/koalaman/shellcheck) can detect this problem ([SC2155](https://github.com/koalaman/shellcheck/wiki/SC2155)). – pjh Feb 26 '16 at 20:50