2011-06-08 33 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"