Bash 單命令列解釋(3)--重定向

acHao發表於2019-12-27

這是翻譯系列文章的第3篇,參考原文連結
翻譯的系列文章列表:

  1. Bash 單命令列解釋,第一部分:檔案操作
  2. Bash 單命令列解釋,第二部分:字串操作
  3. Bash 單命令列解釋,第三部分:重定向(本篇)

這是 Bash One-Liners Explained 系列文章的第3篇。本文中將講授 輸入/輸出重定向 。我將利用 bash 最佳實踐,多變的 bash 方言和 bash 命令技巧,展示僅利用 bash 內建命令和外部程式命令構建命令流完成各種各樣的任務需求。

參見系列文章的第一篇 Bash 單命令列解釋,第一部分:檔案操作 瞭解我的初衷。若這個系列文章完成後,我將放出其同名的電子書。正如我創作的其它系列文章-- awksedperl 一樣,我的電子書 有 pdf 格式及方便在手機上看的格式(mobi 和 epub)。同時,像 perl1line.txt 一樣,也有純文字 txt 格式的文件。

也可參考我其它的高效使用 bash 的系列文章:

開始學習

第三部分:重定向

當你理解了 檔案描述符(file descriptors) 的操作,將會覺得使用 bash 的重定向非常簡單。當 bash 啟動時,它將預設開啟 3 個標準檔案描述符 :stdin(0號檔案描述符)stdout(1號檔案描述符)stderr(2號檔案描述符) 。你可以開啟更多的檔案描述符(諸如:345 ...),也可以關閉它們,你可以拷貝檔案描述符 ,也可以從它那裡讀或寫入到它。

檔案描述符 總是指向某些檔案(除非檔案被關閉)。通常,bash 啟動時會把3個標準檔案描述符:stdin,stdout,stderr 通通指向終端。輸入(stdin)來自終端的鍵入內容,所有的輸出(stdout,stderr)顯示在終端裡。

假定你的終端是 /dev/tty0 ,下面是終端標準檔案描述符之間的關係示意圖:

當 Bash 執行一條命令時,它會 分支(fork) 一個子程式,這個子程式繼承 fork 它的父程式的一切標準檔案描述符(關於 fork ,詳情參考手冊命令 man 2 fork )。首先按照命令列指示進行 重定向輸入/輸出 後才 執行(exec) 命令(關於 exec ,詳情參考手冊命令 man 3 exec)。

對於想 bash 重定向 操作進階的你,永遠心中有個藍圖 -- 當重定向發生時,標準檔案描述符如何變化 --,這個藍圖將極大地幫助到你。

1. 重定向標準輸出到一個檔案

$ command >file

符號 > 是輸出重定向操作符。bash 先嚐試開啟重定向指向的檔案(這裡是檔案 file)並可寫入,如果成功,Bash 將 command 命令子程式的標準輸出檔案描述符指向開啟的檔案。如果失敗,整個命令失敗退出,結束子程式。

命令列 command >file 等同於命令列 command 1>file 。數字 1 代表 stdout,它是標準輸出檔案描述符 stdout 的檔案描述符號。

下面是標準檔案描述符改變的藍圖示意。Bash 開啟檔案 file 並確定可寫入後,替換子程式的標準輸出檔案描述符1file 檔案的檔案描述符,自此,命令的所有輸出將寫入檔案 file 中。

通常,你可使用形如 "command n>file" 的命令,表示此命令的 n 號標準輸入/輸出檔案描述符指向 file

舉例:

$ ls > file_list

重定向 ls 命令的輸出到 file_list 檔案(命令的輸出寫入到檔案)。

2. 重定向命令的標準錯誤輸出到檔案

$ command 2> file

這裡,將命令的標準錯誤輸出(stderr 號 2)檔案描述符重定向到檔案。這裡的數字 2 代表標準錯誤輸出檔案描述符。

下面是標準檔案描述符表改變藍圖:

