我有一个包含多行文本的 bash 变量,其中包括 IP 地址,并且我需要删除同一行中最后一个 IP 地址出现之前的“所有内容”。
这:
43.12.40.53 [email protected]
archery-666.foobar.com 66.77.11.44 data test@example
55.32.39.153 [email protected]
5.113.30.37 dummy
89-109-22-006.static.example.com.br 89.109.22.6 [email protected]
68.28.15.55 68.28.15.55 another
应转变为:
43.12.40.53 [email protected]
66.77.11.44 data test@example
55.32.39.153 [email protected]
5.113.30.37 dummy
89.109.22.6 [email protected]
68.28.15.55 another
读这篇文章如何从一行中删除一个模式之前的所有内容以及另一个模式之后的所有内容?我试过:
var=$(sed 's/^.*\(([0-9]{1,3}[\.]){3}[0-9]{1,3}\).*$/\1/' <<< "$var")
但它不起作用。
答案1
有几个问题:
您正在混合 BRE 和 ERE(例如与分组
\(
相对)(
.*
如果您希望结果包含 IP 之后的所有内容,则最后需要位于捕获组内开头的
^.*
会贪婪地消耗尽可能多的字符 - 包括除一个前导 IP 数字之外的所有字符
另外,.
不需要在内部逃逸[]
- 尽管这不会破坏任何东西。
我不确定处理(3)的正确方法,其中sed
(与perl
所说的不同)没有非贪婪修饰符。添加单词边界锚点\b
似乎有效,但感觉很脆弱
所以要么 (BRE)
sed 's/^.*\(\b\([0-9]\{1,3\}[.]\)\{3\}[0-9]\{1,3\}.*$\)/\1/' <<< "$var"
或(ERE)
sed -E 's/^.*(\b([0-9]{1,3}[.]){3}[0-9]{1,3}.*$)/\1/' <<< "$var"
答案2
您已经正确转义了第一个括号,但没有转义第二个括号,也没有{}
转义也需要转义的括号。另外,您将所有内容都匹配到.*$
不需要的行尾 ( )。使用您的正则表达式,这将执行您想要的操作:
$ sed 's/^.*\(\([0-9]\{1,3\}[\.]\)\{3\}[0-9]\{1,3\}\)/\1/' <<< "$var"
3.12.40.53 [email protected]
6.77.11.44 data test@example
5.32.39.153 [email protected]
5.113.30.37 dummy
9.109.22.6 [email protected]
8.28.15.55 another
但这仍然比必要的更复杂。例如,你不需要[\.]
,一个简单的\.
就足够了。您可以使用该-E
标志来启用扩展正则表达式并将语法简化为:
$ sed -E 's/^.*(([0-9]{1,3}\.){3}[0-9]{1,3})/\1/' <<< "$var"
3.12.40.53 [email protected]
6.77.11.44 data test@example
5.32.39.153 [email protected]
5.113.30.37 dummy
9.109.22.6 [email protected]
8.28.15.55 another
然而,正如钢铁司机指出的,你的前导.*
可能会比你预期的消耗更多,所以在 perl 中完成整个事情会更安全:
$ perl -pe 's/^.*?(([\d]{1,3}\.){3}\d{1,3})/\1/' <<< "$var"
43.12.40.53 [email protected]
66.77.11.44 data test@example
55.32.39.153 [email protected]
5.113.30.37 dummy
89.109.22.6 [email protected]
68.28.15.55 68.28.15.55 another