1

I have tried looking for a questions similar to this that cover a solution for me, but none that I could find quite answer my exact question.

I would like to run a command within a subshell within an eval call and obtain the status code returned by the function called within the subshell.

For example, I call a command like this:

eval "$(some_command)"
if [ "${?}" -ne 0 ]
then
    # do stuff if `some_command` returned status code not equal to zero
fi

This some_command function returns a list of environment variables and their assignments like this:

$ some_command      # Execute some_command in a standard fashion without eval or subshell
some_env_variable='some_value'
another_env_variable='another value'

The goal is to run this single command to add these environment variable to the current environment. The only way to do that is to call some_command within a subshell, and have eval evaluate the resulting output. If I do this without the subshell, eval will simply run some_command but it will not evaluate it's output to add the environment variable to the current environment.

This works:

$ eval "some_command"
-bash: some_command: command not found
$ echo $?
127

This works:

$ $(some_command)
-bash: some_command: command not found
$ echo $?
127

But this does not work:

$ eval "$(some_command)"
-bash: some_command: command not found
$ echo $?
0

There must be some way of obtaining the resulting status code from some_command, but I have been unable to determine how. Any help is appreciated!

Ian Tait
  • 607
  • 1
  • 8
  • 16
  • If I understand your question, the [bash(1) - Linux manual page](http://man7.org/linux/man-pages/man1/bash.1.html) is clear "The args are read and concatenated together into a single command. This command is then read and executed by the shell, and its **exit status** is returned as the value of eval. If there are no args, or only null arguments, eval returns 0." – David C. Rankin Jan 10 '19 at 18:16
  • Maybe there's a way to avoid `eval` entirely? – Paul Hodges Jan 10 '19 at 18:32
  • I know many developers are very weary of using eval because it is "dangerous" or whatever, but this is definitely what I would like to do. I have extensive verification that the output of some_command will not be dangerous for eval to interpret. I need to use eval because I would like the output of some_command to add environment variables to the calling process – Ian Tait Jan 10 '19 at 18:43
  • @PaulHodges This is the one situation where `eval` is pretty much indispensable; you do have to trust the program to produce output that is safe to evaluate. `ssh-agent` is a commonly used example where it is designed to be used with `eval $(ssh-agent -s)`. – chepner Jan 10 '19 at 18:58

1 Answers1

5

If you are actually concerned about the exit status, don't use eval immediately.

if envvars=$(some_command); then
    eval "$envvars"
else
    # do something else
fi

If you need the exact error code, instead of just distinguishing between 0 and non-zero:

envvars=$(some_command)
rv=$?  # save it for later if necessary
case $rv in
   0) eval "$envvars" ;;
   1) ... ;;
   2) ... ;;
   # etc
   *) printf 'Some other error %d\n' "$rv" >&2 ;;
esac
chepner
  • 497,756
  • 71
  • 530
  • 681
  • This will work for determining whether the command succeeded or not, but still does not give me the actual status code within an environment variable such as `$?`. I'd like to be able to grab the error code and preform certain actions based on the exact value of the status code. – Ian Tait Jan 10 '19 at 18:36
  • `$?` should be available in the `else` block. – Barmar Jan 10 '19 at 18:37
  • @IanTait The question just says that you want to do something if the status is not `0`, it doesn't say you need to distinguish different codes. – Barmar Jan 10 '19 at 18:39
  • It says that I want to capture the status code. From the original post: "I would like to run a command within a subshell within an eval call and OBTAIN THE STATUS CODE returned by the function called within the subshell". I have made some edits to try to make this more clear. – Ian Tait Jan 10 '19 at 18:41
  • It also says `# do stuff if \`some_command\` returned status code not equal to zero` – Barmar Jan 10 '19 at 18:43
  • Yes, you have to take the entire post into consideration to determine what I am trying to achieve. Simply looking at one line will not do. – Ian Tait Jan 10 '19 at 18:44
  • @chepner After your edit, that will work for me. After looking at it, it seems obvious to me.. I was stuck in a one-liner mindset and I just needed to get away from that. Thanks! – Ian Tait Jan 10 '19 at 18:46