簡體   English   中英

為什么管道重置當前的工作目錄?

[英]Why pipe resets current working directory?

第一個腳本:

$ { mkdir dir; cd dir; pwd; } | cat; pwd;
./dir
.

第二個腳本:

$ { mkdir dir; cd dir; pwd; }; pwd;
./dir
./dir

為什么這個| cat | cat對當前目錄有影響嗎? 以及如何解決? 我需要第一個腳本完全像第二個腳本一樣工作。 我不希望cat將我當前的目錄更改回.

引自手冊

管道中的每個命令都在其自己的子shell中執行 (請參閱命令執行環境 )。

另請參閱分組命令

{}

  { list; } 

在花括號之間放置命令列表會導致列表在當前shell上下文中執行。 沒有創建子shell。

這不是管道返回到目錄,而是你已經使第一個命令(在分號之前)僅適用於cat命令。 你實際上是管道mkdir的子進程的輸出, cdpwd轉到cat進程。

例如: { mkdir dir; cd dir; pwd; } | cat; pwd; { mkdir dir; cd dir; pwd; } | cat; pwd;

首先擴展到兩個過程:1) { mkdir dir; cd dir; pwd; } | cat; { mkdir dir; cd dir; pwd; } | cat; 和2) pwd

第一個過程擴展為兩個過程, { mkdir dir; cd dir; pwd; } { mkdir dir; cd dir; pwd; } { mkdir dir; cd dir; pwd; } ,然后將其stdoutstdincat 當這兩個進程中的第一個完成並收集stdout ,它的子進程退出,就像cd從未發生過,因為cd只會影響它運行的進程的目錄pwd實際上從未改變$PWD ,它只是打印在stdin提供的內容。

要解決此問題(假設我了解您要執行的操作),我會將其更改為:

{ mkdir dir; cd dir; pwd; }; pwd; cd -

當你運行:

{ mkdir -p dir; cd dir; pwd; } | cat; pwd

要么

{ mkdir -p dir; cd dir; pwd; } | date

要么

{ mkdir -p dir; cd dir; pwd; } | ls

您正在子shell中的管道LHS上運行命令組,因此完成兩個命令(LHS和RHS)后, change dir 不會反映在當前shell中

但是當你運行時:

{ mkdir -p dir; cd dir; pwd; }; pwd;

之間沒有管道,因此花括號內的所有命令和花括號外的pwd 都在當前shell中運行,因此您將獲得更改的目錄。

PS:還要注意這一行:

( mkdir -p dir; cd dir; pwd; )

也不會更改當前shell中的當前目錄,因為方括號內的命令在子shell中執行,而花括號僅用於分組。

關於變量的管道命令的行為是實現定義的。

您碰巧使用bash選擇將每個組件放在后台shell中,因此cd效果在主shell中丟失。

你是否應該運行ksh選擇在當前shell中保留管道的最后一個元素,如果你把cd放在最后一個語句中,那么行為將是你期望的行為。

$ bash
$ { mkdir -p dir; cd dir; pwd; } | { cat; mkdir -p dir; cd dir; pwd ; } ; pwd;
/tmp/dir
/tmp/dir
/tmp
$ ksh
$ { mkdir -p dir; cd dir; pwd; } | { cat; mkdir -p dir; cd dir; pwd ; } ; pwd;
/tmp/dir
/tmp/dir
/tmp/dir

管道不會重置當前工作目錄。 管道在管道的每一側以bash形成子殼。 子shell也不會重置當前工作目錄。 子shell包含對環境本身的更改,並且不會將它們傳播到父shell。

在你的第一個腳本中:

$ { mkdir dir; cd dir; pwd; } | cat; pwd;

cd在管道的左子shell內執行。 工作目錄僅在子shell中更改。 父shell的工作目錄不會更改。 第一個pwd在與cd相同的子shell中執行,因此它讀取已更改的工作目錄。 最后的pwd在父shell中執行,因此它讀取未更改的父shell的工作目錄。

在你的第二個腳本中:

$ { mkdir dir; cd dir; pwd; }; pwd;

沒有創建子shell。 花括號不會創建子殼。 cd在父shell中執行,兩個pwd讀取已更改的工作目錄。

有關更多信息和解釋,請閱讀精細bash手冊:

雖然手冊說:

   { list; }

Placing a list of commands between curly braces causes the list to be executed in the current shell context. No subshell is created.

將它放在管道上仍然會將它放在子殼上。

   { list; } | something

以來

Each command in a pipeline is executed in its own subshell (see Command Execution Environment).

{ }本身中的命令不會放在子shell上,但它本身的更高上下文將是它仍然是相同的原因。

作為測試,running ( ){ }將是相同的:

# echo "$BASHPID"
6582
# ( ps -p "$BASHPID" -o ppid= ) | cat
 6582
# { ps -p "$BASHPID" -o ppid=; } | cat
 6582

兩者都將父進程作為調用shell發送。

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM