基於這三個問題中的文件:啓動和停止記錄終端輸出從bash腳本
- redirect COPY of stdout to log file from within bash script itself
- Redirect a COPY of stdout to different log files multiple times from within same bash script
- Temporary redirection of stderr in a bash script
...我有放在一起腳本testlogredir.sh
,包含在下面。它試圖做的是:運行三個命令,其stdout和stderr輸出將被記錄到終端和日誌文件;然後再運行兩個命令,其stdout和stderr輸出僅發送給終端。實際上,它將啓動和停止將腳本的終端輸出重定向到日誌文件,同時保留終端輸出。
有趣的是,如果我用一個sleep
停止記錄到文件後,一切正常:
$ bash testlogredir.sh 1 y
--- testlogredir.sh METHOD=1 DOSLEEP=y ---
aaa
bbb
ccc
ddd
eee
$ cat test.log
aaa
bbb
ccc
...,也得到相同的結果運行bash testlogredir.sh 2 y
。
有趣的是,如果我不使用的睡眠(相同的輸出也將與bash testlogredir.sh 1
獲得):
$ bash testlogredir.sh 2
--- testlogredir.sh METHOD=2 DOSLEEP= ---
ddd
eee
$ aaa
bbb
ccc
^C
$ cat test.log
aaa
bbb
ccc
...值得注意的是,第一最後「ddd
」和「eee
」輸出到終端;然後提示然後出現的第一個「aaa
」,「bbb
」,「ccc
」是輸出 - 並且該過程作爲一個整體(b)中的鎖;所以我必須按Ctrl-C(^ C)才能退出它。但是,日誌文件確實具有預期的內容。
我推測,在沒有睡眠的情況下,在bash解釋器通過腳本跑這麼快,它成功地呼應了「最後」二「ddd
」和「eee
」 第一 - 然後才做tee
輸出它已經存儲了(注意,這是不是由於tee
緩衝行爲,因爲我已經stdbuf
得到相同的結果試了一下還),顯然它是不會阻塞的tee
。因此,添加sleep
,以某種方式使bash腳本與tee
(sub?)進程「同步」。
很顯然,我希望命令輸出按順序顯示 - 而sleep
本身並沒有打擾我很多,因爲我可以將它設置爲sleep 0.1
,但幾乎沒有注意到它。但我要問 - 這是做這種開始以正確的方式從bash
腳本中/停止「tee
」重定向?換句話說 - 有沒有其他方法可以使用sleep
來實現這種「同步」,可以這麼說呢?
testlogredir。SH
#!/usr/bin/env bash
# testlogredir.sh
# defaults:
METHOD="1" # or "2"
DOSLEEP="" # or "y"
if [ "$1" ] ; then
METHOD="$1" ;
fi
if [ "$2" ] ; then
DOSLEEP="$2" ;
fi
# this should be echoed only to terminal
echo " --- $0 METHOD=$METHOD DOSLEEP=$DOSLEEP ---"
# silent remove of test.log
rm -f test.log
if [ $METHOD == "1" ] ; then
# Redirect 3 into (use fd3 as reference to) /dev/stdout
exec 3> /dev/stdout
# Redirect 4 into (use fd4 as reference to) /dev/stderr
exec 4> /dev/stderr
fi
if [ $METHOD == "2" ] ; then
# backup the original filedescriptors, first
# stdout (1) into fd6; stderr (2) into fd7
exec 6<&1
exec 7<&2
fi
# Redirect stdout (>) into a named pipe (>()) running "tee"
#~ exec > >(stdbuf -i0 -o0 tee test.log)
exec > >(tee test.log)
# Redirect stderr (2) into stdout (1)
exec 2>&1
# these should be echoed both to terminal and log
echo "aaa"
echo "bbb"
echo "ccc" >&2
if [ $METHOD == "1" ] ; then
# close current stdout, stderr
exec 1>&-
exec 2>&-
# Redirect stdout (1) and stderr (2)
exec 1>&3
exec 2>&1
fi
if [ $METHOD == "2" ] ; then
# close and restore backup; both stdout and stderr
exec 1<&6 6<&-
exec 2<&7 2<&-
# Redirect stderr (2) into stdout (1)
exec 2>&1
fi
if [ "$DOSLEEP" ] ; then
sleep 1 ;
fi
# these should be echoed only to terminal
echo "ddd"
echo "eee" >&2
exit
謝謝,@vegatripy - 我想,以避免在大括號的方法,因爲這三個命令可以是一個獨立對於100個命令,我不想追蹤那裏的額外大括號。我更喜歡「睡眠」命令的替代方案,如果存在的話......乾杯! – sdaau