29
#!/bin/bash
function0()
{
 local t1=$(exit 1)
 echo $t1
}

function0

echo prints empty value. I expected:

1

Why doesn't t1 variable get assigned the exit command's return value - 1?

45

local t1=$(exit 1) tells the shell to:

  • run exit 1 in a subshell;
  • store its output (as in, the text it outputs to standard output) in a variable t1, local to the function.

It's thus normal that t1 ends up being empty.

($() is known as command substitution.)

The exit code is always assigned to $?, so you can do

function0()
{
  (exit 1)
  echo "$?"
}

to get the effect you're looking for. You can of course assign $? to another variable:

function0()
{
  (exit 1)
  local t1=$?
  echo "$t1"
}
  • You know, you can always put the return into the pipe, too. `$(trap 'printf "::ERRNO:$?"' 0; # now do whatever however - that trap will ensure the last string written is the last return for the whole substitution context. – mikeserv Jun 7 '15 at 16:28
  • @mikeserv did you miss a backtick? $(trap 'printf "::ERRNO:$?"' 0; # now do whatever however – Doktor J Jun 4 '18 at 18:27
9

Exit code was stored in $? variable. Using Command Substitution only capture the output, you should use (...) to create subshell:

#!/bin/bash

func() {
  (exit 1)
  local t1=$?
  printf '%d\n' "$t1"
}

func
  • the point of the assignment t1=$? is to use it, no? and wouldn't $? get clobbered by the assignment op? I guess I'm asking if it shouldn't be printf '%d\n' "${t1}" – Dani_l Jun 7 '15 at 15:09
  • @Dani_l: Thanks, that's a mis-typo. Updated. – cuonglm Jun 7 '15 at 15:11
  • Note that Command Substitution only captures standard out unless redirected differently. – phyatt Mar 17 '17 at 14:28
7

In bash this works:

loc(){  local   "x=$(exit "$1"):$?"
        printf  '$%s:\t%d\n' \
                 x "${x##*:}" \? "$?"
}

It has to do with the order of command evaluation and variable assignment. local has a return value all its own - and it is the currently executing command, not the command substitution. The reason things like...

x=$(exit 1); echo "$?"

...can return 1 is because there never is a return in that command except for the subshell run to assign $x's value - so $? doesn't get clobbered as it does in practically every other case in which command substitutions are used.

Anyway, with local it does get clobbered - but if you catch it at just the right time - which is while the expansions are still being evaluated and before local's routines have a chance to clobber it - you can still assign it.

unset x; loc 130; echo "${x-\$x is unset}"

...prints...

$x: 130
$?: 0
$x is unset

You should know though that in many shells you cannot rely upon $? being set mid-evaluation in that way. In fact, that's probably because those shells do not bother re-evaluating at every possible juncture as perhaps bash does - which I would argue is probably better behavior than bash's. Do you really want your interpreter recursively loop-evaluating values which are very likely to be overwritten before ever you have the chance to use them?

Anyway, that's how you can do that.

-1

Depending why you are trying to just get the exit code you can also just run if some-command; then echo "Success $?"; else echo "Failure $?"; fi which doesn't do anything with the output of the command, it just evaluates the exit code of the command run. You can add or(or$(around the command and you'll still get the same results. A better example might beif grep -q 'somestring' somefile; then echo "Found somestring exit code is $?"; else "Did not find somestring exit code is $?"; fi`.

You can also test the return code of a function which can be either an explicit return 3 or an implied return code which is the result of the last command, in this case you need to be careful that you don't have an echo at the end of the function, otherwise it masks/resets the previous exit code.

command_last () {
  echo "True is `true`"
  echo "False is `false`"
  false
}
command_last; echo $?
# Outputs:
# True is 0
# False is 1
# 1

echo_last () {
  echo "True is `true`"
  echo "False is `false`"
  false
  # echo'ing literally anything (or nothing) returns true aka exit 0
  echo
}
echo_last; echo $?
# Outputs:
# True is 0
# False is 1
#            # Blank line due to empty echo
# 0

Finally a dirty trick since you can't do VAR=(SOME_COMMAND) because VAR=() is an array definition so you need to VAR=( $(echo 'Some value') ).

  • All the claimed outputs are wrong, due to the fact that command substitution doesn't give the exit code, which is the whole point of the question. It's not clear what the "dirty trick" has to do with anything. – kundor Nov 15 '18 at 2:49

Your Answer

By clicking "Post Your Answer", you acknowledge that you have read our updated terms of service, privacy policy and cookie policy, and that your continued use of the website is subject to these policies.

Not the answer you're looking for? Browse other questions tagged or ask your own question.