我有一个看起来像这样的文件:
# cat $file
...
ip access-list extended DOG-IN
permit icmp 10.10.10.1 0.0.0.7 any
permit tcp 10.11.10.1 0.0.0.7 eq www 443 10.12.10.0 0.0.0.63
deny ip any any log
ip access-list extended CAT-IN
permit icmp 10.13.10.0 0.0.0.255 any
permit ip 10.14.10.0 0.0.0.255 host 10.15.10.10
permit tcp 10.16.10.0 0.0.0.255 host 10.17.10.10 eq smtp
...
我希望能够按名称搜索(使用脚本)以获得独立访问列表的“部分”输出。我希望输出看起来像这样:
# grep -i dog $file | sed <options??>
ip access-list extended DOG-IN
permit icmp 10.10.10.1 0.0.0.7 any
permit tcp 10.11.10.1 0.0.0.7 eq www 443 10.12.10.0 0.0.0.63
deny ip any any log
...没有进一步输出不适用的非缩进行。
我尝试了以下方法:
grep -A 10 DOG $file | sed -n '/^[[:space:]]\{1\}/p'
...这只给我 DOG 之后以单个空格开头的 10 行(包括不适用于搜索到的访问列表的行)。
sed -n '/DOG/,/^[[:space:]]\{1\}/p' $file
...这给了我包含 DOG 的行,下一行以一个空格开头。 (需要访问列表的所有适用行...)
我想要包含 DOG 的行,以及 DOG 之后以单个空格开头的所有行,直到下一个未缩进的行。内容中有太多变量依赖于除前导空格以外的任何模式(末尾并不总是拒绝等...)。
最佳答案
使用 GNU sed
(Linux):
name='dog' # case-INsensitive name of section to extract
sed -n "/$name/I,/^[^[:space:]]/ { /$name/I {p;d}; /^[^[:space:]]/q; p }" file
要使匹配区分大小写,请在上面出现的/I
之后删除I
。
-n
抑制默认输出,以便必须在脚本内使用p
等函数明确请求输出。- 请注意在
sed
脚本周围使用 双 引号 ("..."
),以便引用 < em>shell 变量$name
:双引号确保在将脚本交给sed
之前扩展 shell 变量引用(sed
本身无权访问 shell 变量)。- 警告:此技术很棘手,因为 (a) 您必须使用 shell 转义来转义要传递给
sed
的 shell 元字符>,例如$
为\$
,并且 (b) shell 变量值不得包含sed
可能破坏sed
脚本的元字符;对于在sed
脚本中使用的 shell 变量值的一般转义,参见 this answer我的,或者使用我的awk
-based answer .
- 警告:此技术很棘手,因为 (a) 您必须使用 shell 转义来转义要传递给
/$name/I,/^[^[:space:]]/
使用范围匹配感兴趣的行 (/$name/I
;尾随I
是 GNUsed
的不区分大小写的匹配选项)到下一个部分的开头(/^[^[:space:]]/
- 即不以空格开头的下一行);因为sed
范围总是包含,挑战是有选择地删除范围的最后一行,如果它是下一个部分的开始- 请注意,如果感兴趣的部分是文件中的最后一个部分,则不会出现这种情况。
请注意,{ ... }
中的命令仅针对范围内的每一行执行。/$name/I {p;d};
无条件打印范围的第一行:d
删除该行(已打印)并开始下一个循环(进入下一个输入行)。/^[^[:space:]]/q
匹配范围内的最后一行,如果它是下部分的第一行,并完全退出处理(q
),不打印该行。p
然后只到达部分内部线并打印它们。
注意:
- 假设标题行可以通过不以空白字符开头来识别,并且任何其他行都是非标题行 - 如果需要更复杂的匹配,请参见 my
awk
-based answer . - 此解决方案有一个小缺点,即必须复制范围正则表达式,尽管您可以使用 shell 变量来缓解这个问题。
FreeBSD/macOS sed
可以几乎做同样的事情,除了它缺少不区分大小写的选项,我
。
name='DOG' # case-SENSITIVE name of section to extract
sed -n -e "/$name/,/^[^[:space:]]/ { /$name/ {p;d;}; /^[^[:space:]]/q; p; }" file
请注意,FreeBSD/OSX sed
通常有更严格的语法要求,例如 ;
在命令之后,即使后面是 }
。
如果您确实需要不区分大小写,请参阅 my awk
-based answer .
关于regex - 如何 grep/sed/awk 获取以空白字符开头的一系列输出,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/24252555/