了解破折號中的管道和重定向
有人問如何將兩個命令的輸出作為文件傳遞給另一個命令,他們得到了下面的答案。
( cmd1 | ( cmd2 | ( main_command /dev/fd/3 /dev/fd/4 ) 4<&0 ) 3<&0 )
我需要打開這個。
假設我有一個文本文件
some_file
,我希望將其作為輸入傳遞給main_command
.main_command
將兩個文件作為輸入。如果我想與命令的輸出一起使用main_command
,some_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。
這是一個相當複雜的命令。我已經在最後直接回答了你的問題,但在那之前所有這一切都是在解壓命令本身。我試圖做到全面,所以在某些地方可能會有比你需要的更多的細節。
**括號創建一個子**shell :
( x y z )
表示從目前的 shell 派生一個新的 shell,在其中執行
x y z
(然後返回到目前 shell)。子外殼繼承了目前外殼的所有內容,但它是一個單獨的程序:這意味著它可以將輸入通過管道傳輸到其中,並且可以在內部進行不影響父外殼的自己的環境更改。每個打開的文件都有一個與之關聯**的數字“文件描述符” 。**在此上下文中的“文件”包括任何類型的輸入或輸出流,包括真實文件、套接字和標準 I/O 流。這些數字是句柄,可以直接與C
read
函式一起使用,以辨識您正在談論的流,以及作業系統提供的相應系統呼叫以及所有其他 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
然後有三個主要部分:
- 執行
cmd2
並將其輸出通過管道傳輸到( main_command /dev/fd/4 ) 4<&0
.- 為由(標準輸入) of
4
標識的流命名。0``( main_command /dev/fd/4 )
- 作為參數執行
main_command
,/dev/fd/4
它將(可能)作為文件打開並從中讀取,得到cmd2
.最後的效果是
main_command
獲得一個路徑名參數,它可以打開並讀取cmd2
from 的輸出,就像 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,另一個是輸出ofcmd2
,在通過管道進入最裡面的子殼後被放入 FD 4。這兩個0
s 都指標準輸入,但每個命令的標準輸入是不同的,因為我們有不同的東西通過管道輸入。我認為這是問題中最令人困惑的部分。每個命令(這裡是每個子shell)都有自己的標準輸入,從
cmd1
or管道輸入cmd2
,並且唯一的標準輸入流被別名為3
or4
。那些打開的文件描述符被下一層的子shell和子命令繼承,所以/dev/fd/3
在最裡面的命令指的是它在外面做的同樣的事情,即使標準輸入現在指向別的東西。外括號不是嚴格要求的,儘管它們使某些命令更加健壯,並且可能是一個好習慣。內部是:那些用於創建一個新的子程序,該子程序可以在其中擁有自己的一組重定向,並通過管道輸入自己的標準輸入流。
最裡面的重定向實際上是多餘的:
cmd2 | main_command /dev/fd/3 /dev/stdin
也可以工作,因為沒有對標準輸入進行進一步的更改。直接解決您的問題:
- >
如何解壓問題開頭的命令?
開箱是到目前為止的整個文章。 2. >
括號有什麼作用?
括號創建一個子shell,一個獨立的shell程序,可以像任何其他命令一樣使用,包括將輸入通過管道輸入,但可以在內部執行普通的shell操作,例如重定向。 3. >
我對更簡單命令的解釋是否正確?
部分。
4<&0
說文件描述符 4 將指向標準輸入,重要的是現在稱為標準輸入- 而不是標準輸入的概念。/dev/fd/4
是“一切都是文件意義”中的“文件”,但更具體地說,它是一個路徑名,當打開它時,它會將您的 FD 4 交還給您。