I want to assign my variable a a the first word of the result of the command func <some_arg> only if it does not fail. And if it fails I need to log that.

What I've done so far is:

func() {
    if [[ $1 -eq 1 ]]
        echo 'hello world'
        return 0

    echo 'Something wrong has happened!' >> path/to/dev.log
    return 2

a=$(func 1)

if [[ $r -eq 0 ]]
    a=$(awk '{ print $1 }' <<<"$a")

This works of course but I do not like assigning my variable a twice.

I tried this:

  a=$(func 2 | awk '{ print $1 }') || echo 'Something wrong has happened!' >> path/to/dev.log

But it does not log anything

Is there a better way?


You could use set -o pipefail to get the error from the earlier part of the pipeline:

The return status of a pipeline is the exit status of the last command, unless the pipefail option is enabled. If pipefail is enabled, the pipeline's return status is the value of the last (rightmost) command to exit with a non-zero status, or zero if all commands exit successfully.

$ foo() { [[ "$1" = 1 ]] || return 1; echo "hello world"; }
$ a=$(set -o pipefail; foo 2 | awk '{print $1}' || echo "fail..." >&2)

But really, I can't see why assigning twice would be an issue. In essence, you just modify the value you got if the command succeeds, or ignore it if it failed.

Also, you can condense that logic a bit:

if a=$(foo 1); then
   a=${a%% *};
   echo "first word of a is '$a'"; 
   # do some work with $a...
   echo "error..." >&2;


first word of a is 'hello'

The shell has several native ways to parse out the first word of a string:

  1. Trim by suffix - ${a%% *}

  2. Assign to positional parameters - set -- ${a} - the result will be in $1. You can simplify this with set -- $(func 1).

  3. Divide into array elements (bash only) - a=( $(func 1) ) - the result will be in ${a[0]}.


One issue with your code is that it clobbers a even if the function func returns a non-zero result.



func () {
    if [ "$1" -eq 1 ]; then
        echo 'some sort of logging stuff' >>logfile
        return 1

    echo 'hello world'

a="a string"

if b=$( func 0 ); then
    a=${b%% *}

printf '1: a = "%s"\n' "$a"

a="a string"

if b=$( func 1 ); then
    a=${b%% *}

printf '2: a = "%s"\n' "$a"

Running this will produce

1: a = "hello"
2: a = "a string"

As you can see, in the second case, a retains its value.

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.