在 awk 中从 FILENAME 中提取值并将其用作新字段

Kiw*_*iwy 1 awk text-processing

我正在处理命名Event_42417555_2018-05-23_16\:45\:28-log.txt和格式如下的CSV 文件:

timestamp;fullpath;event;size
1521540649.02;/home/workdir/ScienceXMLIn/config.cfg;IN_OPEN;2324
1521540649.02;/home/workdir/ScienceXMLIn/config.cfg;IN_ACCESS;2324
1521540649.02;/home/workdir/ScienceXMLIn/config.cfg;IN_CLOSE_NOWRITE;2324
1521540649.02;/home/workdir/quad_list_14.json;IN_OPEN;2160
1521540649.03;/home/workdir/quad_list_14.json;IN_ACCESS;2160
1521540649.03;/home/workdir/quad_list_14.json;IN_CLOSE_NOWRITE;2160
Run Code Online (Sandbox Code Playgroud)

我想要的是根据使用正则表达式提取的文件名中的值向该文件添加一列[0-9]{8}(并删除标题)。

1521540649.02;/home/workdir/ScienceXMLIn/config.cfg;IN_OPEN;2324;42417555
1521540649.02;/home/workdir/ScienceXMLIn/config.cfg;IN_ACCESS;2324;42417555
1521540649.02;/home/workdir/ScienceXMLIn/config.cfg;IN_CLOSE_NOWRITE;2324;42417555
1521540649.02;/home/workdir/quad_list_14.json;IN_OPEN;2160;42417555
1521540649.03;/home/workdir/quad_list_14.json;IN_ACCESS;2160;42417555
1521540649.03;/home/workdir/quad_list_14.json;IN_CLOSE_NOWRITE;2160;42417555
Run Code Online (Sandbox Code Playgroud)

使用 gnu 工具很容易,就像这样(几乎没有测试,几乎可以肯定引号有问题):

#!/bin/bash
#$1 being the filename
JOBID=$(grep -oE "[0-9]{8}" "${1}")
sed -E "s/(.*)/\1;$JOBID/" "${1}"
Run Code Online (Sandbox Code Playgroud)

awk到目前为止,我想在这里实现最好的效果

awk -F";"  'JOBID=substr(FILENAME ,match(FILENAME,"[0-9]{8}"),8); \  
BEGIN { OFS=";"} { if ($1 != "timestamp") print $0,JOBID; }' \  
Event_42417555_2018-05-23_16\:45\:28-log.txt | head

timestamp;fullpath;event;size
timestamp;fullpath;event;size
1521540649.02;/home/workdir/ScienceXMLIn/config.cfg;IN_OPEN;2324
1521540649.02;/home/workdir/ScienceXMLIn/config.cfg;IN_OPEN;2324;42417555
1521540649.02;/home/workdir/ScienceXMLIn/config.cfg;IN_ACCESS;2324
1521540649.02;/home/workdir/ScienceXMLIn/config.cfg;IN_ACCESS;2324;42417555
1521540649.02;/home/workdir/ScienceXMLIn/config.cfg;IN_CLOSE_NOWRITE;2324
1521540649.02;/home/workdir/ScienceXMLIn/config.cfg;IN_CLOSE_NOWRITE;2324;42417555
Run Code Online (Sandbox Code Playgroud)

我有我的变量并且它设置正确,但我找不到它的正确位置。
如果我移动,JOBID=substr(FILENAME ,match(FILENAME,"[0-9]{8}"),8);
我将无法访问该变量。
这里的问题是文件被处理了两次,一次正确(尽管我的条件被忽略了),另一次它认为我的变量

Ste*_*itt 5

由于它是每个文件的一个属性,因此您应该JOBID在处理任何文件的第一行时进行计算,whenFNR为 1:

awk -F";" 'BEGIN { OFS = FS }
FNR == 1 { JOBID=substr(FILENAME, match(FILENAME, "[0-9]{8}"), 8); print }
FNR > 1 { print $0, JOBID }' \
Event_42417555_2018-05-23_16\:45\:28-log.txt | head
Run Code Online (Sandbox Code Playgroud)

有多种方法可以提取正则表达式的匹配项;我通常会match进入一个数组:

awk -F";" 'BEGIN { OFS = FS }
FNR == 1 { match(FILENAME, "([0-9]{8})", a); JOBID = a[1]; print }
FNR > 1 { print $0, JOBID }' \
Event_42417555_2018-05-23_16\:45\:28-log.txt | head
Run Code Online (Sandbox Code Playgroud)

理想情况下有一些错误处理。这用于match查找文本匹配[0-9]{8},并将任何匹配的值提取到数组中amatch查找组,因此添加了括号)。

另一种适用于任何 AWK 实现的方法是在下划线上拆分文件名:

awk -F";" 'BEGIN { OFS = FS }
FNR == 1 { split(FILENAME, a, "_"); JOBID = a[2]; print }
FNR > 1 { print $0, JOBID }' \
Event_42417555_2018-05-23_16\:45\:28-log.txt | head
Run Code Online (Sandbox Code Playgroud)

您的版本中出现双倍输出是因为它JOBID=substr(FILENAME ,match(FILENAME,"[0-9]{8}"),8)是一个完整的表达式,其权重与您的 AWK 程序中的任何其他表达式的权重相同,并带有一个隐式块 ( ie print );它总是匹配的,因为JOBID它总是非空的并且不是一个等于零的数值,所以它的块总是被处理。