Linux Shell : Process Substitution
注:本文为 “Process Substitution” 相关文章合辑。
英文引文机翻,未校。
Process Substitution.
进程替换允许使用文件名引用进程的输入或输出。它采取以下形式
<(list)
or
>(list)
进程 list 异步运行,其输入或输出显示为文件名。该文件名作为扩展结果作为参数传递给当前命令。如果使用 >(list) 形式,写入文件将为 list 提供输入。如果使用 <(list) 形式,则应读取作为参数传递的文件以获得 list 的输出。请注意,< 或 > 与左括号之间不得出现空格,否则该结构将被解释为重定向。支持命名管道 (FIFO) 或/dev/fd 命名打开文件的方法。
如果可用,进程替换与参数和变量扩展、命令替换和算术扩展同时执行。
Bash process substitution Bash 进程替换
Posted on 2012-02-27 by Tom Ryder
For tools like diff
that work with multiple files as parameters, it can be useful to work with not just files on the filesystem, but also potentially with the output of arbitrary commands. Say, for example, you wanted to compare the output of ps
and ps -e
with diff -u
. An obvious way to do this is to write files to compare the output:
对于像 diff
这样使用多个文件作为参数的工具,不仅使用文件系统上的文件,而且可能使用任意命令的输出也很有用。例如,假设您想将 ps
和 ps -e
的输出与 diff -u
进行比较。一个明显的方法是编写文件来比较输出:
$ ps > ps.out
$ ps -e > pse.out
$ diff -u ps.out pse.out
This works just fine, but Bash provides a shortcut in the form of process substitution, allowing you to treat the standard output of commands as files. This is done with the <()
and >()
operators. In our case, we want to direct the standard output of two commands into place as files:
这工作得很好,但 Bash 以进程替换的形式提供了一个快捷方式,允许您将命令的标准输出视为文件。这是通过 <()
和 >()
运算符完成的。在我们的例子中,我们希望将两个命令的标准输出作为文件定向到位:
$ diff -u <(ps) <(ps -e)
This is functionally equivalent, except it’s a little tidier because it doesn’t leave files lying around. This is also very handy for elegantly comparing files across servers, using ssh
:
这在功能上是等效的,只是它更整洁一些,因为它不会留下文件。这对于使用 ssh
优雅地比较不同服务器的文件也非常方便:
$ diff -u .bashrc <(ssh remote cat .bashrc)
Conversely, you can also use the >()
operator to direct from a filename context to the standard input of a command. This is handy for setting up in-place filters for things like logs. In the following example, I’m making a call to rsync
, specifying that it should make a log of its actions in log.txt
, but filter it through grep -vF .tmp
first to remove anything matching the fixed string .tmp
:
相反,您也可以使用 >()
运算符从文件名上下文定向到命令的标准输入。这对于为日志等内容设置就地过滤器非常方便。在下面的示例中,我调用了 rsync
,指定它应该记录 log.txt
中的操作,但首先通过 grep -vF .tmp
对其进行过滤,以删除与固定字符串 .tmp
匹配的任何内容:
$ rsync -arv --log-file=>(grep -vF .tmp >log.txt) src/ host::dst/
Combined with tee
this syntax is a way of simulating multiple filters for a stdout
stream, transforming output from a command in as many ways as you see fit:
与 tee
结合使用时,此语法是一种模拟 stdout
流的多个过滤器的方法,以您认为合适的多种方式转换命令的输出:
$ ps -ef | tee >(awk '$1=="tom"' >toms-procs.txt) \
>(awk '$1=="root"' >roots-procs.txt) \
>(awk '$1!="httpd"' >not-apache-procs.txt) \
>(awk 'NR>1{print $1}' >pids-only.txt)
In general, the idea is that wherever on the command line you could specify a file to be read from or written to, you can instead use this syntax to make an implicit named pipe for the text stream.
通常,这个想法是,在命令行的任何地方,你可以指定要读取或写入的文件,你可以改用此语法为文本流创建一个隐式命名管道。
Thanks to Reddit user Rhomboid for pointing out an incorrect assertion about this syntax necessarily abstracting mkfifo
calls, which I’ve since removed.
感谢 Reddit 用户 Rhomboid 指出关于此语法必须抽象 mkfifo
调用的错误断言,此后我将其删除。
Linux Shell 技巧: 进程替代 (Process Substitution)
ZMonster’s 2015-01-03
What is process substitution?
“Process Substitution”,我将之翻译为"进程替代",不知道有没有更相应的专业中文翻译,姑且先用着好了。它允许用将命令的输出结果当作"文件"来使用——这句话的意思是这样的,假设有一个工具,它原本接受的参数应该是一个指代某个具体文档的"文件名",使用"进程替代"后,可以用其他命令的输出来作为文件的内容,让这个工具去处理。
说得比较绕,先看看 Wikipedia 上的解释:
In computing, process substitution is a form of inter-process communication that allows the input or output of a command to appear as a file. The command is substituted in-line, where a file name would normally occur, by the command shell. This allows programs that normally only accept files to directly read from or write to another program.
Process substitution on Linux
在Linux上,通过下面的形式使用 process substituion:
<(<some command> <args>)
下面用一个实际的例子来说明它的使用。
以我的工作为例,对于一个测试集,在进行完 Speaker Diarization 后,会根据标注文件(即用作参照的标准结果)计算它的错误率,而 Speaker Diarization 的错误率由三部分组成:
- Missed speech
- False alarm speech
- Speaker error
读者不必对这些词的具体含义去深究,只要知道是一个错误率的统计,同时总体错误由三个成分组成就行了。
在计算了错误率之后,会将统计结果记录在一个文件中,在这个文件中,每一行都一个音频的测试结果,形式如下:
1.wav Miss = 2.9 False = 3.4 Speaker = 1.0 Total = 7.3
现在有两个这样的文件,是对同一批测试集进行了两次测试后得到的结果,第一个文件 2015-05-31-der.log 的内容如下:
1.wav Miss = 2.9 False = 3.4 Speaker = 1.0 Total = 7.3
2.wav Miss = 1.0 False = 2.5 Speaker = 0.0 Total = 3.5
3.wav Miss = 2.7 False = 1.1 Speaker = 0.1 Total = 3.9
第二个文件 2015-06-22-der.log 的内容如下:
2.wav Miss = 0.5 False = 2.2 Speaker = 0.9 Total = 3.6
1.wav Miss = 2.8 False = 0.0 Speaker = 0.0 Total = 2.8
3.wav Miss = 2.4 False = 1.3 Speaker = 0.4 Total = 4.1
(注: 以上数据纯属杜撰,与我目前工作中的实际错误率情况没有任何关系)
我需要根据这两个文件,得到每个音频在两次测试中各个成分的对比情况,希望输出的每一行是这样的:
1.wav Miss = 2.9 False = 3.4 Speaker = 1.0 Total = 7.3 | Miss = 2.8 False = 0.0 Speaker = 0.0 Total = 2.8
比较容易想到需要根据文件名进行 sort ,然后使用 paste 把两个文件拼接起来,那么很自然地可以这样写:
sort -k1,1 2015-05-31-der.log > 2015-05-31-der-sorted.log
sort -k1,1 2015-06-22-der.log | cut -d ' ' -f 2- > 2015-06-22-der-sorted.log
paste -d '|' 2015-05-31-der-sorted.log 2015-06-22-der-sorted.log
rm *-sorted.log
使用进程替代的话,我可以用一行就搞定,而且不需要生成临时文件:
paste -d '|' <(sort -k1,1 2015-05-31-der.log) <(sort -k1,1 2015-06-22-der.log | cut -d ' ' -f 2-)
另外一个例子,就是使用 diff 比较两个文件内容的时候,而且关心的是某个文件中某个记录在另外一个文件中有没有,不希望受次序影响时—— diff 是按行来进行文件内容对比的。还是来假设一个场景吧。
假设我和我的一个朋友各自出去购物,完了回来想比较一下购买东西的区别:我买的东西里面哪些他没有买,他买的哪些我没有买。
我的购物清单是 shopping-list-1.txt ,内容如下:
苹果
上衣
毛巾
耳机
无线键盘
我朋友的购物清单是 shopping-list-2.txt ,内容如下:
耳机
苹果
无线键盘
科幻小说
五号电池
体重秤
移动电源
那么相比不用进程替代的传统办法,使用进程替代的办法会简单很多,一行搞定:
$ diff <(sort shopping-list-1.txt) <(sort shopping-list-2.txt)
结果如下:
diff结果
$ diff <(sort shopping-list-1.txt) <(sort shopping-list-2.txt)
2c2
< 毛巾
---
> 科幻小说
4c4
< 上衣
> 体重秤
5a6,7
> 五号电池
> 移动电源
可以看到,我买了而我朋友没买的东西是:
毛巾
上衣
我朋友买了而我没买的东西是:
科幻小说
体重秤
五号电池
移动电源
Some more
实际上,进程替代也不是什么很新奇的东西,Wikipedia 上说,它是进程间通信的一种方式,事实上也确实是这样。在 Linux 上使用进程替代的时候,系统会创建一个临时的文件描述符,然后将用以替代的进程的输出和这个文件描述符关联起来,这个可以通过以下命令来验证:
echo <(sort shopping-list-1.txt)
不出意外,应该会看到这样的输出:
/dev/fd/63
"fd"就是文件描述父 (File Description) 的缩写,但去 /dev/fd/ 下面找这个文件描述符,却会发现找不到,那是因为这个文件描述符是临时的,在传给"echo"命令后就被释放了。
此外,进程替代并不能和文件完全等价,这一点要切记。进程替代所建立的"对象",是不能进行写入和随机读取操作的。不能写入的话应该很好理解,因为如果进行写操作,将会写到那个临时的文件描述符里面去,而这个临时文件描述符会被迅速地释放掉,而且由于创建的这个"文件"——姑且这么称呼,不是一个 regular file (与之相对的是 special file),如果在写入时有严格的检查,甚至连写入都会被拒绝;有时候需要对文件进行随机读取,比如 C 语言里的 fseek() 函数的操作,这样的操作将不能在进程替代产生的临时对象上正常运作。
总的来说,我个人是很喜欢这个功能的,减少了处理数据时不少的工作量。
That’s it!
via:
-
Bash process substitution Posted on 2012-02-27 by Tom Ryder.
https://sanctum.geek.nz/arabesque/bash-process-substitution/ -
Linux Shell技巧: 进程替代(Process Substitution) · ZMonster’s Blog 2015/01/03
https://www.zmonster.me/2015/01/03/process-substitution.html
原文地址:https://blog.csdn.net/u013669912/article/details/143940339
免责声明:本站文章内容转载自网络资源,如本站内容侵犯了原著者的合法权益,可联系本站删除。更多内容请关注自学内容网(zxcms.com)!