如何从管道中使用两次 STDIN



我有一个像这样的awk脚本

awk 'FNR==NR {col1[$1]++; col2[$2]++; next} {print $0, col2[$2] "/" length(col1)}' input input

但是,如果我有很多文件并且需要将此脚本用于连接在一起的文件,例如:

cat *all_input | awk 'FNR==NR {col1[$1]++; col2[$2]++; next} {print $0, col2[$2] "/" length(col1)}' STDIN STDIN

不工作。如何从管道中使用两次STDIN?

你不需要

使用管道。如果您使用bash请使用进程替换作为<(cmd)即实现重定向,其中进程的输入或输出(某些命令序列(显示为临时文件。

awk 'FNR==NR {col1[$1]++; col2[$2]++; next} {print $0, col2[$2] "/" length(col1)}' <(cut -f3 5- input) <(cut -f3 5- input)

How to use STDIN twice from pipe的答案是"你不能"。如果您想使用stdin中的数据两次,则需要在第一次读取时将其保存在某个地方,以便下次使用。例如:

$ seq 3 |
awk '
    BEGIN {
        if ( ("mktemp"|getline line) > 0) tmp=line; else exit
        ARGV[ARGC]=tmp; ARGC++
    }
    NR==FNR { print > tmp }
    { print FILENAME, NR, FNR, $0 }
' -
- 1 1 1
- 2 2 2
- 3 3 3
/var/folders/11/vlqr7jmn6jj3fglyl12lj0l00000gn/T/tmp.Y03l9pS7 4 1 1
/var/folders/11/vlqr7jmn6jj3fglyl12lj0l00000gn/T/tmp.Y03l9pS7 5 2 2
/var/folders/11/vlqr7jmn6jj3fglyl12lj0l00000gn/T/tmp.Y03l9pS7 6 3 3

或者,您可以将其存储在内部数组或字符串中,稍后再从那里读回。

话虽如此,您的具体问题不需要任何花哨的东西,只需一个简单的:

cat *all_input | awk 'FNR==NR {col1[$1]; col2[$2]++; next} {print $0, col2[$2] "/" length(col1)}' - *all_input

会这样做,但除非你的文件很大,否则你真正需要的是存储在阵列中的方法:

awk '{ col1[$1]; col2[$2]++; f0[NR]=$0; f2[NR]=$2 }
END {
    for (nr=1; nr<=NR; nr++) {
        print f0[nr], col2[f2[nr]] "/" length(col1)
    }
}' *all_input
我不知道

这是否有帮助,因为我不是awk专家,但是任何Linux应用程序(包括awk(都可以直接从/proc/self/fd/0读取stdin

请注意,这比 open(0( 的可移植性要低得多,并且只能在具有可读 procfs 的 Linux 上运行(今天几乎所有的 Linux 发行版(。

如果应用程序允许并行文件描述符使用,则可以打开该文件描述符两次并从中读取两次。

路径中的 self 指定访问应用程序的 PID。

最新更新