shell编程小技巧:进程替换

jwang-48 / 2024-10-30 / 原文

今天来给大家介绍一个非常好用的shell编程技巧,即进程替换(Process substitution)。

进程替换可以将一个进程(程序)的输入或输出当做一个文件来使用。

它的两种使用形式为:<(cmd)>(cmd) .

需要注意的是,<>(之间不能有空格!

下面通过一个示例来介绍进程替换的具体用法。

假如我有一个几种编程语言的使用用户数目的文件,其内容如下(虚构数字请勿当真):

$ cat num_users.tsv 
programming_language    num_users
Python  2000
Linux   3000
R       3500
C       2000
Java    2000

此时我还有一个几种编程语言的起源时间的文件,其内容如下:

$ cat history.tsv 
programming_language    orgin_date
R       1980
Python  1989

如果我想通过第二个文件(history.tsv)从第一个文件(num_users.tsv)中取出来R和Python的用户数目,那么可以运行的命令为:

$ cut -f1 history.tsv |sed '1d' > a # 首先取出第一列,并去掉第一行(header)

$ cat a # 其内容如下
R
Python

$ grep -Fwf a num_users.tsv # 在num_users.tsv文件中搜索文件a中的内容,搜索结果如下
Python  2000
R       3500

可以发现上面一共用了三行命令,其过程为:

  • 首先将history.tsv文件的内容取出来存入到一个临时文件a
  • 其次使用grepnum_users.tsv文件中搜索文件a中的关键词

如果使用了进程替换,那么将不需要产生临时文件a,其命令如下:

$ grep -Fwf <(cut -f1 history.tsv |sed '1d') num_users.tsv 
Python  2000
R       3500

在上述命令中<(cut -f1 history.tsv |sed '1d')的内容与前面文件a的内容完全一致,且作用也一样,因此可以得到相同的结果。

可以发现,使用了进程替换以后便可以一行命令完成上述需求,无需产生中间文件。

进程替换的应用还有很多,这里再举另一个比较简单的例子,即比较两个文件的第一列是否一致。

这两个文件(a.tsvb.tsv)的内容如下:

$ cat a.tsv 
programming_language    orgin_date
R       1980
Python  1989

$ cat b.tsv 
programming_language    num_users
R       3500
Python  2000

由于这两个文件的第一列一样,但是后面的列不同,所以不能直接使用diff命令来比较这两个文件。

要比较这两个文件的第一列是否一致,传统的命令如下:

$ cut -f1 a.tsv > 1
$ cut -f1 b.tsv > 2
$ diff 1 2

而使用进程替换的命令如下:

$ diff <(cut -f1 a.tsv) <(cut -f1 b.tsv)

一行命令即可搞定!非常简洁!

参考链接:https://www.gnu.org/software/bash/manual/html_node/Process-Substitution.html

最后

本文同步发表于微信公众号:水木的生信与编程世界,如果觉得本文对您有帮助欢迎关注公众号,我会持续分享更多关于生信的分析经验和实用技巧。