Shell

如果 stdout 已被重定向,我怎麼知道腳本中的內容?

  • January 29, 2019

我在 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 的輸出被重定向,包括somecmdothercmd。在第二種情況下看到命令行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

引用自:https://unix.stackexchange.com/questions/497395