2017-05-23 22 views
1

當編譯時間失敗時,編程語言Crystal當前不寫入STDERR。如果退出狀態不是0並且仍然返回退出狀態,我需要將STDOUT重定向到STDERR。退出狀態在Bash中不爲0時將STDOUT重定向到STDERR

+0

您嘗試過'some_bash_command.sh 2&1'嗎? – t0mm13b

+1

重新定向在**程序啓動之前運行**。退出狀態僅在**該程序退出後才知道。你不能回到過去。 –

回答

3

從字面上看,您的請求實際上是不可能的:重定向在命令啓動之前執行,而退出狀態僅在退出時才知道。

但是,您可以無條件地重定向到緩衝區,然後在知道退出狀態後將該緩衝區寫入stdout或stderr。

考慮類似於以下的包裝:

#!/bin/sh 
if output=$("[email protected]"); then 
    printf '%s\n' "$output" 
else 
    retval=$? 
    printf '%s\n' "$output" >&2 
    exit "$retval" 
fi 

...援引爲(如果這被保存爲stderr-wrapper):

stderr-wrapper your-program arg1 arg2 ... 
+0

這太棒了!非常感謝!它對其他快樂道路沒有任何副作用。 –

+0

這裏*有一個警告,因爲這段代碼會吃掉任何可能包含在程序輸出中的NULs(因爲NULs不能存儲在C字符串中,bash用於存儲內存)。如果這是一個問題,你可能會寫入一個文件。 –

+1

如果預期的輸出太大,則臨時文件可能更安全 –

1

迴旋管的方法,這需要tac和無害eval,但既不是緩衝區變量也不是臨時文件。

演示腳本demo,使用echo false ; false模擬程序,它輸出到標準輸出返回一個錯誤碼「」。

#!/bin/bash 
out=([0]=/dev/stdout [1]=/dev/stderr) 
{ { echo $1 ; $1 ; echo $? ; } | tac ; } | \ 
    { read x ; eval tac \> ${out[$x]} ; exit $x ; } 

證明,使用annotate-output

annotate-output +'' ./demo true ; echo --- ; annotate-output +'' ./demo false 
I: Started ./demo true 
O: true 
I: Finished with exitcode 0 
--- 
I: Started ./demo false 
E: false 
I: Finished with exitcode 1 

歸納該demostderr-wrapper

  1. 對於bash

    #!/bin/bash 
    # Usage: stderr-wrapper program [ args... ] 
    out=([0]=/dev/stdout [1]=/dev/stderr) 
    { { [email protected] ; echo $? ; } | tac ; } | \ 
    { read x ; eval tac \> ${out[$((x>0))]} ; exit $x ; } 
    
  2. 對於POSIX殼,(這裏是dash):

    #!/bin/dash 
    # Usage: stderr-wrapper program [ args... ] 
    { { "[email protected]" ; echo $? ; } | tac ; } | \ 
    { read x ; eval tac 1\>\&$(((x>0)+1)) ; exit $x ; } 
    

bash版本是如何工作的:

  1. 運行有問題的程序,它輸出到標準輸出
  2. 之後立即打印錯誤代碼,也可以標準輸出
  3. 反轉整個流與tac,所以錯誤代碼是第一個。 (昂貴,如果流很長。)
  4. read一行,錯誤代碼,存儲在$x
  5. eval$out陣列成員對應於輸出應該去的設備,然後用tac重新反向輸出到該設備。
相關問題