Bash 開啟檔案 file 並確定可寫入後,替換子程式的標準錯誤輸出檔案描述符2file 檔案的檔案描述符,自此,命令的所有錯誤輸出由原來寫入 stderr 中改寫入檔案 file 中。

3. 重定向標準輸出和標準錯誤輸出到檔案

$ command &>file

上面這行命令中 "&>" 表示把所有的標準輸出檔案描述符(stdoutstderr )重定向到 file 檔案描述符。&> 是 Bash 快速引用所有標準輸出描述符(12)的簡寫。

下圖是標準檔案描述符改變示意圖:

這裡你看到所有的標準輸出( stdout 和 stderr )都指向 file 檔案的檔案描述符。

有不同的幾個方法將所有標準輸出重定向到一個目標。可以按順序一個接一個地重定向:

$ command >file 2>&1

上面命令是較通用的重定向所有標準輸出到檔案的方法。首先,標準輸出(stdout)重定向到 file 檔案(這步是先執行 ">file" 的結果)。之後,標準錯誤輸出(stderr)重定向到 已重定向過的 stdout(&1) 上 (通過 "2>&1") 。因此,所有的標準輸出都重定向到 file 上。

Bash 在命令列解析時,發現有多個重定向操作時,按從左到右的順序依次解釋處理。讓我們按 Bash 執行順序,單步分析,更好地理解它。一開始,Bash 在執行命令前,其3個標準輸入/輸出檔案描述符都指向終端。示意圖如下:

首先,Bash 處理第一個重定向 ">file" 。之前,我們見過這個示意圖。它的標準輸出(stdout)指向終端:

下一步解釋處理重定向操作 "2>&1",這個操作的含義是使標準錯誤輸出檔案描述符(stderr 號 2)成為 1號標準輸出檔案描述符(stdout)的副本(重定向 2 到 1 的當前引用)。我們得到如下示意圖:

所有的標準輸出描述符都重定向到 file 檔案。

然而,小心不要把 command >file 2>&1 寫成 command 2>&1 >file ,它們是不同的!

Bash 對重定向指令的順序敏感!後一命令僅僅把標準輸出1(stdout) 重定向到 file 檔案,而 標準輸出2(stderr) 仍然輸出到終端。理解為什麼,讓我們再進行單步分析,看看發生了什麼。初始示意圖如下:

Bash 從左到右一步步處理重定向,首先遇到 "2>&1" ,因此將 2 (stderr) 重定向與 1(stdout) 相同,即都指向終端,示意圖如下:

現在,Bash 看到第2個重定向操作符 ">file" ,它重定向 1(stdout) 到 file 檔案,示意圖如下:

看到了什麼,1(stdout) 重定向到了 file 檔案,但 2(stderr) 仍指向終端,所有寫到 stderr 的都顯示到螢幕。所以,在使用重定向時,要非常非常小心給出它的操作循序!

另外在 Bash 中要注意:

$ command &>file

操作含義,與下面命令形式完全相同:

$ command >&file

但推薦第一種形式寫法。

4. 捨棄命令的螢幕輸出

$ command > /dev/null

特殊檔案 /dev/null 拋棄所有寫入它的內容(譯註:可認為 /dev/null 是一個大小恆為0的檔案,向它寫入任何內容,它都會將它清空,保持檔案大小為 0 。把它拷貝覆蓋已有檔案的動作也是把檔案內容清空的方法)。下面是標準檔案描述符示意圖:

類比地,組合之前學過的命令,我們可以捨棄命令的輸出和錯誤輸出,命令如下:

$ command >/dev/null 2>&1

或簡寫成:

$ command &>/dev/null

相應的標準輸入輸出描述符示意圖如下:

5. 重定向檔案內容作為命令的輸入

$ command <file

這裡, Bash 在執行命令前,試圖開啟 file 檔案並可讀。若開啟檔案失敗,命令失敗退出。若開啟讀取檔案成功,將使用開啟的檔案描述符作為命令的標準輸入描述符(stdin 號 0)。

上述動作完成後的標準輸入輸出描述符表示意圖如下:

下面是個例子,假定你想從 file 中讀取其第1行賦值給變數,命令如下:

$ read -r line < file

Bash 的內建命令 read 從標準輸入讀取單行資料。 使用輸入重定向操作符 < 使它從 file 檔案中讀取第1行資料。

6. 重定向多行文字到命令的輸入

$ command <<EOL
>你
>多行
>文字
>輸入
>到這兒
>EOL不是唯一文字
>  EOL
>EOL

這裡,我們使用 即入文件(here-document) 重定向操作符 "<<MARKER" 的功能。這個操作指示 bash 從標準輸入(stdin 0)讀取多行輸入,直到某行(最後一行)只包含 MARKER 且無前導空白即退出輸入。最後一行的終止輸入標誌不會附加到輸入中。將最終的多行輸入給命令。

下面是個一般的例子。假設你拷貝了一堆的網上的網址(URLs)在系統剪貼簿裡,你想去掉所有的字首 http:// ,快速的單行命令如下:

$ sed 's|http://||' <<EOL
http://url1.com
http://url2.com
http://url3.com
EOL

這裡使用即入文件重定向符,將多行網址記錄輸入給 sed 命令,"sed" 命令使用正規表示式將所有行記錄中的 http:// 刪除。

以上例子輸出:

url1.com
url2.com
url3.com

7. 重定向單行字串文字到命令輸入

$ command <<< "foo bar baz"

舉個例子,假如你想系統剪貼簿裡的文字當作某個命令的輸入(文字是命令的引數或選項),可能的辦法是:

$ echo "粘帖剪貼簿內容" | command

現在你可以使用下面命令:

$ command <<< "粘帖剪貼簿內容"

當我學會這個技巧,它改變了我的人生!

8. 重定向所有的錯誤輸出到一個檔案

$ exec 2>file
$ command1
$ command2
$ ...

上述第一個命令列使用了 Bash 內建命令 exec 的功能,如果使用它重定向了標準輸入輸出(演示中是 2 號標準輸出 stderr ),它在本 shell 中永久有效!除非你再次修改它或退出這個 shell 。

例子中,使用 exec 2>file 命令將 2 號標準輸出(stderr)重定向到 file 檔案。之後,在這個 shell 環境裡所有命令的標準錯誤輸出都重定向到 file 檔案中。這是非常有用的一個技巧。當你想把所有命令或指令碼中的執行記錄到一個日誌檔案裡,而又不想在每條命令中都繁瑣地輸入重定向操作。

概括地講,exec 命令的主要功能是不建立子程式地呼叫一個 bash 命令或指令碼並執行,若命令列中指定了命令或指令碼,當前 shell 將被替換。我們演示的命令,在 exec 後並未給出任何命令,這僅僅利用了 exec 的執行重定向的功能,並無 shell 被替換。(譯註:個人覺得 exec 是個較分裂的命令。推薦參考這個 連結 中對 exec 命令的解釋。或直接看這個 AskUbuntu 中的回答)

9. 建立使用者的檔案描述符做為自定義的輸入描述符

$ exec 3<file

這裡,我們再次使用 exec 命令進行重定向的設定,指定 3<file 的意思是開啟 file 檔案可讀取,並將其分配給當前 shell 的 3 號輸入檔案描述符。當前 shell 的輸入輸出檔案描述符示意圖如下:

現在就可以從3號輸入檔案描述符讀取,如下命令:

$ read -u 3 line

上面的命令從 3 號輸入檔案描述符(重定向到 file 檔案)中讀取。

或用常規命令,諸如 grep 操作3號輸入檔案描述符:

$ grep "foo" <&3

這裡,3號輸入檔案描述符通過重定向代替了 grep 命令的預設 stdin 輸入。一定要記住,資源有限,故使用完使用者自開啟的檔案描述符後,要及時關閉它,釋放描述符號。可以再次使用。

使用完3號檔案描述符後,可以關閉它,使用如下命令:

$ exec 3>&-

