3

I have getinfo.sh which either prints information or exists with code 1.

I want to store the result of this script in a bash variable, otherwise print an error message and exit.

If I run this

#!/bin/bash
X=`getinfo.sh` || echo "failed" && exit 1

then the script exits even when getinfo.sh succeeds (in this case it prints nothing.

On the other hand

X=`getinfo.sh` || (echo "failed" && exit 1)

which makes sense to me, coming from C-like languages, but this does not exit the script since the parentheses create a new, inner shell, and it is the inner-shell which is exited, the outer shell keeps running.

How can I store the output of getinfo.sh and print-and-exit if that fails?

3

(...) is not (primarily) to group commands, but to start a subshell. So the exit in (echo failed && exit 1) only exits the subshell.

To group commands without running them in a subshell, you'd use { ...; } instead:

X=`getinfo.sh` || {
  echo >&2 "failed"
  exit 1
}

Though here, I'd rather use:

if ! x=$(getinfo.sh); then
  echo >&2 failed
  exit 1
fi

Also note that your echo failed && exit 1 could fail to exit if echo itself fails which could happen for intance when stdout is a file on a full filesystem, or a broken pipe with SIGPIPE ignored, or stdout has been closed, or a file size limit has been reached with SIGXFSZ ignored...

2

You can use curly braces to group commands together without creating a subshell.

X=$(getinfo.sh) || { echo "failed" && exit 1; }

From Grouping Commands section in the Bash manual

{ list; }

Placing a list of commands between curly braces causes the list to be executed in the current shell context. No subshell is created. The semicolon (or newline) following list is required.

Note: backticks are effectively deprecated for command substitution so I’ve used the more modern $() syntax.

1

Since you're setting the value of a variable why not check the value of the variable and exit if it's inappropriate?

X=`getinfo.sh`

[ -z "$X" ] && echo "failed" && exit 1

This would assume getinfo.sh would return empty on failure, (if X is zero length, exit) but you can modify the check based on what getinfo returns on failure. Or more appropriately, check to ensure X contains the sort of data you're looking for.

0

The easiest way is to add -e to your shebang:

#!/bin/bash -e

This means that script will stop at the first error. Since you use backtick, if there's any error message you will probably see it in your stdout anyway.

If you really want to use your echo-and-exit method, I'd write a separate function that would be called, that always prints some error message and immediately exits. Look up how to write bash functions(they're really easy).

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

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