Shell
正在執行的腳本可以辨識日誌記錄上下文嗎?
假設我將程序的
STDOUT
,重定向STDERR
到文件。./script.sh 1> output.log 2> error.log
正在執行的程序能否發現這一點,即知道這些文件的路徑?
您可以呼叫
lsof
列出 shell 程序的打開文件。用於-a -p $$
將輸出限制為 shell 程序 ($$
),-d 1
將輸出限制為文件描述符 1(例如),並-F n
以可解析的形式列印輸出。這是一個處理文件名中任意字元的 shell 片段:output_file=$(lsof -a -p $$ -d 1 -F pn; echo .) output_file=${output_file%.} output_file=${output_file#n}
如果文件名不包含換行符,您將能夠擺脫
output_file=$(lsof -a -p $$ -d 1 -F pn | sed -n '2s/.//p')
.請注意,文件名可能並不總是存在,尤其是在文件已被刪除的情況下。
在 Linux 下,訪問文件名的另一種方法是通過
/proc/$$/fd
:/proc/$$/fd/1
是一個稍微神奇的符號連結,指向 shell 在文件描述符 1 上打開的文件(即使返回的文件名readlink
不存在,該連結也有效,例如在刪除文件的情況)。利用這種方式獲得的資訊通常是一個非常糟糕的主意。如果有人呼叫您的腳本並將輸出重定向到文件,如果您因文件的位置而表現不同,或者以附加到文件以外的方式影響文件,他們將不會喜歡它。有一個例外:您可能希望根據您是在寫入終端還是其他東西(管道、套接字、文件)做出不同的反應,例如在終端上顯示顏色或進度指示器。有一個特定的測試來確定文件描述符是否連接到終端:
if [ -t 2 ]; then # stderr is a terminal printf 1>&2 '\e[31mError: widget not found\e[0m' else # stderr is not a terminal echo 1>&2 'Error: widget not found' fi
{ readlink /dev/fd/[1,2] ; echo "out" ; } >./file 2>./error { readlink /dev/fd/0 ; cat ; } <./file
輸出:
/home/mikeserv/file /home/mikeserv/file /home/mikeserv/error out { readlink /proc/$$/fd/[1,2] ; echo out ; } >./file 2>./error { readlink /proc/$$/fd/0 ; cat ; } <./file
輸出:
/home/mikeserv/file /home/mikeserv/file /home/mikeserv/error out