此行基于第一列折叠文件。
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