Red*_*ect 2 shell pipe io-redirection file-descriptors posix
有人问如何将两个命令的输出作为文件传递给另一个命令,他们得到了下面的答案。
( cmd1 | ( cmd2 | ( main_command /dev/fd/3 /dev/fd/4 ) 4<&0 ) 3<&0 )
Run Code Online (Sandbox Code Playgroud)
我需要拆开这个。
假设我有一个文本文件some_file
,我希望将它作为输入传递给main_command
. main_command
将两个文件作为输入。如果我想main_command
与some_file
命令的输出一起使用cmd2
,一种方法是
( cmd2 | ( main_command some_file /dev/fd/4 ) 4<&0 )
Run Code Online (Sandbox Code Playgroud)
main_command some_file /dev/fd/4
. 这只是将文件some_file
和/dev/fd/4
作为参数传递
给main_command
.4<&0
部分表示stdin
将指向文件描述符4
。cmd2 |
将 的输出cmd2
与后面任何内容的输入连接起来。我的问题是:
编辑:我应该说如果我的逻辑是正确的,那么就没有必要回答 1。
这是一个相当复杂的命令。我在最后直接回答了您的问题,但在此之前所有这些都是解压缩命令本身。我试图做到全面,因此某些地方可能比您需要的要详细一些。
( x y z )
Run Code Online (Sandbox Code Playgroud)
意味着从当前的 shell 中派生出一个新的 shell,在其中执行x y z
(然后返回到当前的 shell)。子shell 继承了当前的所有内容,但它是一个单独的进程:这意味着它可以将输入通过管道传输到其中,并且可以在不影响父级的情况下进行自己的环境更改。
每个打开的文件都有一个与之关联的数字“文件描述符”。此上下文中的“文件”包括任何类型的输入或输出流,包括真实文件、套接字和标准 I/O 流。这些数字是句柄,可以直接与Cread
函数一起使用,以识别您正在谈论的流,以及操作系统提供的相应系统调用以及所有其他 IO 函数。
4<&0
执行重定向,将标准输入文件描述符 (0) 克隆为文件描述符 4。这意味着FD 0 被复制到 4,而不是相反。在这种情况下,它正在修改重定向之前的子 shell 的打开文件。目前,这只是为输入流创建另一个“名称”。但一个关键部分是这两个名称此后彼此独立:FD 4 将始终指代同一个流,即使 FD 0 被更改为指代其他东西并且两者有分歧。
/dev/fd/4
是程序访问其自己打开的文件描述符的(非标准)方式。在 Linux 上,它是指向 的符号链接/proc/self/fd
,它具体化了当前进程的文件描述符表。程序可以open("/dev/fd/4", O_RDONLY)
并获得一个文件句柄,该句柄引用该程序在 FD 4 上的流(例如它4
本身)。就程序而言,这只是一个可以像其他任何文件一样打开、关闭和读取的常规文件。因为打开的文件描述符是由子main_command
进程继承的,与它所在的子外壳具有相同的文件描述符 4,因此也/dev/fd/4
可以在那里工作。
cmd2 | x
运行cmd2
,并将其标准输出连接到标准输入 - 或 FD 0 - of x
. 在您的命令中,x
是子shell 表达式。
我们的总指挥
cmd2 | ( main_command /dev/fd/4 ) 4<&0
Run Code Online (Sandbox Code Playgroud)
然后有三个主要部分:
cmd2
并将其输出通过管道传输到( main_command /dev/fd/4 ) 4<&0
.4
另一名由确定的流0
(标准输入)( main_command /dev/fd/4 )
。main_command
,/dev/fd/4
它将(大概)作为文件打开并从中读取,获取cmd2
.最终效果是main_command
获得一个路径名参数,它可以打开并cmd2
从中读取输出,这与 Bash 进程替换会发生的情况完全一样main_command <(cmd2)
:事实上,这可能会/dev/fd/63
作为参数给出,否则在内部进行非常相似。
对于完整的命令
( cmd1 | ( cmd2 | ( main_command /dev/fd/3 /dev/fd/4 ) 4<&0 ) 3<&0 )
Run Code Online (Sandbox Code Playgroud)
我们有嵌套的子shell:那是因为我们想要制作标准输入的两个副本,但它是两个不同的标准输入:一个是 的输出cmd1
,在通过管道进入更大的子shell后放入FD 3,另一个是输出of cmd2
,它在通过管道进入最里面的子壳后被放入 FD 4。这两个0
s 都指的是标准输入,但是每个命令的标准输入是不同的,因为我们有不同的东西被输送到它里面。
我认为这是问题中最令人困惑的部分。每个命令——这里,每个子shell——都有自己的标准输入,从cmd1
或管道输入cmd2
,并且唯一的标准输入流被别名为3
or 4
。这些打开的文件描述符由下一层子shell和子命令继承,所以/dev/fd/3
在最里面的命令指的是它在外面所做的同样的事情,即使标准输入现在指向别的东西。
外圆括号不是严格要求的,尽管它们使某些命令的健壮性稍强一些,并且可能是一个很好的做法。内部是:它们用于创建一个新的子进程,该子进程可以在其中拥有自己的一组重定向,以及自己的标准输入流。
最里面的重定向实际上是多余的:cmd2 | main_command /dev/fd/3 /dev/stdin
也可以工作,因为没有对标准输入进行进一步更改。
要直接解决您的问题:
如何解压问题开头的命令?
到目前为止,拆包是整个帖子。
括号有什么作用?
括号创建了一个子 shell,一个独立的 shell 进程,可以像任何其他命令一样使用,包括将输入通过管道传输到其中,但可以在内部执行普通的 shell 操作,例如重定向。
我对简单命令的解释是否正确?
部分。4<&0
说文件描述符 4 将指向标准输入,重要的是现在称为标准输入- 而不是标准输入的概念。/dev/fd/4
是“一切都是文件意义上的”中的“文件”,但更具体地说,它是一个路径名,打开时会将您的 FD 4 交还给您。
归档时间: |
|
查看次数: |
546 次 |
最近记录: |