這裡似乎3號檔案描述符被重定向給 &- 實際上,&- 就是 關閉這個檔案描述符 的一種語法。

10. 建立使用者的檔案描述符做為自定義的輸出描述符

$ exec 4>file

這裡,簡單地指示 bash 開啟可寫 file 檔案,並將其檔案描述符重定向成為4號輸出描述符。當前 shell 的輸入輸出檔案描述符示意圖如下:

正如你在上圖所見,輸入輸出檔案描述符並未按順序來,使用者可自由指定 0 只 255 之間的數字做為自定義開啟的檔案描述符號。

現在,簡單往4號輸出檔案描述符中寫入:

$ echo "foo" >&4

同樣,可以關閉4號輸出檔案描述符:

$ exec 4>&-

學會使用自定義輸入輸出檔案描述符,一切都是那麼簡單!

11. 開啟檔案用於讀寫

$ exec 3<>file

這裡使用 bash 的菱形操作符 <> ,菱形操作符開啟 file 檔案用於讀寫。

所以,可以執行如下例子:

$ echo "foo bar" > file   # 將字串  "foo bar" 寫入 file 檔案。
$ exec 5<> file           # 以讀寫方式開啟 file 檔案並重定向到5號描述符
$ read -n 3 var <&5       # 從5號輸入輸出描述符中讀取前3個字元。
$ echo $var

上面最後命令將輸出 "foo" ,只讀出前3個字元。

也可寫一些內容到 file 檔案:

$ echo -n + >&5           # 在檔案中第4字元位置寫入 "+"
$ exec 5>&-               # 關閉5號檔案描述符
$ cat file

上面會輸出 foo+bar 。(譯註:實踐發現以永久重定向檔案描述符讀寫檔案,會保持讀寫位置)

12. 多個命令輸出重定向到檔案

$ (command1; command2) >file

上面例示使用 (commands) 執行命令操作,其中 bash 會將 () 中的命令在一個建立的子程式中執行。

所以這裡的 command1command2 執行在當前 shell 的子程式,同時,bash 將他們的輸出重定向到 file 檔案。

13. 通過檔案 shell 之間傳遞命令執行

開啟2個 shell 模擬終端,在第1個 shell 中,輸入命令:

$ mkfifo fifo
$ exec < fifo

在第2個 shell 中,輸入命令:

$ exec 3> fifo; echo 'echo test' >&3

現在看第1個 shell ,發現 echo test 命令執行輸出在第1個 shell 裡。你可以在第2個 shell 中傳送命令字串給3號描述符的方式給第1個 shell 傳送命令。

下面講解它是如何做到的。

在 shell 1 中,使用 mkfifo 建立 命名管道 -- fifo 。一個命名管道(也稱為 FIFO)性質與一般的管道相同,除了它是通過系統檔案系統訪問之外(建立命名管道將會在當前目錄下建立一個以命名管道名命名的檔案,這個檔案第一個屬性為 p 表示它為一個 管道(pipe),並且檔案大小始終顯示為 0)。它可供多程式讀寫(可供程式間通訊)。當程式間通過 FIFO --命名管道--交換資料時,系統核心並不會把資料寫入檔案儲存系統。因此,命名管道檔案大小永遠為 0 。僅僅把檔案系統中的檔名做為程式引用它的一個名稱罷了。

下一命令 exec < fifo 重定向 shell 1 的輸入為 fifo

接著,shell 2 重定向這個命名管道做為使用者輸出檔案描述符,並分配號為 3 。然後給 3 號輸出傳送字串 echo test ,這將傳給 fifo 檔案。

因此,shell 1 連線到 fifo 的標準輸入進入 shell 1 命令列並執行!很容易吧!

(譯註:原理很簡單,自己開兩個shell 去實踐練習一下。別的不多說,只提醒一點:當 shell 1 把自己的標準輸入重定向成命名管道之後,它就不能接受它自己終端的輸入了。如何恢復它回到原始的輸入?2個辦法,1.是重定向前備份。2.是使用它原始的名稱恢復,提示:輸入僅可用 /dev/tty 。至於怎樣讓它執行命令?自己想想,你棒棒噠!)

