Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

No-op shell command that preserves $?

Using only the features of the POSIX shell, is there a "simple command" that does nothing and does not change the value of $? People usually describe : as a no-op command for shell, but this always sets $? to zero, so it's not what I want.

This is needed by a program that generates shell scripts. In several places it needs to emit an if-then-else block

if CONDITION
then
    TRUE-COMMANDS
else
    FALSE-COMMANDS
fi

but, because of further complications that I'd rather not try to explain right now, it cannot reliably tell whether TRUE-COMMANDS and FALSE-COMMANDS are empty. An empty then- or else-clause will be a shell syntax error.

: can be put at the beginning of the then-clause to take care of TRUE-COMMANDS being empty, but that won't work for FALSE-COMMANDS because it clobbers $? and the FALSE-COMMANDS might want to look at the value $? was set to by the condition. For the same reason, : can't be put after FALSE-COMMANDS—the code after the if-then-else might want to see $? from the last operation within the if-then-else.

Bonus points if you can avoid:

  • Forking: (exit $?) does the job, but there are so many of these conditional blocks in a generated script that it produces a measurable slowdown.

  • Functions: given nop () { return $? } then nop does the job, but due to more complications that I'd rather not get into, it's not practical to have nop defined sufficiently early for all of the places that would need it.

like image 633
zwol Avatar asked Nov 11 '20 15:11

zwol


1 Answers

The easiest would be to make use of a simple assignment. Instead of using :, do _rc=$?.

if condition; then
   [ list-true ]     # optional 
   _rc=$?
else
   [ list-false ]    # optional
   _rc=$?
fi
( exit $_rc )        # optional
list-post-if

Using this variable _rc, you have stored the exit status of the last executed command, whether this is condition or the last command in list-true or list-false.

  • The arguments in favour of this method is the low overhead of an assignment.
  • The argument against is the need to at least rewrite list-post-if to make use of _rc instead of $?.
  • If the latter is not possible, or too tedious, you might concider to add a (exit $_rc) just after the conditional statement. This, however, requires a sub-shell, but it is only one.
like image 51
kvantour Avatar answered Sep 28 '22 06:09

kvantour