Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How to use detect failure in command substitution

Tags:

bash

As you know set -e is very useful to discover any failure when command is executed. However I found it to be delicate to use and I don't know how to use it in the following scenarios:

==============First example================================

set -e
function main() {    
  local X1="$(exp::notdefined)"    
  echo "Will reach here : ${LINENO}"    
  X2="$(exp::notdefined)"    
  echo "Will not reach here : ${LINENO}"
}
main 

==============Second example================================

set -e    
function exp::tmp() {    
  echo "Now '$-' is "$-" : ${LINENO}"    
  false    
  return 0
}    
function main() {    
  X1="$(exp::tmp)"    
  echo "Will reach here : ${LINENO}. '\$X1' : ${X1}"    
  X2="$(set -e ; exp::tmp)"    
  echo "Will not reach here : ${LINENO}"
}    
main

===============================

The first example shows that, if we use command substitution on a local variable, then it will not fail even if the command substituted is not found. I don't know how to detect these kinds of failures.

The second example shows that, if the bash options (-e) will not propagate unless we call set -e inside the command braces. Is there any better way to do this?

like image 636
Nan Hua Avatar asked Mar 14 '23 13:03

Nan Hua


2 Answers

You request immediate exit on pipeline failure with -e, e.g.:

-e      Exit immediately if a pipeline (which may consistof a single simple
        command), a list, or a compound command (see SHELL GRAMMAR above), 
        exits with a non-zero status.

The reason the bad command substitution does not cause failure within the function is because local provides its own return status.

local [option] [name[=value] ...]
... The return status is 0 unless local is used outside a function, an invalid name is supplied, or name is a readonly variable.

The assignment of a failed command substitution does not cause local to return non-zero. Therefore, no immediate-exit is triggered.

As far as checking for a failure of command substitution following local, since the output is assigned to the variable, and the return will not be non-zero in the event of command substitution failure, you would have to validate by checking the variable contents itself for expected values for success/failure.

like image 76
David C. Rankin Avatar answered Mar 19 '23 18:03

David C. Rankin


From the bash manual:

   Subshells spawned to execute command substitutions inherit the value of
   the -e option from the parent shell. When not in posix mode, bash
   clears the -e option in such subshells.

Example 2 behaves differently when bash runs with --posix; however for example 1 I can't find any documentation explaining why local would cause this.

like image 20
PhilR Avatar answered Mar 19 '23 17:03

PhilR