如何理解这个命令行中的

如何理解这个命令行中的

此行基于第一列折叠文件。

awk '{if($1==x){i=i" "$2}else{if(NR>1){print i};i=$0};x=$1;y=$2}' test.cov <(echo)

输入:

1001  hisk01
1001  hisk02
1001  hisk03
1002  hisk04
1002  hisk05
1002  hisk06
1003  hisk07
1003  hisk08

输出:

1001 hisk01 hisk02 hisk03
1002 hisk04 hisk05 hisk06
1003 hisk07 hisk08

它有效,但我不知道<(echo)这里是如何工作的。有人可以帮我吗?

谢谢

答案1

<(是“进程替换”,这是 GNU Bourne-Again Shell (Bash) 的一个功能。它不在 POSIX 中。

进程替换是一段扩展为命令行参数的语法。目标程序可以打开参数,就好像它是文件名一样。生成的文件描述符连接到括号之间的语法中指示的命令管道。

也就是说,<(echo)扩展为诸如 之类的单词/magic/path/53。当程序接收到此路径并将其打开以作为输入的文件时,它会获取一个从 读取的管道描述符echo

有什么echo作用?它产生一个空行。

之间唯一的区别

some-command <(echo)

some-command /dev/null

<(echo)产生一个空行,而/dev/null什么也不产生。

您可以假设它<(echo)是包含一个空行的文件的路径名(只要该路径名仅打开用于输入,而不是输出)。

这里的想法似乎是确保输入包含awk终止空行。也就是说,无论输入文件中是什么test.cov,都会多一个空行。脚本的逻辑需要它,因为它维护连续行之间的状态。有一个变量i,其内容取决于前一行,并在下一行到达时打印。为最后一行i计算的 永远不会打印,因此如果没有来自 的额外空行,则不会完全处理 的<(echo)最后一行。test.cov

请注意,如果test.cov缺少终止换行符,则<(echo)不会简单地提供该换行符; awk 的多个输入文件并不是简单地连接在一起形成一个字符流。无论是否存在换行符,记录都将在第一个文件的末尾定界,第二个文件会生成一条新记录。

有一种简单的方法可以从周围的 shell 中删除对进程替换功能的依赖:

awk '{if($1==x){i=i" "$2}else{if(NR>1){print i};i=$0};x=$1;y=$2}; END {print i}'

就是这样!我们添加一个END块来打印任何累积的i.我们不需要NR > 1在那里进行测试,因为 if NR == 0,这意味着没有处理任何记录,因此i是未定义的,打印为空。但是,在这种情况下会输出一个空行,可以使用 来避免这种情况END {if (i) print i}

答案2

这只会导致输出i变量中缓冲的最后内容。这会产生一个空行,因此它会导致 awk 再次运行该空行,因此它将输出i变量中的缓冲值。而不是<(echo)你可以使用该END{ print i }块。

也可以看看我的这个答案在输入已排序/未排序的两种情况下如何以其他方式执行此操作。

答案3

您得到了所问问题的答案,但仅供参考,执行您想做的事情的更常见方法之一就是:

$ awk -v ORS= '$1!=prev{print rec; ORS=RS; rec=prev=$1} {rec=rec OFS $2} END{print rec}' file
1001 hisk01 hisk02 hisk03
1002 hisk04 hisk05 hisk06
1003 hisk07 hisk08

相关内容