![从 awk 中的 FILENAME 中提取值并将其用作新字段](https://linux22.com/image/133953/%E4%BB%8E%20awk%20%E4%B8%AD%E7%9A%84%20FILENAME%20%E4%B8%AD%E6%8F%90%E5%8F%96%E5%80%BC%E5%B9%B6%E5%B0%86%E5%85%B6%E7%94%A8%E4%BD%9C%E6%96%B0%E5%AD%97%E6%AE%B5.png)
我正在处理命名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
我想要的是根据使用正则表达式提取的文件名中的值向该文件添加一列[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
使用 gnu 工具,很容易会像这样(几乎没有经过测试,几乎可以肯定引号存在问题):
#!/bin/bash
#$1 being the filename
JOBID=$(grep -oE "[0-9]{8}" "${1}")
sed -E "s/(.*)/\1;$JOBID/" "${1}"
我想在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
我有我的变量并且它设置正确,但我找不到它的正确位置。
如果我移动JOBID=substr(FILENAME ,match(FILENAME,"[0-9]{8}"),8);
我将无法访问该变量。
这里的问题是该文件被处理两次,一次正确处理(尽管我的条件被忽略),另一次考虑了我的变量
答案1
由于它是每个文件的属性,因此您应该JOBID
在处理任何文件的第一行时进行计算,IE什么时候FNR
是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
有多种方法可以提取正则表达式的匹配项;我通常会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
最好有一些错误处理。这用于match
查找文本匹配[0-9]{8}
,并将任何匹配值提取到数组中a
(match
查找组,因此添加括号)。
另一种适用于任何 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
您的版本中出现双倍输出是因为JOBID=substr(FILENAME ,match(FILENAME,"[0-9]{8}"),8)
它是一个完整的表达式,其权重与 AWK 程序中的任何其他表达式相同,并且具有隐式块(IE print
);它总是匹配,因为JOBID
总是非空并且不是等于零的数值,所以它的块总是被处理。