管道後的多個命令和子shell執行
好的,我知道在 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
所以:
- 為什麼總是沒有實際執行命令序列中的最後一個變數賦值?(或者如果是,為什麼它沒有被 subshell 擷取並由 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 腳本管道中執行的最後一個函式不保留變數值?