我正在搜索输入,以提取有关每条记录的特定信息。可悲的是,每条记录都分布在多行上,例如(简化摘录)
01238584 (other info) more info, more info
[age=81][otherinfo][etc, etc]
我唯一真正关心的是标识符和年龄(在示例中,101238584和81)。为了清楚起见,我唯一能在输入中可靠地搜索到的正则表达式是
[age=[0-9]+]
当然,我想打印出年龄以及上面一行的识别记录编号,例如
01238584 81
凭借我所有的sysadminshell经验和对awk的熟练掌握,我还没有想出一个解决方案。我当然可以使用grep -B1
来获得每一组行,但那又怎样呢?我总是用锥子做这类事情。。。但是相关联的数据总是在同一行中叹气这绝对超出了我目前的awk技能。
感谢阅读。有什么线索吗?
编辑
我同意查理的建议,改变awk的唱片分隔符,这是我以前从未做过的。它不漂亮,但输入也不漂亮。工作完成了。
egrep -B1 '[age=[0-9]+]' inputfile |
awk '
BEGIN{ RS = "--" }
{ printf "%s %sn", $1, gensub(/.*[age=([0-9]+)].*/, "\1", 1) }'
您能显示更多的输入文件吗?例如,如果数据记录由空行分隔,则可以使用Awk中的RS特殊变量更改记录分隔符,使其将多行视为一条记录。(例如,http://www.staff.science.uu.nl/~oostr102/docs/nawk/nawk_19.html)
在任何情况下,我都会尝试将您的所有数据记录放在一行或一个逻辑记录中。
如果你不能做到这一点,但你知道记录ID总是在age标记之前的行上,那么在Python中使用readlines很容易做到,它将整个文件读取到一个行列表中,类似于这个
with open("file.dat") as f:
lines = f.readlines()
for ix, line in enumerate(lines):
if # line has age field
# get record from lines[ix-1]
或者,当然,你可以在Awk 中始终保留前一行
BEGIN { prevline = "" }
{ # process the line
prevline = $0
}
Perl在这种情况下可以很容易地充当您的朋友。你可以阅读将整个文件放入内存,以便在多行中应用正则表达式。将输入记录分隔符设置为0777
会导致这样的"诋毁"操作。-n
开关只是简单地表示读取命令行上提供的一个或多个文件。-e
开关的参数构成了要执行的代码。
正则表达式的/s
修饰符允许.
匹配换行符。m
修饰符允许^
和$
在嵌入换行符前后立即匹配。这些是解析包含多个逻辑行的字符串的关键。/g
修饰符告诉regex引擎全局搜索所有匹配项。
perl -0777 -ne 'print "$1 $2n" while m{^(S+).+?[age=(d+)]}gms' file
给定这样的输入文件:
01238584 (other info) more info, more info
[age=81][otherinfo][etc, etc]
98765432 (still other info) still more info, and more info
[age=82][and more otherinfo][etc, etc, ad infinitum]
上面的脚本输出:
01238584 81
98765432 82
我们可以这样剖析正则表达式:
perl -MYAPE::Regex::Explain -e 'print YAPE::Regex::Explain->new(qr/m{^(S+).
+?[age=(\d+)]}gms/)->explain()'
The regular expression:
(?-imsx:m{^(S+).+?[age=(d+)]}gms)
matches as follows:
NODE EXPLANATION
----------------------------------------------------------------------
(?-imsx: group, but do not capture (case-sensitive)
(with ^ and $ matching normally) (with . not
matching n) (matching whitespace and #
normally):
----------------------------------------------------------------------
m{ 'm{'
----------------------------------------------------------------------
^ the beginning of the string
----------------------------------------------------------------------
( group and capture to 1:
----------------------------------------------------------------------
S+ non-whitespace (all but n, r, t, f,
and " ") (1 or more times (matching the
most amount possible))
----------------------------------------------------------------------
) end of 1
----------------------------------------------------------------------
.+? any character except n (1 or more times
(matching the least amount possible))
----------------------------------------------------------------------
[ '['
----------------------------------------------------------------------
age= 'age='
----------------------------------------------------------------------
( group and capture to 2:
----------------------------------------------------------------------
d+ digits (0-9) (1 or more times (matching
the most amount possible))
----------------------------------------------------------------------
) end of 2
----------------------------------------------------------------------
] ']'
----------------------------------------------------------------------
}gms '}gms'
----------------------------------------------------------------------
) end of grouping
----------------------------------------------------------------------