14. 通過 bash 訪問網站

$ exec 3<>/dev/tcp/www.bing.com/80
$ echo -e "GET / HTTP/1.1\n\n" >&3
$ cat <&3

Bash 處理 /dev/tcp/host/port 作為特殊檔案。它不需要在你的檔案系統中存在。這個只為 Bash 通過它開啟指定主機的網路介面。

以上例子,首先開啟可讀寫3號輸入輸出檔案描述符指向 /dev/tcp/www.bing.com/80 ,它將連結到 www.bing.com 網站的埠 80 。

下一步,向3號檔案描述符寫入 'GET / HTTP/1.1\n\n' (傳送HTTP請求),然後使用 cat 命令簡單讀取3號檔案描述符的內容。

類似地,你可以通過 /dev/udp/host/port 建立特殊檔案用於 UDP 連線。

使用 /dev/tcp/host/port 的方法,你甚至可以在 Bash 中寫出埠掃描的命令或指令碼!

(譯註:原文示例使用的是谷歌,我這裡換成了必應。實驗了一下,可能由於現在網站都使用 SSL 的緣故,第一次會獲得一個包含錯誤提示的 HTTP 響應內容,連線就關閉了)

15. 當重定向輸出時阻止寫入已有檔案

$ set -o noclobber

上面的命令開啟當前 shell 的 noclobber 選項。這個選項阻止當前 shell 使用重定向 '>' 操作覆蓋寫入已有的檔案。

如果你輸出重定向的檔案是一個已有檔案,將會得到一個錯誤提示:

$ > exFile
$ echo test > exFile
bash: exFile: cannot overwrite existing file
#bash: exFile: 不能覆寫已有檔案

如果你完全確定就是要覆蓋寫入已有檔案,可以使用 >| 重定向符:

$ echo test >| exFile
$ cat exFile
test

這個操作符成功超越 noclobber 選項。

16. 將輸入重定向到一個檔案和輸出到標準輸出

$ command | tee file

這個 tee 命令超級方便,雖然它不是 bash 的內建命令但很常用。它能把收到的輸入流輸出到標準輸出和一個檔案中。

如上例子,它將 command 命令的輸出分別輸出到 shell 螢幕和一個檔案。

下面是它工作原理示意圖:

17. 將一個處理程式(命令)的輸出重定向到另一個處理程式(命令)的輸入

$ command1 | command2

這是簡單的管道。我確定每個人都熟悉它。我放它到這裡只是為了教程的完整。僅僅提醒你,管道 的本質就是將命令 command1輸出 重定向到 command2 命令的 輸入

可以用圖示意如下:

上圖可見,所有到達 command1 標準輸出(1 stdout)的內容都被重定向到了 command2 的標準輸入(0 stdin)。

更進一步請參考手冊命令 man 2 pipe .

18. 傳送一個命令的標準輸出和標準錯誤輸出到另一命令程式

$ command1 |& command2

這個操作符在 bash 4.0 版本後出現。 |& 重定向操作符通過管道將 command1 命令的標準輸出和標準錯誤輸出都發到 command2 命令的標準輸入。

最新的 bash 4.0 版 的新功能未廣泛普及前,舊的,方便的方法是:

$ command1 2>&1 | command2

下面是標準輸入/輸出描述符 的變化示意圖:

前面的操作先將 command1 的 stderr(2) 重定向到 stdout(1) ,然後通過管道將標準輸出重定向到 command2 的標準輸入 stdin(0) 。

19. 為建立的檔案描述符賦名

$ exec {filew}>output_file
#譯註:引用命名檔案描述符,使用 &$ 如下命令:
$ echo test >&$filew    #譯者加的命令

