如果 stdout 已被重定向,我怎麼知道腳本中的內容?
我在 ksh 中有一個腳本;根據是否有來自命令行的重定向,我通過
exec 1>file
. 如果呼叫它的命令已重定向其輸出,我如何從腳本本身內部進行測試?我嘗試使用 $ @, $ *、$0,甚至是
ps
腳本的 PID(希望有一個 shebang),但重定向永遠不會出現。在這種情況下,該腳本在 AIX 上執行。
在 AIX 上,stdout 文件描述符位於
/proc/$$/fd/1
,因此您可以測試它是否為正常文件:if [ -f /proc/$$/fd/1 ] then echo stdout has already been redirected else echo redirecting stdout exec 1>file echo some output fi
/bin/sh 硬連結到 /bin/ksh,因此您在任一 shell 中都會獲得相同的行為。
如果需要,您可以單獨測試 stdout 是否已重定向到 /dev/null:
if [ /proc/$$/fd/1 -ef /dev/null ]; then : ...; fi
一般來說,你不能。重定向不會顯示為正在執行的命令的參數。即使他們這樣做了,您也無法在所有情況下都知道腳本輸出的位置。考慮這兩個:
bash -c 'somecmd > /dev/null; othercmd'
和
bash -c 'somecmd; othercmd' > /dev/null
在第一種情況下, 的輸出
somecmd
被重定向到/dev/null
,但在第二種情況下,整個 shell 的輸出被重定向,包括somecmd
和othercmd
。在第二種情況下看到命令行somecmd
並不能說明輸出是如何重定向的。也就是說,看來 Bash 的
DEBUG
陷阱可以用於此目的。$ trap 'export CMDLINE=$BASH_COMMAND' DEBUG $ env 2>/dev/null |grep CMD CMDLINE=env 2> /dev/null
陷阱將要執行的命令導出為
CMDLINE
,我們可以看到它已導出,因為它顯示在 的輸出中env
。請注意,未顯示完整的管道,僅顯示一個命令。也就是說,在大多數情況下,有比試圖猜測使用者的重定向更好的方法來處理事情。許多命令會檢查輸出是否到達終端並據此更改它們的行為。
要檢查 stdout 是否是終端,您可以使用
[ -t 1 ]
:$ if [ -t 1 ]; then echo terminal; else echo not terminal; fi |cat not terminal
這最常用於禁用某些互動功能或無關輸出,以防輸出不發送到終端,因此假設是發送給使用者。
如果僅測試文件描述符是否指向終端還不夠,可能最簡單的方法是安排向程序傳遞一個附加參數,告訴程序在哪種模式下執行。也就是說,不用關心重定向,而是讓如果以 開頭,則程序執行一件事,如果以 開頭,則執行另一件事,如果以不帶參數的
someprog --mode=cron
方式啟動,則以someprog --mode=batch
互動方式執行。(將互動或命令行模式設為預設模式,這樣使用者每次手動執行時都--mode
無需手動輸入。)--mode=commandline