提取 IPv6 地址的 sed 命令如何工作?

提取 IPv6 地址的 sed 命令如何工作?

我收到一条提取 IPv6 地址的命令:

/usr/bin/ip a | grep inet6 | grep -vE 'fe80|host' | sed -e 's/^.*inet6 \([^ ]*\)\/.*$/\1/;t;d'

有人可以帮我分解一下sed替换吗?

sed 命令在没有;t;d

答案1

看来你想学点东西,我很欣赏。 symcbeansed向您解释了该命令,但我想添加一些您可以从代码中学到的更多内容。你可以学会避免坏习惯。 (-;

  1. 整个命令通过两个greps 和一个进行管道传输sed,这几乎总是无意义的。在 中sed,您可以地址通过在行前面加上正则表达式来替换行,这可以grep动态执行功能,就像sed -n '/foo/s/pattern/replace/p'仅在带有 . 的行上进行替换一样foo。因此 '/inet6/!d' 可以删除所有不带 ( !)的行,然后您可以用 (或者使用扩展正则表达式选项: )inet6替换第二grep行。/fe80/d;/host/d-E/fe08|host/d
  2. -e如果只有一个命令(或由 串联的多个命令),则 是可选的;。如果你去掉多余的东西,事情会变得更容易阅读。
  3. 正如已经指出的,以 开始正则表达式^.*是无意义的。贪婪的人*无论如何都会从一开始就匹配任何东西,所以不要用不必要的锚点来分散读者的注意力。
  4. 同样适用于.*$最后。拆下锚。
  5. 如果模式包含斜杠,请为s命令使用不同的分隔符。几乎任何字符都是允许的,那么为什么要通过用反斜杠填充表达式来使表达式更难以阅读呢?下划线是很好的选择,例如:s_.*inet6 \([^ ]*\)/.*_\1_
  6. 使用\(…\)\1可能很有用,但如果这只是提取中间部分,那么简单地分别删除开头和结尾可能会更全面:s/.*inet6 //;s_/.*__
  7. 根据sed定义,命令后面可选地跟随一个跳转标记,在本例中t就是这样。;d不常见,但合法。 GNU 版本sed不允许在跳转标记中使用分号,但将其解释为命令分隔分号。在这种情况下,不会有跳转标记,这意味着“如果进行替换,则跳转到脚本末尾”。但其他sed版本会抛出错误。让脚本不兼容这样的细节,实在是太恶心了!例如,可以通过单独的脚本来避免这种情况-e '…;t' -e d。或者通过在新行中编写命令。
  8. 在本例中,其想法t;d是避免替换失败时输出混乱。一个好主意,但是有一个真正的工具可以实现这一点,即命令p的标志ss_.*inet6 \([^ ]*\)/.*_\1_p;d。如果进行了更换,p请冲洗缓冲区。更易于阅读和便携。
  9. 尾随d命令可以替换为-n抑制默认输出的选项,但这是一个品味问题。

最后我们可以比较命令

/usr/bin/ip a | grep inet6 | grep -vE 'fe80|host' | sed -e 's/^.*inet6 \([^ ]*\)\/.*$/\1/;t;d'

/usr/bin/ip a | sed '/inet6/!d; /fe80/d; /host/d; s/.*inet6 //; s_/.*__p; d'

或用 ERE-n代替d

/usr/bin/ip a | sed -En '/inet6/!d; /fe80|host/d ;s/.*inet6 //; s_/.*__p'

高尔夫球手可能会写的代码

sed -En '/fe80|host/!s_.*inet6 ([^ ]*)/.*$_\1_p'

但这对我来说似乎不太可读。

答案2

我首先会稍微简化一下你的表达......

LINE=" inet6 fd86:73ea:ff6b:0:141b:ca40:741b:ec0c/64 scope global noprefixroute"
echo $LINE | sed -e' s/^.*inet6 \([^ ]*\)\/.*$/\1/;t;d'

-e意味着下一个参数是 sed 脚本。

's/pattern/replace/' 表示在输入中查找“pattern”并替换为“replace”。

这里的模式是/^.*inet6 \([^ ]*\)\/.*$/

'/' 标记模式的开始和结束。

^ 和 $ 字符始终分别与输入字符串的开头和结尾匹配。观察输入字符串总是有一个开始和结束 - 当您想要匹配或替换相对于这些位置的元素时,这些会变得有用。

.*表示任何字符出现零次或多次。在上面的 $LINE 中,它匹配单个空格字符。

inet6表示文字字符串“inet6”(带有尾随空格)。

括号\(pattern\)告诉 sed 不仅匹配输入中的子模式,而且存储它以供以后使用。

均值\/与文字“/”匹配(参见上文 - 如果没有前缀,“/”字符表示模式中的结构元素)。

.*$只是意味着匹配任何剩余的字符直到行尾。

/标记模式的结束。

\1这就是替换。这里 1 指的是模式找到的第一个存储的匹配(但只有一个)。

相关内容