子shell和进程替换之间的区别

Pej*_*ylo 14 process process-substitution subshell

在 bash 中,我想将当前工作目录分配给一个变量。使用子shell,我可以做到这一点。

var=$(pwd)

echo $var
/home/user.name
Run Code Online (Sandbox Code Playgroud)

如果我像这样使用进程替换:

var=<(pwd)

echo $var
/dev/fd/63
Run Code Online (Sandbox Code Playgroud)

我知道进程替换主要在程序不接受 STDIN 时使用。我不清楚进程替换究竟做了什么以及为什么它分配/dev/fd/63var.

Kus*_*nda 17

命令替换 ( $(...)) 将被命令的输出替换,而进程替换 ( <(...)) 将被替换为可以从中读取命令输出的文件名。在这两种情况下,该命令都将在子 shell 中运行。

在您的情况下,pwdin的输出<(pwd)可能位于/dev/fd/63。一旦使用进程替换的命令完成执行(var在您的示例中完成分配时),该文件就不再存在。

进程替换返回的文件名是文件描述符或命名管道的名称,而不是常规文件:

支持命名管道 (FIFO) 或/dev/fd命名打开文件方法的系统支持进程替换。

进程替换的一个常见用途是为join命令预先排序文件:

$ join <( sort file1 ) <( sort file2 )
Run Code Online (Sandbox Code Playgroud)

或用于从文件中删除列(此处,通过使用cut两次并将paste结果拼接在一起,从制表符分隔的文件中删除第 2 列):

$ paste <( cut -f 1 file ) <( cut -f 3- file )
Run Code Online (Sandbox Code Playgroud)

进程替换或多或少是避免显式使用临时文件的语法快捷方式。


命令替换和进程替换都在子 shell 中执行。下面显示这些子shell中的环境不会影响父shell的环境:

$ unset t
$ echo "$( t=1234; echo "$t" )"
1234
$ echo "$t"
(empty line output)
Run Code Online (Sandbox Code Playgroud)

在这里,从命令替换中echo获取1234作为字符串参数。

$ unset t
$ cat <( t=4321; echo "$t" )
4321
$ echo "$t"
(empty line output)
Run Code Online (Sandbox Code Playgroud)

在这里,cat获取文件的文件名(命名管道/文件描述符)作为其参数。该文件包含数据4321