2017-07-23 33 views
1

我使用的是KSH腳本來執行一個二進制文件(程序)具有以下語法正確執行:用戶定義輸出重定向無法正常運行

  • myprog [-v | --verbose (optional)] [input1] [input2]

該程序打印什麼&成功時返回退出代碼0(零)。在失敗時,它將打印ERROR消息至STDERR &返回exit status > 0。如果指定了-v選項,則會在成功和失敗的情況下將詳細的詳細信息打印到STDOUT

爲了使其可用並減少參數交換和用戶控制日誌的機會,我使用了一個ksh shell腳本來調用這個二進制文件。運行KSH外殼腳本的語法:

  • myshell.sh [-v(可選)] [-a INPUT1] [-b輸入2]

如果指定-v選項,KSH重定向STDOUT<execution_date_time>_out.logSTDERR<execution_date_time>_err.log。我的ksh腳本如下:

myshell.sh:

#! /bun/ksh 

verbopt="" 
log="" 
arg1="" 
arg2="" 
dateTime=`date +%y-%m-%d_%H:%M:%S` 

while getopts "va:b:" arg 
do 
    case $arg in 

     v) # verbose output 
      verbopt="-v" 
      log="1>${dateTime}_out.log 2>${dateTime}_err.log" 
      ;; 
     a) # Input 1 
      arg1=$OPTARG 
      ;; 
     b) # Input 2 
      arg2=$OPTARG 
      ;; 
     *) # usage 
      echo "USAGE: myshell.sh [-v] [-a input1] [-b input2]" 
      exit 2 
      ;; 
    esac 
done 

if [[ -z $arg1|| -z $arg2]] 
then 
    echo "Missing arguments" 
    exit 2 
fi 

myprog $verbopt $arg1 $arg2 $log 
exit $? 

這裏的問題是,所有的輸出STDERR & STDOUT印在屏幕上(即沒有重定向發生),以及無*.log文件是在成功執行或不成功執行後創建的(即退出狀態分別爲0或> 0)。

任何人都可以幫我解決這個問題嗎? 謝謝。

回答

1

問題是>未擴大$log的值。

我怕你會需要使用條件對於這一點,例如:

cmd="myprog $verbopt $arg1 $arg2" 

if [ "$log" ]; then 
    $cmd 1>${dateTime}_out.log 2>${dateTime}_err.log 
else 
    $cmd 
fi 
-1

看看在eval命令。

替換...

myprog $verbopt $arg1 $arg2 $log 

有:

eval myprog $verbopt $arg1 $arg2 $log 

我不知道你的myprog做什麼,但這裏是一個使用eval運行date一個簡單的例子(有效的命令)和date xyz(invalid command),將輸出重定向到log.stdout/log。標準錯誤相應:

$ cat logout 
log='1>log.stdout 2>log.stderr' 

'rm' -rf log.std* > /dev/null 2>&1 

echo "" 
echo 'eval date ${log}' 
eval date ${log} 

echo "" 
echo "++++++++++++ log.stdout" 
cat log.stdout 
echo "++++++++++++ log.stderr" 
cat log.stderr 
echo "++++++++++++" 

'rm' -rf log.std* > /dev/null 2>&1 

echo "" 
echo 'eval date xyz ${log}' 
eval date xyz ${log} 

echo "" 
echo "++++++++++++ log.stdout" 
cat log.stdout 
echo "++++++++++++ log.stderr" 
cat log.stderr 
echo "++++++++++++" 

現在運行腳本:

$ logout 

eval date ${log} 

++++++++++++ log.stdout 
Sun Jul 23 15:56:01 CDT 2017 
++++++++++++ log.stderr 
++++++++++++ 

eval date xyz ${log} 

++++++++++++ log.stdout 
++++++++++++ log.stderr 
date: invalid date `xyz' 
++++++++++++ 
+0

強烈建議不要使用'eval'。特別是用戶提供的字符串。這不是完成目標的安全方法。 –

+0

我的第一篇文章是一個簡單的例子,介紹如何使用eval。 OP仍然可以在腳本中使用'eval',因爲他實際上並沒有讓用戶提供任何潛在的惡意命令;我已更新該帖子以提供一個不顯示運行任何用戶提供的字符串的示例;現在開心? :-) – markp

0

我會用成語exec重定向,彷彿當它是給定的重定向已提供其運行腳本的其餘部分運行:

if need_to_log; then 
    exec >stdout_file 2>stderr_file 
fi 
this command will be logged if the above if statement was true 

如果您需要恢復stdout和stderr,以便腳本可以做更多未記錄的事情S,你可以在子shell中運行日誌部分:

(
    if need_to_log; then 
    exec >stdout_file 2>stderr_file 
    fi 
    this command will be logged if the above if statement was true 
) 
this command will not be logged regardless 

我還要在一個陣列構建命令,這樣你就可以不必爲每個可能的參數一個獨立的變量像-v將其添加的東西。如果-a-b自變量提供給myprog的順序無關緊要,那麼您可以將它們添加到數組中,而不是具有單獨的變量。

你可以在下面看到我的版本。除了上述更改外,如果不進行日誌記錄,我也不打擾獲取時間戳,因爲它不需要,並且使用ksh內建print將錯誤消息發送到標準錯誤而不是標準錯誤。

這是我放在一起:

#!/usr/bin/env ksh 

# new array syntax requires ksh93+; for older ksh, use this: 
# set -A cmd myprog 
cmd=(myprog) # build up the command to run in an array 
log_flag=0 # nonzero if the command should be logged 
input_a=  # the two input filenames 
input_b= 

while getopts 'va:b:' arg; do 
    case $arg in 
    v) # verbose output 
     # older ksh: set -A cmd "${cmd[@]}" -v 
     cmd+=(-v) 
     log_flag=1 
     ;; 
    a) # Input 1 
     input_a=$OPTARG 
     ;; 
    b) # Input 2 
     input_b=$OPTARG 
     ;; 
    *) # usage 
     print -u2 "USAGE: $0 [-v] [-a input1] [-b input2]" 
     exit 2 
     ;; 
    esac 
done 

if [[ -z $input_a || -z $input_b ]]; then 
    print -u2 "$0: Missing arguments" 
    exit 2 
fi 

if ((log_flag)); then 
    timestamp=$(date +%y-%m-%d_%H:%M:%S) 
    exec >"${timestamp}_out.log" 2>"${timestamp}_err.log" 
fi 

"${cmd[@]}" "$input_a" "$input_b" 

你戳使用兩位數的年份(%y);以及組件之間的下劃線是與ISO 8601標準唯一的偏差,所以我建議您繼續並採用標準格式。那應該是%Y-%m-%dT%H:%M:%S,或者在C庫中有更新版本的strftime,%FT%T

你也可以更聰明一些,並且使log_flag爲空或字符串-q,將它傳遞給命令,並根據空字符串測試它以確定是否打開日誌文件,但是我使用簡單的0/1值作爲布爾值來處理邏輯更容易。

+0

downvote的說明嗎? –

2

與其試圖將重定向補丁修改到命令行中,不如在解析標誌時重定向流。那就是:

while getopts "va:b:" arg 
do 
    case $arg in 

     v) # verbose output 
      verbopt="-v" 
      exec 1>${dateTime}_out.log 2>${dateTime}_err.log 
      ;; 
... 

你必須要小心一點,因爲你做了一些錯誤後,這個檢查,你可能不希望你以後的錯誤消息,要去* _err.log,但這是相當瑣碎固定。 (例如錯誤檢查更快,或者在錯誤檢查後執行test -n "$verbopt" && exec > ...或類似的操作)