【问题标题】:How to use STDIN twice from pipe如何从管道中使用 STDIN 两次
【发布时间】:2017-11-24 01:47:54
【问题描述】:

我有一个类似的 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?

【问题讨论】:

  • 你的问题毫无意义。如果您要通过标准输入将许多文件添加到 awk 中?为什么你需要在最后再次通过标准输入。你理解错了
  • ..你为什么在先问另一个要求后完全改变问题?
  • 抱歉描述有误,但似乎 |进入
  • 但如果这是你“需要”的,那么你就不需要了。即使您不想将这些行存储在内存或临时文件中(请参阅stackoverflow.com/a/44688094/1745001),您也可以通过简单的cat *files | awk '...' - *files 获得相同的输出,并且无需进行进程替换。

标签: linux bash shell awk pipe


【解决方案1】:

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

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

【讨论】:

  • 谢谢 Inian - 但是如果我有很多文件并且需要执行以下操作怎么办: cat *files | awk ....... STDIN SDTIN?
  • @Geroge:您上述评论的要求不清楚。举例说明并添加到问题中
  • 很高兴知道流程替代!但我几乎没有改变我的问题来连接我的文件..
  • 只需将| 之前的所有内容移动到&lt;(...) 中,两次。
  • 你不能总是用进程替换来替换管道,因为你不能总是多次运行相同的命令来多次产生相同的输入。我很惊讶 OP 接受了这个答案,但问题中的例子是一般情况的一个坏例子,所以也许他说他想要的(How to use STDIN twice from pipe)不是他的例子表明他真正想要的(how to execute awk on multiple files? )。哦,好吧....
【解决方案2】:

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

$ 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

【讨论】:

  • 嗨,Ed,谢谢你的好点子。你理解我的问题是对的。可以将 awk 脚本的这种修改放入数组中: awk 'FNR==NR{a[$90];b[$1]+=!c[$1,$90]++;next}{print b[$1] " /" 长度(a) "\t" (b[$1]/length(a))*100}'
  • 对不起,我不明白你的问题。如果您有一个巨大的文件,为什么要将它们的内容存储在一个数组中,而不是直接使用文件中的数据?您选择了一个答案,因此您应该询问提供该答案的人,而不是像我这样提供错误答案的人 - 也许他们会理解您的意思并为您调整他们的答案。
【解决方案3】:

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

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

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

路径中的

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

【讨论】:

    猜你喜欢
    • 2015-10-27
    • 2013-04-27
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2015-08-01
    • 1970-01-01
    • 2016-06-05
    相关资源
    最近更新 更多