local t1=$(exit 1)
 echo $t1


echo prints empty value. I expected:


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

up vote 42 down vote accepted

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

  (exit 1)
  echo "$?"

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

  (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 at 18:27

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


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

  • 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

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}"


$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.

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.