我有一个这样的文件:
[group]
enable = 0
name = green
test = more
[group]
name = blue
test = home
[group]
value = 48
name = orange
test = out
标签和=
之间可能还有一个或多个空格/标签和值
每个街区的行数可能会谨慎
我希望拥有name
,但前提是enable = 0
所以输出应该是:
blue
orange
以下是我设法创建的内容:
awk -v RS="group" '!/enable = 0/ {sub(/.*name[[:blank:]]+=[[:blank:]]+/,x);print $1}'
blue
orange
这有几个错误:
RS
设置为[group]
,这都会导致RS="[group]"
和RS="\[group\]"
失败。如果name
或其他标签包含group
,则会失败。RS
使用多个字符,因为这只是gnu awk
。有人有其他建议吗? sed
或awk
并且不使用长链命令。
答案 0 :(得分:5)
如果您知道组总是用空行分隔,请将RS
设置为空字符串:
$ awk -v RS="" '!/enable = 0/ {sub(/.*name[[:blank:]]+=[[:blank:]]+/,x);print $1}'
blue
orange
@devnull在他的回答中解释说GNU awk也接受RS
中的正则表达式,所以如果它在自己的行上,你只能在[group]
分割:
gawk -v RS='(^|\n)[[]group]($|\n)' '!/enable = 0/ {sub(/.*name[[:blank:]]+=[[:blank:]]+/,x);print $1}'
这确保我们不会像
那样分裂邪恶的名字[group]
enable = 0
name = [group]
name = evil
test = more
答案 1 :(得分:5)
您的问题似乎是:
我无法将RS设置为
[group]
,这都失败了RS="[group]"
和RS="\[group\]"
。
话说:
RS="[[]group[]]"
应该产生预期的结果。
答案 2 :(得分:5)
在记录中有明确name = value
语句的情况下,我想先用这些映射填充数组,例如:
map["<name>"] = <value>
然后只使用名称来引用我想要的值。在这种情况下:
$ awk -v RS= -F'\n' '
{
delete map
for (i=1;i<=NF;i++) {
split($i,tmp,/ *= */)
map[tmp[1]] = tmp[2]
}
}
map["enable"] !~ /^0$/ {
print map["name"]
}
' file
blue
orange
如果您的awk版本不支持删除整个数组,请将delete map
更改为split("",map)
。
与使用RE和/或sub()等等相比,它使得解决方案更加健壮和可扩展,以备将来比较和/或打印其他字段的值。
答案 3 :(得分:3)
由于您有行分隔记录,因此应考虑将awk
置于段落模式中。如果您必须测试[group]
标识符,只需添加代码来处理它。这是一些应该满足您要求的示例代码。像:
awk -f script.awk file.txt
script.awk
的内容:
BEGIN {
RS=""
}
{
for (i=2; i<=NF; i+=3) {
if ($i == "enable" && $(i+2) == 0) {
f = 1
}
if ($i == "name") {
r = $(i+2)
}
}
}
!(f) && r {
print r
}
{
f = 0
r = ""
}
结果:
blue
orange
答案 4 :(得分:3)
这可能适合你(GNU sed):
sed -n '/\[group\]/{:a;$!{N;/\n$/!ba};/enable\s*=\s*0/!s/.*name\s*=\s*\(\S\+\).*/\1/p;d}' file
如果[group]
变量未设置为enable
,请将0
块读入模式空间,然后替换颜色。
sed -n '...'
设置sed以静默模式运行,除非指定为p
或P
命令/\[group\]/{...}
当我们有一行包含[group]
时,请执行大括号内的内容。:a;$!{N;/\n$/!ba}
做一个循环我们需要一个循环的地方,:a
是循环的地方。 $
是文件地址的结尾,$!
表示不文件的结尾,因此$!{...}
表示在花括号内找到的内容不是文件的结尾。 N
表示当我们有一行以空行分支(/\n$/ba
)到b
结尾时,将换行符和下一行附加到当前行和a
。因此,这会从包含“[group]”的行收集所有行到空行(或文件末尾)。/enable\s*=\s*0/!s/.*name\s*=\s*\(\S\+\).*/\1/p
如果收集的行包含enable = 0
,则不要替换颜色。换句话说,如果到目前为止收集的行不包含enable = 0
做替换颜色。答案 5 :(得分:2)
如果您不想使用记录分隔符,可以使用如下虚拟变量:
#!/usr/bin/awk -f
function endgroup() {
if (e == 1) {
print n
}
}
$1 == "name" {
n = $3
}
$1 == "enable" && $3 == 0 {
e = 0;
}
$0 == "[group]" {
endgroup();
e = 1;
}
END {
endgroup();
}
答案 6 :(得分:1)
你实际上可以使用Bash。
while read line; do
if [[ $line == "enable = 0" ]]; then
n=1
else
n=0
fi
if [ $n -eq 0 ] && [[ $line =~ name[[:space:]]+=[[:space:]]([a-z]+) ]]; then
echo ${BASH_REMATCH[1]}
fi
done < file
只有当enable = 0
始终只有name
行的一行时才会有效。