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



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

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

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

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

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

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

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

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

下面是foo_new.txt期望的示例。从 awk 请求的 2 列输出(最后 2 列(。在此示例中,列 5 是列 3 和列 2 加 1 之间的差值。第 6 列是第 1 列除以第 5 列的结果。

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

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

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

到目前为止,祝你好运,但不幸的是,这是首先生成一个包含原始输出的文件,然后在其下方生成添加的输出。我想将添加的输出作为列(#5 和 #6(附加。

cat foo.txt | tail -n +2 | awk '$17 ~ /^[F][0-9][0-9][0-9]$/' >> foo_new.txt
cat foo_new.txt | awk '{print $4=$3-$2+1, $5=$1/($3-$2+1)}' >> foo_new.txt

考虑一个带有如下标题行的输入文件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

显然,您可以更改文件名,以便计数器从 0 或 1 开始,方法是分别使用counter++++counter代替print语句中的NR,并且您可以使用前导零或其他任何您想要的sprintf()再次格式化它。 如果要删除每个文件的第一行,而不仅仅是第一个文件,请将NR == 1条件更改为FNR == 1

请注意,这不需要cat foo.txt | tail -n +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 ... }`

从您提供的示例脚本中获取前 3 列,并用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

我猜你的意思是"添加 1 的两列之间的差异(N+1)

最新更新