根据一行中的条件从多个文件中提取行
Extract lines from multiple files based on condition in one line
我有许多目录包含具有如下模式的文本文件:
class FeatureFE():
meta_data = MetaData(
name='COOL_FEATURE',
sub_type='EXTRA_COOL_FEATURES',
required_data=[accounts, logs],
has_graph=True,
x_axis_label='Time',
y_axis_label='Foo',
graph_caption='Description of my feature',
priority='low',
)
我的任务是检查每个 .py
文件,如果 has_graph=True
,则提取 name
、required_data
和 graph_caption
- 最终目标是 CSV 结构如下:
name, required_data, graph_caption
'COOL_FEATURE', [accounts, logs],'Description of my feature',
awk
/sed
/grep
这似乎绝对可行,但我正在努力实现目标。到目前为止,我已经做到了:
grep -E -B 4 -A 5 "has_graph=True" feature_17.py | tr -s ' ' | grep '^ name\|^ required_data\|^ graph_caption' | sed 's/.*=//'
哪个returns
'COOL_FEATURE',
[accounts, logs],
'Description of my feature',
对于一个文件,但当 运行 on *.py.
时什么也没有
非常感谢帮助!
每当您的数据中有名称=值对时,我发现最好先创建这些映射的数组,然后简单地通过名称访问这些值。例如,使用 GNU awk 将第三个参数匹配 () 和 ENDFILE:
$ cat tst.awk
BEGIN {
OFS = ","
numNames = split("name required_data graph_caption",names)
}
match([=10=],/^\s*(\w+)\s*=\s*(.*\S)\s*,\s*$/,a) {
name = a[1]
value = a[2]
name2value[name] = value
}
ENDFILE {
if ( name2value["has_graph"] == "True" ) {
if ( !doneHdr++ ) {
for (nameNr=1; nameNr<=numNames; nameNr++) {
name = names[nameNr]
printf "%s%s", name, (nameNr<numNames ? OFS : ORS)
}
}
for (nameNr=1; nameNr<=numNames; nameNr++) {
name = names[nameNr]
value = name2value[name]
gsub(/"/,"\"\"",value)
printf "\"%s\"%s", value, (nameNr<numNames ? OFS : ORS)
}
}
delete name2value
}
$ awk -f tst.awk file
name,required_data,graph_caption
"'COOL_FEATURE'","[accounts, logs]","'Description of my feature'"
我在打印前添加了双引号,以确保输出是有效的 CSV,即使您的值包含 ,
(如 [accounts, logs]
那样)and/or 双引号。
要将上述内容与 find
一起使用,我会这样做:
find . -name '*.py' -exec awk -f tst.awk {} +
但先删除这部分脚本:
if ( !doneHdr++ ) {
for (nameNr=1; nameNr<=numNames; nameNr++) {
name = names[nameNr]
printf "%s%s", name, (nameNr<numNames ? OFS : ORS)
}
}
所以你不会为每批从 find 传递给 awk 的文件打印一次 header 行,只需稍后手动添加 header 行或在 [=29= 之前打印它] 剧本。还有其他方法可以解决这个问题,但这是最简单的。
能否请您尝试以下操作(考虑到您的 python 文件只会出现 1 次此 class)。在 GNU awk
.
中测试和编写
awk '
BEGIN{
FS="="
s1="7"
OFS=","
print "name, required_data, graph_caption"
}
/has_graph=True/{
found=1
}
found && /name/{
sub(/,/,"",)
name=
next
}
found && /required_data/{
sub(/,/,"",)
data=
}
found && /graph_caption/{
sub(/,/,"",)
print s1 name s1,s1 data s1,s1 s1
nextfile
}
' *.py
Perl 解决方案:
perl -0777 -nE 'for my $key (qw( name required_data graph_caption )) {
($h{$key}) = /\b$key=(.*),/;
}
say join ",", @h{qw{ name required_data graph_caption }};
' -- *.py
-n
逐条读取输入记录,对每一条执行代码
-0777
读取整个文件而不是逐行读取
%h
哈希值填充了从正则表达式匹配中捕获的值,\b
代表 "word boundary"
我有许多目录包含具有如下模式的文本文件:
class FeatureFE():
meta_data = MetaData(
name='COOL_FEATURE',
sub_type='EXTRA_COOL_FEATURES',
required_data=[accounts, logs],
has_graph=True,
x_axis_label='Time',
y_axis_label='Foo',
graph_caption='Description of my feature',
priority='low',
)
我的任务是检查每个 .py
文件,如果 has_graph=True
,则提取 name
、required_data
和 graph_caption
- 最终目标是 CSV 结构如下:
name, required_data, graph_caption
'COOL_FEATURE', [accounts, logs],'Description of my feature',
awk
/sed
/grep
这似乎绝对可行,但我正在努力实现目标。到目前为止,我已经做到了:
grep -E -B 4 -A 5 "has_graph=True" feature_17.py | tr -s ' ' | grep '^ name\|^ required_data\|^ graph_caption' | sed 's/.*=//'
哪个returns
'COOL_FEATURE',
[accounts, logs],
'Description of my feature',
对于一个文件,但当 运行 on *.py.
时什么也没有非常感谢帮助!
每当您的数据中有名称=值对时,我发现最好先创建这些映射的数组,然后简单地通过名称访问这些值。例如,使用 GNU awk 将第三个参数匹配 () 和 ENDFILE:
$ cat tst.awk
BEGIN {
OFS = ","
numNames = split("name required_data graph_caption",names)
}
match([=10=],/^\s*(\w+)\s*=\s*(.*\S)\s*,\s*$/,a) {
name = a[1]
value = a[2]
name2value[name] = value
}
ENDFILE {
if ( name2value["has_graph"] == "True" ) {
if ( !doneHdr++ ) {
for (nameNr=1; nameNr<=numNames; nameNr++) {
name = names[nameNr]
printf "%s%s", name, (nameNr<numNames ? OFS : ORS)
}
}
for (nameNr=1; nameNr<=numNames; nameNr++) {
name = names[nameNr]
value = name2value[name]
gsub(/"/,"\"\"",value)
printf "\"%s\"%s", value, (nameNr<numNames ? OFS : ORS)
}
}
delete name2value
}
$ awk -f tst.awk file
name,required_data,graph_caption
"'COOL_FEATURE'","[accounts, logs]","'Description of my feature'"
我在打印前添加了双引号,以确保输出是有效的 CSV,即使您的值包含 ,
(如 [accounts, logs]
那样)and/or 双引号。
要将上述内容与 find
一起使用,我会这样做:
find . -name '*.py' -exec awk -f tst.awk {} +
但先删除这部分脚本:
if ( !doneHdr++ ) {
for (nameNr=1; nameNr<=numNames; nameNr++) {
name = names[nameNr]
printf "%s%s", name, (nameNr<numNames ? OFS : ORS)
}
}
所以你不会为每批从 find 传递给 awk 的文件打印一次 header 行,只需稍后手动添加 header 行或在 [=29= 之前打印它] 剧本。还有其他方法可以解决这个问题,但这是最简单的。
能否请您尝试以下操作(考虑到您的 python 文件只会出现 1 次此 class)。在 GNU awk
.
awk '
BEGIN{
FS="="
s1="7"
OFS=","
print "name, required_data, graph_caption"
}
/has_graph=True/{
found=1
}
found && /name/{
sub(/,/,"",)
name=
next
}
found && /required_data/{
sub(/,/,"",)
data=
}
found && /graph_caption/{
sub(/,/,"",)
print s1 name s1,s1 data s1,s1 s1
nextfile
}
' *.py
Perl 解决方案:
perl -0777 -nE 'for my $key (qw( name required_data graph_caption )) {
($h{$key}) = /\b$key=(.*),/;
}
say join ",", @h{qw{ name required_data graph_caption }};
' -- *.py
-n
逐条读取输入记录,对每一条执行代码-0777
读取整个文件而不是逐行读取%h
哈希值填充了从正则表达式匹配中捕获的值,\b
代表 "word boundary"