【问题标题】:Merging output of two awk acripts into 1 file将两个 awk 脚本的输出合并到 1 个文件中
【发布时间】:2016-12-15 08:28:34
【问题描述】:

我有一个包含 150 多列和 50M 行的大型输入文件,此处显示了一个示例:

id,c1,c2,c3,c4,c5,c6,c7,c8,c9,c10,c11,c12,c13,c14
1,0,0,0,0,1,0,0,1,1,0,0,1,0,0
2,0,0,1,0,0,1,1,0,0,0,1,0,0,1

我有一个 bash shell 脚本:

function awkScript() {
awk -F, -v cols="$1" -v hdr="$2" '
   BEGIN {OFS=FS}
   NR==1 {n=split(cols,cn); 
          for(i=1;i<=NF;i++) 
            for(j=1;j<=n;j++) 
              if($i==cn[j]) c[++k]=i; 
          $(NF+1)=hdr}
   NR >1 {v1=$c[1]; v2=$c[2]; v3=$c[3]
          if(!v2 && !v3) $(NF+1) = v1?10:0
          else $(NF+1) = v3?(v1-v3)/v3:0 + v2?(v1-v2)/v2:0}1' "$3" 
}   

function awkScript1() {
awk -F, -v cols="$1" -v hdr="$2" '
   BEGIN {OFS=FS}
   NR==1 {n=split(cols,cn); 
          for(i=1;i<=NF;i++) 
            for(j=1;j<=n;j++) 
              if($i==cn[j]) c[++k]=i; 
          $(NF+1)=hdr}
   NR >1 {v1=$c[1]; v2=$c[2]; v3=$c[3]; v4=$c[4]
          $(NF+1) = v1?(v1/(v1+v2+v3+v4)):0
         }1' "$3"
}

function awkScriptWrapper() {
   awkScript "$1" "$2"
}

function awkScriptWrapper1() {
   awkScript1 "$1" "$2"
}

awkScript "c1,c2,c3" "Header1" "input.txt" | awkScriptWrapper "c4,c5,c6" "Header2" >> output.txt
awkScript1 "c7,c8,c9,c10" "Header3" "input.txt" | awkScriptWrapper1 "c11,c12,c13,c14" "Header4" >> output1.txt 

output.txt 的示例是:

id,c1,c2,c3,c4,c5,c6,c7,c8,c9,c10,c11,c12,c13,c14,Header1,Header2
1,0,0,0,0,1,0,0,1,1,0,0,1,0,0,0,-1
2,0,0,1,0,0,1,1,0,0,0,1,0,0,1,-1,-1

output1.txt 的示例是:

id,c1,c2,c3,c4,c5,c6,c7,c8,c9,c10,c11,c12,c13,c14,Header3,Header4
1,0,0,0,0,1,0,0,1,1,0,0,1,0,0,0,0
2,0,0,1,0,0,1,1,0,0,0,1,0,0,1,1,0.5

我的要求是我必须将 Header1,Header2,Header3,Header4 附加到同一个输入文件的末尾,即上面的脚本应该只生成 1 个输出文件“finaloutput.txt”:

id,c1,c2,c3,c4,c5,c6,c7,c8,c9,c10,c11,c12,c13,c14,Header1,Header2,Header3,Header4
1,0,0,0,0,1,0,0,1,1,0,0,1,0,0,0,-1,0,0
2,0,0,1,0,0,1,1,0,0,0,1,0,0,1,-1,-1,1,0.5

我尝试了以下语句:

awkScript "c1,c2,c3" "Header1" "input.txt" | awkScriptWrapper "c4,c5,c6" "Header2" >> temp_output.txt
awkScript1 "c7,c8,c9,c10" "Header3" "temp_output.txt" | awkScriptWrapper1 "c11,c12,c13,c14" "Header4" >> finaloutput.txt

但我不明白。

任何帮助将不胜感激。

【问题讨论】:

  • 看看man 1 join和我昨天发布的这个答案:stackoverflow.com/questions/41144043/…
  • @andlrc:我的 AWK 脚本运行良好。我的问题是将它们的结果都重定向到同一个输出文件。据我了解,这里没有给出我需要的答案 [stackoverflow.com/questions/41144043/…。请花时间仔细阅读我的问题。
  • 正如我所说,join 似乎是完成这项工作的工具。您可以使用-o 指定输出列。请记住,您可以使用进程替换:command1 | join ... - &lt;(command2)
  • 你能花点时间详细说明一下并将其作为答案吗?我对 shellscripting 还很陌生。
  • 只使用第一个脚本的输出作为第二个脚本的输入文件。

标签: bash awk


【解决方案1】:

假设您需要在管道中加入两个命令:

$ cmd1 | join --header -j1 -t, -o1.{1..17} -o2.16,2.17 - <(cmd2)
id,c1,c2,c3,c4,c5,c6,c7,c8,c9,c10,c11,c12,c13,c14,Header1,Header2,Header3,Header4
1,0,0,0,0,1,0,0,1,1,0,0,1,0,0,0,-1,0,0
2,0,0,1,0,0,1,1,0,0,0,1,0,0,1,-1,-1,1,0.5

以上假设cmd1输出:

id,c1,c2,c3,c4,c5,c6,c7,c8,c9,c10,c11,c12,c13,c14,Header1,Header2
1,0,0,0,0,1,0,0,1,1,0,0,1,0,0,0,-1
2,0,0,1,0,0,1,1,0,0,0,1,0,0,1,-1,-1

cmd2 输出:

id,c1,c2,c3,c4,c5,c6,c7,c8,c9,c10,c11,c12,c13,c14,Header3,Header4
1,0,0,0,0,1,0,0,1,1,0,0,1,0,0,0,0
2,0,0,1,0,0,1,1,0,0,0,1,0,0,1,1,0.5

它是如何工作的?

--header 将每个文件中的第一行视为字段标题
-j1 将连接到字段一个
-t, 指定 , 作为字段分隔符
-o xxx 将指定输出列,1.1 表示文件一中的第一列,在本例中为 cmd12.1 表示文件二中的第一列,在本例中为 cmd2

-o1.{1..17} 将扩展为:

-o1.1 -o1.2 -o1.3 -o1.4 -o1.5 -o1.6 -o1.7 -o1.8 -o1.9 -o1.10 -o1.11 -o1.12 -o1.13 -o1.14 -o1.15 -o1.16 -o1.17

这是一种从cmd1 中指定前 17 列的快速方法。

- 指的是标准输入,在这种情况下它是来自cmd1 的输出

&lt;(command)process substitution

你可以改成:

join [options] file1 file2

如果您需要加入两个常规文件。

【讨论】:

  • 你有没有花时间测试你的答案。因为我在执行它时遇到了错误。
  • 我将它作为 bash 脚本运行
  • --header unrecognized command 你在执行我发布的命令时做得很差。由于您缺少命令名称(join
  • 请提供您根据我的样本输入测试过的解决方案
  • 这是我使用的awkScript "c1,c2,c3" "Header1" "stinput.txt" | awkScriptWrapper "c4,c5,c6" "Header2" | join --header -j1 -t, -o1.{1..17} -o2.16,2.17 - &lt;(awkScript1 "c7,c8,c9,c10" "Header3" "stinput.txt" | awkScriptWrapper1 "c11,c12,c13,c14" "Header4")。介意解释我哪里出错了吗?
猜你喜欢
  • 2021-10-19
  • 1970-01-01
  • 1970-01-01
  • 2013-12-09
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2013-09-06
相关资源
最近更新 更多