将多个awk输出语句合并为一行

时间:2019-09-04 17:46:51

标签: bash awk

我正在处理一些ascii文件,每个文件有35列,行数是可变的。我需要取两列之间的差(N + 1),然后将结果放入第36列的重复的ascii文件中。然后,我需要取另一列,并将其(按行)除以列36,并将结果放入第37列中相同的重复ascii文件中。

我过去做过类似的处理,但是通过为每个awk命令输出临时文件,读取每个连续的临时文件,最终创建最终的ascii文件。然后,我将删除临时文件。我希望有一种比必须创建一堆临时文件简单/快速的方法。

下面是一个初始的工作处理步骤,上面的awk命令需要遵循并适应于此。此步骤从foo.txt中获取数据,删除标题,并仅处理包含特定但变化的字符串的行。

Firefox WebDriver

针对不同的数据文件还有另一个处理步骤,我还需要前面讨论过的2个新列。这只是将要保存的唯一文件名附加到新ascii文件中每一行的最后一列。实际上,此命令处于循环中,输入文件各不相同,但我在这里对其进行了简化。

cat foo.txt | tail -n +2 | awk '$17 ~ /^[F][0-9][0-9][0-9]$/' >> foo_new.txt

其中一个foo.txt文件的示例。

cat foo.txt | tail -n +2 | awk -v fname="$fname" '{print $0 OFS fname;}' >> foo_new.txt

下面是所需的示例foo_new.txt。从awk请求的2列输出(后2列)。在此示例中,第5列是第3列与第2列加1的差。第6列是第1列除以第5列的结果。

 20 0  5  F001
  4 2  3  F002
 12 4  8  F003
100 10 29 O001

对于第二个示例foo_new.txt。最后一列是fname的示例。这些是在shell脚本中计算的,并传递给awk。我不在乎第7列(fname)中的结果是在最后还是位于第4列和第5列之间,只要它与其他awk语句相符即可。

 20 0  5  F001 6  3.3
  4 2  3  F002 2  2.0
 12 4  8  F003 5  2.4

到目前为止,祝你好运,但是不幸的是,这产生的文件首先是原始输出,下面是添加的输出。我想将添加的输出附加为列(#5和#6)。

 20 0  5  F001 6  3.3 C1
  4 2  3  F002 2  2.0 C2
 12 4  8  F003 5  2.4 C3

2 个答案:

答案 0 :(得分:2)

  

我需要取两列之间的差(N + 1),并将结果放入第36列的重复的ascii文件中。然后,我需要取另一列,并将其除以(按行)第36列,并将结果放入第37列中相同的重复ascii文件。

就是这样:

awk -vN=9 -vanother_column=10 '{ v36 = $N - $(N+1); print $0, v36, $another_column / v36 }' input_file.tsv

我猜您的文件有一些“标题” /特殊的“第一行”,因此,如果它是第一行,则保留它:

awk ... 'NR==1{print $0, "36_header", "37_header"} NR>1{ ... the script above ... }`

从您呈现的示例脚本的前三列中,将N替换为2,将another_column替换为1,我们得到以下脚本:

# recreate input file
cat <<EOF |
20 0  5
4 2  3
12 4  8
100 10 29
EOF
tr -s ' ' | 
tr ' ' '\t'  > input_file.tsv


awk -vOFS=$'\t' -vIFS=$'\t' -vN=2 -vanother_column=1 '{ tmp = $(N + 1) - $N; print $0, tmp, $another_column / tmp }' input_file.tsv

它将输出:

20  0   5   5   4
4   2   3   1   4
12  4   8   4   3
100 10  29  19  5.26316

这样的脚本:

awk -vOFS=$'\t' -vIFS=$'\t' -vN=2 -vanother_column=1 '{ tmp = $(N + 1) - $N + 1; print $0, tmp, sprintf("%.1f", $another_column / tmp) }' input_file.tsv

我认为得到的输出与您想要的更接近:

20  0   5   6   3.3
4   2   3   2   2.0
12  4   8   5   2.4
100 10  29  20  5.0

我想这(N+1)的意思是“两列加1的差”。

答案 1 :(得分:2)

考虑具有这样的标题行的输入文件data(紧密基于您的最小示例):

Col1 Col2 Col3 Col4
 20 0  5  F001
  4 2  3  F002
 12 4  8  F003
100 10 29 O001

您希望输出包含第5列,它是$3 - $2 + 1的值(第3列减去第2列加1),第6列是第1列的值除以第5列(其中1输出中的小数位),以及基于传递给脚本的变量fname的文件名,但每行具有唯一的值。而且,您只需要第4列与F和3位数字匹配的行,并且您想跳过第一行。全部可以直接写在awk中:

awk -v fname=C '
NR == 1                     { next }
$4 ~ /^F[0-9][0-9][0-9]$/   { c5 = $3 - $2 + 1
                              c6 = sprintf("%.1f", $1 / c5)
                              print $0, c5, c6, fname NR
                            }' data

您也可以将其写在一行上:

awk -v fname=C 'NR==1{next} $4~/^F[0-9][0-9][0-9]$/ { c5=$3-$2+1; print $0,c5,sprintf("%.1f",$1/c5), fname NR }' data

输出为:

 20 0  5  F001 6 3.3 C2
  4 2  3  F002 2 2.0 C3
 12 4  8  F003 5 2.4 C4

很明显,您可以更改文件名,以分别使用counter++++counter代替NR中的print来使计数器从0或1开始。语句,则可以再次使用前导零或使用sprintf()设置其他格式。如果要删除每个文件的第一行而不是仅删除第一个文件,请将NR == 1条件更改为FNR == 1

请注意,这不需要cat foo.txt | tail -n +2提供的预处理。