views:

50

answers:

5

In my bash script I need to check if logger binary exists. If so, I pipe the application output to it.

Edit--------
| It needs to be piping, the application should work permanently.
---------------

I tried to put the pipeline stuff to a variable and use it later. Something like:

if [ -e /usr/bin/logger ]; then
  OUT=| /usr/bin/logger 
fi

application  param1  2>&1   $OUT   >  /dev/null &

but it doesn't work, the output is not piped to the logger. If I put the pipeline stuff directly into the application startline, it works. Unfortunately the real script becomes too complicated if I use command lines with and without logger stuff in if/else statements - the reason is that I already have if/else there and adding new ones will double the number of cases.

Simple test application

TMP=| wc -m
echo aas bdsd vasd $TMP

gives

$ ./test.sh
0
aas bdsd vasd

Seems that somehow command1 and command2 are executed separately.

I managed to solve the problem (in both test and real scripts) using eval and putting the conditional stuff in double quotes.

TMP="| wc -m"
eval echo aas bdsd vasd $TMP

$ ./test.sh
14

It feels like a workaround. What is the right way to do it?

+1  A: 

Try

if [ -e /usr/bin/logger ]; then
  logger $(application  param1 2>&1)
fi

General rule: don't put commands inside variables and call it through the variable. Just run it directly off your script.

ghostdog74
@ghostdog74 thanks for the advice, I'll consider reworking the script.
Dmitry Yudakov
A: 

I tried a similar code and specified the last line like this and it worked

application  param1  &2>1   ${OUT}   >  /dev/null
Raghuram
@Raghuram Unfortunately I don't see any difference in neither of the mentioned examples when bracing the variable name
Dmitry Yudakov
A: 

While ghostdog74's answer is correct, there is certainly a way to make this work

if [ -e /usr/bin/logger ]; then
  OUT='| /usr/bin/logger'
fi

eval application param1 2>&1 $OUT > /dev/null

But I highly recommend that you think twice before using eval, and then don't use it.

Sorpigal
@Sorpigal well, yes, I mentioned that `eval` solves the problem
Dmitry Yudakov
Sorry, I hadn't seen the edit at the time I posted.
Sorpigal
+2  A: 

The correct way to do this is to use if/else:

if [ -e /usr/bin/logger ]
then
    application  param1  2>&1 | /usr/bin/logger >  /dev/null &
else
    application  param1 > /dev/null 2>&1 &
fi

Edit:

In the case of a complex construct, you should use a function:

foo () {
    if [ ... ]
    then
        do_something
    else
        something_else
    fi
    while [ ... ]
    do
        loop_stuff
    done
    etc.
}

Then your log/no log if stays simple:

if [ -e /usr/bin/logger ]
then
    foo  2>&1 | /usr/bin/logger >  /dev/null &
else
    foo > /dev/null 2>&1 &
fi
Dennis Williamson
@Dennis Williamson thank you for the answer, I agree that for a simple case it's better to use if/else and put the logger stuff directly in the command lines. What about the cases when you have several if/else cases already and adding one more would double their total count? Maintaining them would become too hard.
Dmitry Yudakov
@Dmitry: Just put the complex stuff in a function and keep the logger conditional simple. See my edit.
Dennis Williamson
+2  A: 

Just to throw another option into the mix, you could move the pipe outside the variable:

if [ -e /usr/bin/logger ]; then
    logcmd=/usr/bin/logger
else
    logcmd=/bin/cat
fi

application param1 2>&1 | $logcmd >/dev/null &

This avoids having duplicate commands for the two cases (or having to wrap everything in functions, per Dennis' suggestion). The disadvantage is that it's inefficient about how it handles the case where logger doesn't exist -- creating a cat process just to feed output to /dev/null is a complete waste. But a cat process isn't that big a resource drain, so if it makes your code cleaner it might be worth the waste.

Gordon Davisson
that's not a bad idea, thank you
Dmitry Yudakov