Jurasic
Jurasic

Reputation: 1956

Pass command via variable in shell

I have following code in my build script:

if [ -z "$1" ]; then
    make -j10 $1 2>&1 | tee log.txt && notify-send -u critical -t 7 "BUILD DONE"
else
    make -j10 $1 2>&1 | tee log.txt | grep -i --color "Error" && notify-send -u critical -t 7 "BUILD DONE"
fi  

I tried to optimize it to:

local GREP=""
[[ ! -z "$1" ]] && GREP="| grep -i --color Error" && echo "Grepping for ERRORS"
make -j10 $1 2>&1 | tee log.txt "$GREP" && notify-send -u critical -t 7 "BUILD DONE"

But error thrown in make line if $1 isn't empty. I just can't figure out how to pass command with grep pipe through the variable.

Upvotes: 0

Views: 116

Answers (3)

tripleee
tripleee

Reputation: 189926

Like others have already pointed out, you cannot, in general, expect a command in a variable to work. This is a FAQ.

What you can do is execute commands conditionally. Like this, for example:

( make -j10 $1 2>&1 && notify-send -u critical -t 7 "BUILD DONE" ) |
tee log.txt |
if [ -z "$1" ]; then
    grep -i --color "Error"
else
    cat
fi

This has the additional unexpected benefit that the notify-send is actually conditioned on the exit code of make (which is probably what you intended) rather than tee (which I would expect to succeed unless you run out of disk or something).

(Or if you want the notification regardless of the success status, change && to just ; -- I think this probably makes more sense.)

This is one of those rare Useful Uses of cat (although I still feel the urge to try to get rid of it!)

Upvotes: 1

Tom Fenech
Tom Fenech

Reputation: 74695

As mentioned in @l0b0's answer, the | will not be interpreted as you are hoping.

If you wanted to cut down on repetition, you could do something like this:

if [ $(make -j10 "$1" 2>&1 > log.txt) ]; then
    [ "$1" ] && grep -i --color "error" log.txt
    notify-send -u critical -t 7 "BUILD DONE"
fi

The inside of the test is common to both branches. Instead of using tee so that the output can be piped, you can just indirect the output to log.txt. If "$1" isn't empty, grep for any errors in log.txt. Either way, do the notify-send.

Upvotes: 1

l0b0
l0b0

Reputation: 58978

You can't put pipes in command variables:

$ foo='| cat'
$ echo bar $foo
bar | cat

The linked article explains how to do such things very well.

Upvotes: 1

Related Questions