2011-06-08 46 views
2

如何让Bash在I/O重定向时解释变量的内容,而不是简单地将这些内容传递给正在执行的命令。就拿这个脚本,例如:Bash - 解释变量的内容

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

所需的行为方式是,当我运行此脚本使用--log选项bash的西港岛线执行

$日期2> & 1 | tee time.log

如果我没有指定--log,那么它只是输出日期而不创建日志。相反,它通过$日志记录的内容,日期,从而导致错误的CLI参数:

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

有没有办法做到这一点,而无需编写像

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

实际应用中要明显得多比只调用“日期”复杂,所以我想避免复制和粘贴该命令两次,如果其他只是附加重定向和日志记录命令。

回答

1

您可以使用eval

eval date $LOGGING 
+1

\ *。*抽搐。 [eval is evil](http://mywiki.wooledge.org/BashFAQ/048)。 – l0b0 2011-06-09 14:17:55

2

如果你的脚本是相当长的,你要记录所有的输出和错误时--log传递中,我建议使用exec来重定向一切。看到这个优秀的文章:

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. 

这种方法的有趣的事情是,你还可以使用Perl或笨拙的人或一些其他实用前插所有记录的行与时间戳:

#!/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 

运行后,time.log将包含:

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

这里的缺点是时间戳也会打印到您的终端上。

1

问题是,通过将command in a variable,您有效地将所有内容转换为字符串,而不是将其保留为Bash关键字。尝试附加-x的家当行:

$ ./test.sh --log 
+ test --log == --log 
+ LOGGING='2>&1 | tee time.log' 
+ date '2>&1' '|' tee time.log 
date: extra operand `|' 
Try `date --help' for more information. 

试试这个:

#!/bin/bash -x 
logging() { 
    if [ "$1" == '--log' ] 
    then 
     cat 2>&1 | tee time.log 
    else 
     cat 
    fi 
} 
date | logging "$1"