Bash - 解释变量的内容

时间:2011-06-08 19:20:26

标签: bash io-redirection

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

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

所需的行为是当我使用--log选项运行此脚本时bash将执行

$ date 2>& 1 | tee time.log

如果我没有指定--log,那么它只是输出日期而不创建日志。相反,它将$ LOGGING的内容作为CLI参数传递给日期,从而导致错误:

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

如果没有像

这样的东西,有没有办法做到这一点
#!/bin/bash
test "$1" == '--log' && date 2>&1 | tee time.log || date

实际的应用程序显然要比调用“date”复杂得多,所以我想避免在if else中复制和粘贴该命令两次只是为了附加重定向和日志记录命令。

3 个答案:

答案 0 :(得分:2)

如果您的脚本相当长并且您希望在传入--log时记录所有stdout和stderr,我建议使用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或gawk或其他一些实用程序为所有记录的行添加时间戳:

#!/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 :(得分:1)

您可以使用eval

eval date $LOGGING

答案 2 :(得分:1)

问题在于,通过添加command in a variable,您实际上将所有内容都转换为字符串,而不是将其作为Bash关键字。尝试将-x附加到shebang行:

$ ./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"