Bash

理解“流程替代”的概念

  • March 20, 2021

我尋求一個針對一般受眾/非專業系統管理員的術語“流程替換”的簡單解釋,他們偶爾為個人項目進行伺服器環境維護,而不是每天為客戶或公司進行維護,如果可以在這裡提出要求的話。

  • 發明這個概念是為了解決什麼問題
  • 什麼過程被替換了,用什麼(名稱可能會誤導)?
  • 它是否也被命名為“保留標準輸入”,如果是,為什麼?如果標準輸入設備擁有可以通過管道傳輸到另一個命令的標準輸入,那麼還有什麼可以“保留”比這更進一步的呢?

這可能有助於我理解以下命令:

bash <(wget -O - URL)

新手注意: -O -告訴wget將數據寫入標準輸出;

重要事實:涉及兩個 shell

首先註意有兩個shell。您在其中工作的外部 Bash,您在bash <(wget -O - URL)其中呼叫(類型)。當命令執行時,內部 Bash 作為外部 Bash 的子程序執行。

換句話說,外部 Bash 接受bash <(wget -O - URL)命令並生成內部 Bash。我會在適當的地方區分這兩者。


重要事實:使用 Bash 執行程式碼的方法不止一種

有幾種方法可以讓(內部)Bash 執行一些程式碼:

  1. bash可以從它的標準輸入讀取程式碼:
echo 'date; sleep 2; date' | bash

標準輸入可以是控制台。例如,您通常工作的互動式bash從控制台讀取,但它實際上從其標準輸入讀取,因為控制台它的標準輸入。 2. bash可以從文件中讀取程式碼:

bash /path/to/some/file

(路徑可能是相對的。) 3. bash可以從命令行參數讀取程式碼:

bash -c 'date; sleep 2; date'

上下文

在評論中你說上下文是這個問題。我在那裡的回答建議更換:

wget -O - URL | bash

bash <(wget -O - URL)

第一個命令bash從其標準輸入進行內部讀取。您似乎沒有意識到的是,第二個命令bash從不是其標準輸入的文件中進行內部讀取。


會發生什麼<(…)

當您bash <(wget -O - URL)在 Bash 中執行時,外部 Bash 將替換為某個文件<(…)的路徑。替換後,正在執行的實際命令可能如下所示:

bash /dev/fd/63

這會產生內部 Bash。它像打開/dev/fd/63一樣打開/path/to/some/file

多虧了程序替換的“魔力”,/dev/fd/63一個管道已經連接到wget -O - URL.

旁注:在/dev/fd不可用的系統上,外部 Bash 將使用真正命名的管道(例如/tmp/sh-np.pldKay)來設置它。


相似度

在這兩種情況下,從wget到(內部)的連接bash是相似的。當你執行時wget -O - URL | bashbash從它的標準輸入讀取程式碼,這是一個管道wget寫入。當您執行時bash <(wget -O - URL)bash從另一個文件(即不是從其標準輸入)讀取程式碼,該文件是管道wget寫入的。在這兩種情況下,外部 Bash 都會設置管道。


區別

不同之處在於程序替換,內部 Bash 的標準輸入不用於將程式碼傳遞給它。標準輸入可以用於其他目的。例如,標準輸入可以是控制台,並且read在程式碼中可以從中讀取。


回答您的明確問題

  • >

發明這個概念是為了解決什麼問題

當命令需要路徑名(文件的路徑)並且您想通過管道輸入內容而不是提供正常文件時,您可以創建命名管道並實現目標。這需要實際創建一個管道 ( mkfifo),向它輸送一些東西(在後台或另一個控制台中),執行命令並最終刪除命名管道 ( rm)。

使用程序替換,Bash 處理管道。這很方便。

  • >

什麼過程被取代,用什麼代替?

在語法中替換為某個文件的路徑,然後才執行命令(並且它是bash <(wget -O - URL)或類似的)。外部 Bash 準備文件,因此從它讀取意味著讀取(程序)寫入的內容。該文件實際上是一個管道,而不是正常文件。<(wget -O - URL)``bash /dev/fd/63``wget -O - URL

  • >

它是否也被命名為“保留標準輸入”,如果是,為什麼?

“保留標準輸入”發生了,但它不是程序替換的替代名稱。這也不是發生的事情的正式名稱。

當您bash …在(外部)Bash 中執行(內部)時,內部 Bash 會從外部 Bash 繼承其標準輸入(即,它是同一個文件)。標準輸入可能是控制台。

但如果你wget … | bash …改為執行,內部 Bash 將看到來自wget它自己的標準輸入的數據。現在,內部 Bash 的某些部分(例如read builtin)或內部 Bash 的某些子項可能想要從標準輸入中讀取某些內容。他們期望來自控制台或其他什麼的輸入,而不是內部 Bash 應該執行的程式碼。但是因為內部 Bash 的標準輸入是來自的管道wget,所以內置程序將使用它,子程序將繼承它作為他們的標準輸入。他們不會繼承外部 Bash 的標準輸入。

通過 (inner) 的標準輸入使用程序替換而不是管道程式碼bash,您可以使外部 Bash 的標準輸入可用於內部 Bash 的內置函式和子級。您為內部 Bash 的內置函式和子級保留外部 Bash 的標準輸入。同時,您可以保護內部 Bash 讀取和執行的程式碼流不被其內置程序或子程序讀取。

這僅是因為bash允許您在指定為命令行參數的文件中提供程式碼。如果(內部)Bash 僅支持從標準輸入讀取程式碼,那麼您必須通過其標準輸入提供程式碼。在這種情況下,程序替換無法解決您遇到的問題

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