Skip to main content
10 of 28
added 11 characters in body
mikeserv
  • 59.4k
  • 10
  • 122
  • 242

Ok, so, as I stated in the comments above, I don't know specifically about bash's set -E, but I know that POSIX compatible shells provide a simple means of testing a value if you desire it:

 sh -cevx ' _test() { echo $( ${empty:?error string} ) &&\ echo "echo still works" } _test && echo "_test doesnt fail" ' sh: line 1: empty: error string + echo + echo 'echo still works' echo still works + echo '_test doesnt fail' _test doesnt fail 

Above you'll see that though I used parameter expansion to test ${empty?} _test() still returns a pass - as is evinced in the last echo This occurs because the failed value kills the $( command substitution ) subshell that contains it, but its parent shell - _test at this time - keeps on trucking. And echo doesn't care - it's plenty happy to serve only a \newline; echo is not a test.

But consider this:

 sh -cevx ' _test() { echo $( ${empty:?error string} ) &&\ echo "echo still works" ; } 2<<-INIT ${empty?function doesnt run} INIT _test ||\ echo "this doesnt even print" ' _test+ sh: line 1: empty: function doesnt run 

Because I fed _test()'s input with a pre-evaluated parameter in the INIT here-document now the test() function doesn't even attempt to run at all. What's more the sh shell apparently gives up the ghost entirely and echo "this doesnt even print" doesn't even print.

Probably that is not what you want.

This happens because the ${var?} style parameter-expansion is designed to quit the shell in the event of a missing parameter, it works like this:

${parameter:?[word]}

Indicate Error if Null or Unset. If parameter is unset or null, the expansion of word (or a message indicating it is unset if word is omitted) shall be written to standard error and the shell exits with a non-zero exit status. Otherwise, the value of parameter shall be substituted. An interactive shell need not exit.

I won't copy/paste the entire document, but if you want a failure for a set but null value you use the form:

${var :? error message }

With the :colon as above. If you want a null value to succeed, just omit the colon. You can also negate it and fail only for set values, as I'll show in a moment.

Another run of _test():

 sh -c ' _test() { echo $( ${empty:?error string} ) &&\ echo "echo still works" ; } 2<<-INIT ${empty?function doesnt run} INIT echo "this runs" |\ ( _test ; echo "this doesnt" ) ||\ echo "now it prints" ' this runs sh: line 1: empty: function doesnt run now it prints 

This works with all kinds of quick tests, but above you'll see that _test(), run from the middle of the pipeline fails, and in fact its containing command list subshell fails entirely, as none of the commands within the function run nor the following echo run at all, though it is also shown that it can easily be tested because echo "now it prints" now prints.

And it may not be obvious, but if you wanted to only pass for the opposite case, it's fairly simple as well:

 N= #N is NULL v=something_you_would_rather_do_without ${v+${N:?you just nest it a little}} : && some other things 

And I guess we should show it work, right? We just declare it as a parameter to our function (or any time beforehand):

 sh -c ' _test() { echo $( echo ${empty:?error string} ) &&\ echo "echo still works" ; } 2<<-INIT ${empty?function doesnt run} INIT echo "this runs" >&2 |\ ( empty=not_empty _test ; echo "yay! I print now!" ) ||\ echo "suspiciously quiet" ' this runs not_empty echo still works yay! I print now! 

It should be noted that this evaluation stands alone - it requires no additional test to fail. A couple more examples:

 sh -c ' empty= ${empty?null, no colon, no failure} unset empty echo "${empty?this is stderr} this is not" ' sh: line 3: empty: this is stderr sh -c ' _input_fn() { set -- "$@" #redundant echo ${*?WHERES MY DATA?} #echo is not necessary though shift ${*?WHERES MY DATA?} } _input_fn heres some stuff _input_fn one #here #shell dies - third try doesnt run _input_fn you there? ' heres some stuff sh: line 4: some: command not found one sh: line 4: *: WHERES MY DATA? 
mikeserv
  • 59.4k
  • 10
  • 122
  • 242