regex - 如何 grep/sed/awk 获取以空白字符开头的一系列输出

标签 regex bash awk sed grep

我有一个看起来像这样的文件:

# 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 转义来转义要传递给 sedshell 元字符>,例如 $\$,并且 (b) shell 变量值不得包含 sed可能破坏 sed 脚本的元字符;对于在 sed 脚本中使用的 shell 变量值的一般转义,参见 this answer我的,或者使用我的 awk-based answer .
  • /$name/I,/^[^[:space:]]/ 使用范围匹配感兴趣的行 (/$name/I;尾随 I 是 GNU sed 的不区分大小写的匹配选项)到下一个部分的开头( /^[^[: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/

相关文章:

mysql - MySQL 中查找换行符和回车符 (\r\n)

javascript - 正则表达式可选和组

python - 从 pandas 数据框列中获取括号周围的文本并将输出复制到同一列

bash - Perl 单行正则表达式不能正确替换 - 返回错误

linux - 如何在 shell 脚本中终止进程

linux - 带有 If 条件的 AWK

mysql - AWK: Mysql: like query with\newline

c++ - std::regex_replace 仅第一次出现

c++ - 使用重新定义的 PS1 环境变量运行 bash

linux - 如何检查条件,然后使用 awk 在条件行之前的行中打印特定字段?