命名檔案描述符 是 bash 4.1 版後的功能特性。以 {varname}>output_file 定義了名為 varname 的輸出檔案描述符到指定檔案。你可以通過其名稱、檔案描述符號正常使用它。Bash 在內部會給它分配一個空閒的檔案描述符號。(譯註:這個命令很容易和臨時重定向到一個檔案混淆!關於如何用其名稱引用它,我寫到上面的程式碼註釋裡。如何找到其檔案描述符號,參見譯註1.

20. 重定向操作的順序

你可以把重定向操作放到命令列的任何位置。看看下面3個例子,它們效果一樣:

$ echo hello >/tmp/example

$ echo >/tmp/example hello

$ >/tmp/example echo hello

喜歡上了 bash !

21. 交換標準 stdout 和 stderr

$ command 3>&1 1>&2 2>&3

這裡,首先將 stdout(&1) 複製一個副本 &3 --3號檔案描述符-- ,再使 stdout(&1) 成為 stderr(&2) -- 2號檔案描述符-- 的副本,最後使 stderr(&2) 成為 &3 的副本。這樣將 stdout 和 stderr 進行了交換。

讓我們用圖示展示每步過程。下面是命令開始時的檔案描述符狀態圖示:

然後,3>&1 重定向操作符指示,建立 3號輸出檔案描述符指向跟 &1 相同:

下一個1>&2 重定向操作符指示,將 1號標準輸出檔案描述符指向跟 &2 相同:

下一個2>&3 重定向操作符指示,將 2號標準輸出檔案描述符指向跟 &3 相同(即原始的 &1):

如果想關閉不再有用的好人 &3 --3號檔案描述符-- ,見如下命令:

$ command 3>&1 1>&2 2>&3 3>&-

之後的檔案描述符表示意如下:

如你所見,檔案描述符 1號 和 2號 已經交換。

22. 重定向 stdout 到一個程式,stderr 到另一程式

$ command > >(stdout_cmd) 2> >(stderr_cmd)

這行命令使用了重定向命令替換展開操作符 >() 。它將會執行 () 中的命令。而其標準輸入通過匿名管道連線到了 command 的標準輸出。接著下一個 >() 操作符將其標準輸入連線到了 command 的標準錯誤輸出。

對於上面的例子,第一個命令替換 >(stdout_cmd) 可能使 bash 返回 /dev/fd/60 檔案描述符。同時,第二個命令替換 >(stderr_cmd) 可能使 bash 返回 /dev/fd/61 檔案描述符。這2個檔案描述符由 bash 實時建立為等待讀取的命名管道。它們都等待某些命令程式往裡寫,以便它們讀取。

所以,上述命令展開後可能是這樣:

$ command > /dev/fd/60 2> /dev/fd/61

現在可看得清楚些, command 的 stdout 重定向到 /dev/fd/60 , stderr 重定向到 /dev/fd/61

command 輸出,內部程式 'stdout_cmd' 的命令執行將接受。當 command 的錯誤輸出,內部程式 'stderr_cmd' 的命令執行將接受。

23. 找出每個管道命令的退出碼

讓我們看一下幾個命令用管道串起來的例子,如下命令:

$ cmd1 | cmd2 | cmd3 | cmd4

你想找出這裡每個命令的退出狀態碼,該如何做?有沒有一個簡便的方法獲取每個命令的退出狀態碼,而不是 bash 簡單給出的最後一條命令的退出狀態碼。

Bash 的開發者想到了這點,他們加入了一個名為 'PIPESTATUS' 的陣列變數來保留管道命令流中每個命令的執行退出狀態碼。

陣列變數 PIPESTATUS 中的每個數字都對應於相應位置命令的退出狀態碼。下面是個例子:

$ echo 'men are cool' | grep 'moo' | sed 's/o/x/' | awk '{ print $1 }'
$ echo ${PIPESTATUS[@]}
0 1 0 0

上面例子中,命令 grep 'moo' 失敗,因此陣列變數 PIPESTATUS 中的第2個數為 1 。

建議

建議研究 bash 高手們的百科 演示重定向教程bash 版本進化.

歡迎指正

享受文中所說的方法和技巧使用的樂趣吧,並且讓我知道您的想法。也許我漏掉了什麼,非常樂意收到您的指正。

----------------------------------------

----------------------------------------

譯註

1. 如何發現當前 bash 的所有檔案描述符

以下內容,譯者受網文 Linux: Find All File Descriptors Used By a Process 啟發,針對在 bash 中發現其所有檔案描述符的任務進行創作。

一、找到當前 bash 程式 ID -- PID

方法1:使用檢視程式命令,如 ps 命令

語法:

ps aux | grep [程式名稱]

ps 命令,參考本站wiki ps 命令(檢視程式)
對於我們的情況,程式名稱 是 bash ,命令如下:

$ ps aux | grep bash

可能的輸出如下:

aman      7146  0.0  0.2  30748  5728 pts/4    Ss   09:42   0:00 bash
aman      7978  0.0  0.2  24432  5516 pts/18   Ss+  13:56   0:00 bash
aman      8022  0.0  0.0  15964   928 pts/4    S+   14:10   0:00 grep --color=auto bash

這裡,我專門開啟了2個 shell ,哪個是我們當前的 shell 呢?方法很多,使用 tty 命令找出當前的 tty 與上面的輸出對比。找到本 shell 的 PID 是 7146

方法2:使用 pidof 命令

語法:

pidof [程式名稱]

這個方法不適用同時開了多個 shell 的例子,但只有一個 shell 時會很簡單,如下命令:

$ pidof bash
7146

二、根據 bash 的 PID 找到其使用的所有檔案描述符

方法1:檢視 /proc/pid/fd 目錄

如下所示命令及輸出:

$ ls -l /proc/7146/fd
total 0
lrwx------ 1 aman aman 64 12月 27 09:42 0 -> /dev/pts/4
l-wx------ 1 aman aman 64 12月 27 09:42 1 -> /dev/pts/4
l-wx------ 1 aman aman 64 12月 27 09:42 10 -> /home/aman/test/nFD
lrwx------ 1 aman aman 64 12月 27 09:42 2 -> /dev/pts/4
lrwx------ 1 aman aman 64 12月 27 12:02 255 -> /dev/pts/4

我之前在這個 shell 下,使用 $ exec {FD1}> nFD 命令建立了一個永久命名檔案描述符重定向到了當前目錄下的 nFD 檔案。在這裡我們看見 bash 內部給它分配了檔案描述符號 10 。這樣,你在重定向輸出時就即可使用 &$FD1&10 都會輸出到 nFD 檔案。

我的執行示意如下:

$ echo 'line 1' >&10
$ echo 'line 2' >&$FD1   #這行命令與上行輸出到相同目的地
$ cat nFD
line 1
line 2
方法2:使用 lsof 命令

語法:

lsof -a -p {輸入PID}

lsof 命令,參考 ’ lsof command ' 。我的命令示意如下:

$ lsof -a -p 7146

輸出:

COMMAND  PID USER   FD   TYPE DEVICE SIZE/OFF   NODE NAME
bash    7146 aman  cwd    DIR    8,5     4096 178864 /home/aman/test
bash    7146 aman  rtd    DIR    8,5     4096      2 /
bash    7146 aman  txt    REG    8,5  1037528 134435 /bin/bash
bash    7146 aman  mem    REG    8,5   101200 265464 /lib/x86_64-linux-gnu/libresolv-2.23.so
...
...
...
bash    7146 aman    0u   CHR  136,4      0t0      7 /dev/pts/4
bash    7146 aman    1w   CHR  136,4      0t0      7 /dev/pts/4
bash    7146 aman    2u   CHR  136,4      0t0      7 /dev/pts/4
bash    7146 aman   10w   REG    8,5       16 178735 /home/aman/test/nFD
bash    7146 aman  255u   CHR  136,4      0t0      7 /dev/pts/4

見上面輸出倒數第二行,可知 nFD 檔案的重定向檔案描述符號為 10

相關文章