Pipeline metacharacter in variable in bash
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?
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
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.
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.
I tried a similar code and specified the last line like this and it worked
application param1 &2>1 ${OUT} > /dev/null
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.
精彩评论