我正在处理一些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
答案 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
提供的预处理。