Welcome to OGeek Q&A Community for programmer and developer-Open, Learning and Share
Welcome To Ask or Share your Answers For Others

Categories

0 votes
601 views
in Technique[技术] by (71.8m points)

io redirection - Bash - interpreting the contents of a variable

How can I make Bash interpret the contents of a variable as I/O redirects and not simply pass those contents to the command being executed. Take this script for example:

#!/bin/bash
test "$1" == '--log' && LOGGING="2>&1 | tee time.log" || LOGGING=""
date $LOGGING

The desired behavior is that when I run this script with the --log option bash wil execute

$ date 2>&1 | tee time.log

If I don't specify --log then it simply outputs date without creating a log. Instead it passes the contents of $LOGGING to date as a CLI argument resulting in an error:

 date: extra operand `|' Try `date
 --help' for more information.

Is there way to do this without writing something like

#!/bin/bash
test "$1" == '--log' && date 2>&1 | tee time.log || date

The actual application is obviously much more complicated than just calling "date" so I'd like to avoid copying and pasting that command twice in an if else just to append the redirect and logging commands.

See Question&Answers more detail:os

与恶龙缠斗过久,自身亦成为恶龙;凝视深渊过久,深渊将回以凝视…
Welcome To Ask or Share your Answers For Others

1 Reply

0 votes
by (71.8m points)

If your script is rather long and you want to log all stdout and stderr when --log is passed in, I suggest using exec to redirect everything. See this excellent article:

http://www.linuxjournal.com/content/bash-redirections-using-exec

#!/bin/bash
if [[ "$1" == '--log' ]]; then
    npipe=/tmp/$$.tmp
    trap "rm -f $npipe" EXIT
    mknod $npipe p
    tee <$npipe log &
    exec 1>&-
    exec 1>$npipe
fi

date
# and any other commands after this will be logged too.

The interesting thing about this approach is that you can also prepend all logged lines with a timestamp using perl or gawk or some other utility:

#!/bin/bash
if [[ "$1" == '--log' ]]; then
    npipe=/tmp/$$.tmp
    trap "rm -f $npipe" EXIT
    mknod $npipe p
    perl -pne 'print scalar(localtime()), " ";' < $npipe | tee time.log &
    exec 1>&-
    exec 1>$npipe 2>&1
fi

echo hello world
echo hello world 2

After running this, time.log will contain:

$ cat time.log 
Wed Jun  8 13:28:45 2011 hello world
Wed Jun  8 13:28:45 2011 hello world 2

The drawback here is that the timestamp are printed to your terminal too.


与恶龙缠斗过久,自身亦成为恶龙;凝视深渊过久,深渊将回以凝视…
OGeek|极客中国-欢迎来到极客的世界,一个免费开放的程序员编程交流平台!开放,进步,分享!让技术改变生活,让极客改变未来! Welcome to OGeek Q&A Community for programmer and developer-Open, Learning and Share
Click Here to Ask a Question

...