Shell

了解破折號中的管道和重定向

  • June 12, 2019

有人問如何將兩個命令的輸出作為文件傳遞給另一個命令,他們得到了下面的答案

( cmd1 | ( cmd2 | ( main_command /dev/fd/3 /dev/fd/4 ) 4<&0 ) 3<&0 )

我需要打開這個。

假設我有一個文本文件some_file,我希望將其作為輸入傳遞給main_command. main_command將兩個文件作為輸入。如果我想與命令的輸出一起使用main_commandsome_file一種cmd2方法是

( cmd2 | ( main_command some_file /dev/fd/4 ) 4<&0 )
  • 這其中“最深”的部分(即一切達到高潮的地方)是 main_command some_file /dev/fd/4. 這只是將文件 some_file/dev/fd/4作為參數傳遞給main_command.
  • 4<&0部分錶示stdin將指向文件描述符4
  • cmd2 |將 的輸出cmd2與後面的任何內容的輸入連接起來。
  • 我真的不知道括號的功能是什麼。它們只是為了解析目的而存在還是更多?

我的問題是:

  1. 如何解壓問題開頭的命令?
  2. 括號有什麼作用?
  3. 我對更簡單命令的解釋是否正確?

編輯:我應該說如果我的邏輯是正確的,那麼沒有必要回答 1。

這是一個相當複雜的命令。我已經在最後直接回答了你的問題,但在那之前所有這一切都是在解壓命令本身。我試圖做到全面,所以在某些地方可能會有比你需要的更多的細節。

**括號創建一個子**shell

( x y z )

表示從目前的 shell 派生一個新的 shell,在其中執行x y z(然後返回到目前 shell)。子外殼繼承了目前外殼的所有內容,但它是一個單獨的程序:這意味著它可以將輸入通過管道傳輸到其中,並且可以在內部進行不影響父外殼的自己的環境更改。

每個打開的文件都有一個與之關聯**的數字“文件描述符” 。**在此上下文中的“文件”包括任何類型的輸入或輸出流,包括真實文件、套接字和標準 I/O 流。這些數字是句柄,可以直接與Cread函式一起使用,以辨識您正在談論的流,以及作業系統提供的相應系統呼叫以及所有其他 IO 函式。

4<&0 執行重定向,將標準輸入文件描述符 (0) 複製為文件描述符 4。這意味著FD 0 被複製到 4,而不是相反。在這種情況下,它正在修改重定向之前的子 shell 的打開文件。目前,這只是為輸入流創建另一個“名稱”。但關鍵部分是這兩個名稱此後相互獨立:FD 4 將始終引用同一個流,即使 FD 0 更改為引用其他內容並且兩者不同。

/dev/fd/4是程序訪問自己打開的文件描述符的一種(非標準)方式。在 Linux 上,它是一個指向 的符號連結/proc/self/fd,它具體化了目前程序的文件描述符表。一個程序open("/dev/fd/4", O_RDONLY)可以獲得一個文件句柄,該句柄引用該程序在 FD 4(例如它4自己)上的流。就程序而言,這只是一個可以像任何其他文件一樣打開、關閉和讀取的正常文件。因為打開的文件描述符是由子main_command程序繼承的,所以文件描述符 4 與它所在的子 shell 相同,因此/dev/fd/4也可以在那里工作。

cmd2 | x執行cmd2,並將其標準輸出連接到標準輸入(或 FD 0)x。在您的命令中,x是子shell 表達式。


我們的總體指揮

cmd2 | ( main_command /dev/fd/4 ) 4<&0

然後有三個主要部分:

  1. 執行cmd2並將其輸出通過管道傳輸到( main_command /dev/fd/4 ) 4<&0.
  2. 為由(標準輸入) of4標識的流命名。0``( main_command /dev/fd/4 )
  3. 作為參數執行main_command/dev/fd/4它將(可能)作為文件打開並從中讀取,得到cmd2.

最後的效果是main_command獲得一個路徑名參數,它可以打開並讀取cmd2from 的輸出,就像 Bash 程序替換會發生的那樣main_command <(cmd2):事實上,這可能會/dev/fd/63作為參數給出,否則在內部進行非常相似的處理。


對於完整的命令

( cmd1 | ( cmd2 | ( main_command /dev/fd/3 /dev/fd/4 ) 4<&0 ) 3<&0 )

我們有嵌套的子shell:那是因為我們想要製作標準輸入的兩個副本,但它是兩個不同的標準輸入:一個是 的輸出cmd1,它在通過管道進入更大的子shell 後被放入 FD 3,另一個是輸出of cmd2,在通過管道進入最裡面的子殼後被放入 FD 4。這兩個0s 都指標準輸入,但每個命令的標準輸入是不同的,因為我們有不同的東西通過管道輸入。

我認為這是問題中最令人困惑的部分。每個命令(這裡是每個子shell)都有自己的標準輸入,從cmd1or管道輸入cmd2,並且唯一的標準輸入流被別名為3or 4。那些打開的文件描述符被下一層的子shell和子命令繼承,所以/dev/fd/3在最裡面的命令指的是它在外面做的同樣的事情,即使標準輸入現在指向別的東西。

外括號不是嚴格要求的,儘管它們使某些命令更加健壯,並且可能是一個好習慣。內部是:那些用於創建一個新的子程序,該子程序可以在其中擁有自己的一組重定向,並通過管道輸入自己的標準輸入流。

最裡面的重定向實際上是多餘的:cmd2 | main_command /dev/fd/3 /dev/stdin也可以工作,因為沒有對標準輸入進行進一步的更改。


直接解決您的問題:

  1. >

如何解壓問題開頭的命令?

開箱是到目前為止的整個文章。 2. >

括號有什麼作用?

括號創建一個子shell,一個獨立的shell程序,可以像任何其他命令一樣使用,包括將輸入通過管道輸入,但可以在內部執行普通的shell操作,例如重定向。 3. >

我對更簡單命令的解釋是否正確?

部分。4<&0說文件描述符 4 將指向標準輸入,重要的是現在稱為標準輸入- 而不是標準輸入的概念。/dev/fd/4是“一切都是文件意義”中的“文件”,但更具體地說,它是一個路徑名,當打開它時,它會將您的 FD 4 交還給您。

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