Bash

管道後的多個命令和子shell執行

  • March 15, 2020

好的,我知道在 Bash 中(預設情況下,沒有啟用 ’lastpipe’ bash 選項)在管道之後分配的每個變數實際上都在子shell中執行,並且變數本身在子shell執行後死亡。它對父程序不可用。但是做了一些測試,我想出了這種行為:

A) 第二條命令 (a=2) 賦值並返回:

[root@centos01]# a=1; a=2; a=10 | echo $a
2

B)第三條命令(a=10)賦值並返回:

[root@centos01]# a=1; a=2; a=10; a=20 | echo $a
10

C)第四條命令(a=20)賦值並返回:

[root@centos01]# a=1; a=2; a=10; a=20; touch fileA.txt | echo $a
20

所以:

  • 為什麼總是沒有實際執行命令序列中的最後一個變數賦值?(或者如果是,為什麼它沒有被 subshel​​l 擷取並由 echo 命令返回?)
  • 在測試 C 中,“touch”命令實際上在目錄中創建了文件“fileA.txt”。那麼,為什麼在步驟 A 和集合 B 中進行的變數賦值序列中的最後一個命令不起作用?有誰知道這方面的技術解釋?

首先,要就幾個名稱達成一致,以下是 shell 解釋您的輸入的方式:

$ a=1; a=2; a=10 | echo $a
 ^^^  ^^^  ^^^^^^^^^^^^^^
   \    \         \_ Pipeline
    \    \_ Simple command
     \_ Simple command

管道由兩個簡單的命令組成:

$ a=10 | echo $a
 ^^^^   ^^^^^^^
    \       \_ Simple command
     \_ Simple command

(請注意,雖然 Bash 的手冊中可能沒有明確說明,但POSIX shell 語法允許一個簡單的命令僅由變數賦值構成)。

a=1;並且a=2;不屬於任何管道。A;將終止管道,除非作為複合命令的一部分出現。例如:

{ a=1; a=2; a=10; } | echo $a

在您的範例中,a=10並且echo $a兩個不同的、獨立的子shell 環境1中執行,它們都作為主環境的副本創建。子shell 不得改變其父執行環境2。引用相關的POSIX 部分

應創建一個子外殼環境作為外殼環境的副本

$$ … $$對子外殼環境所做的更改不應影響外殼環境。

此外,多命令管道的每個命令都處於子shell環境中;然而,作為擴展,管道中的任何或所有命令都可以在目前環境中執行。所有其他命令都應在目前 shell 環境中執行。

因此,雖然您的範例中的所有命令都已實際執行,但管道左側部分的分配沒有明顯的效果:它們只會更改a各自子 shell 環境中的副本,這些副本會在子 shell 終止後立即失去。

管道兩端的子shell 可以直接相互互動的唯一方法是通過管道本身——左側的標準輸出連接到右側的標準輸入。由於a=10不會通過管道發送任何內容,因此它無法影響echo $a.


1 如果lastpipe設置了該選項(預設關閉,可以使用shopt內置啟用),Bash 可能會在目前 shell 中執行管道的最後一條命令。請參閱Bash 手冊中的管道。但是,這與您的問題無關。

2 您可以從 U&L 的實際/歷史角度找到更多詳細資訊,例如,在此答案中,為什麼 POSIX shell 腳本管道中執行的最後一個函式不保留變數值?

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