我希望有一种方法可以让 sed 用替换内容(而不仅仅是匹配内容)替换整行,这样我就可以做这样的事情:
sed -e "/$some_complex_regex_with_a_backref/\1/"
并让它仅打印反向引用。
从这个问题,似乎要做到这一点的方法是弄乱正则表达式以匹配整行,或者使用其他工具(如 perl)。简单地将 to 更改为regex
并不.*regex.*
总是有效(如该问题中所述)。例如:
$ echo $regex
\([:alpha:]*\)day
$ echo $phrase
it is Saturday tomorrow
$ echo $phrase | sed "s/$regex/\1/"
it is Satur tomorrow
$ echo $phrase | sed "s/.*$regex.*/\1/"
$ # what I'd like to have happen
$ echo $phrase | [[[some command or string of commands]]]
Satur
我正在寻找最简洁的方法来做到这一点,假设如下:
- 正则表达式是一个变量,因此不能根据具体情况进行更改。
- 我想在不使用 perl 或其他更强大的语言的情况下做到这一点。
答案1
我对 sed 不太了解,无法回答,但如果你能灵活地使用 grep:
grep --only-matching "complex_regex" file
或者
grep -o "complex_regex" file
这--only-matching(或简称-o) 标志告诉 grep 仅打印出匹配的部分,而不是整行。
答案2
您的第一个 .* 停在“day”,从而使您的反向引用为空。您需要在反向引用中的 [[:alpha:]] 之前找到一些明确的匹配项。例如一个空格,
$ echo $regex
\([[:alpha:]]*\)day
$ echo $phrase
it is Saturday tomorrow
$ echo $phrase | sed "s/.* $regex.*/\1/"
Satur
我又爱又恨正则表达式。
编辑:
字边界非 POSIX 扩展 (\b) 似乎可以捕捉到两种情况:
$ regex="\b\([[:alpha:]]\+\)day\b"
我不确定如何处理模式出现多次或模式中有多个单词的情况。
$ cat phrase.txt
it is Saturday tomorrow
it is Saturday tomorrow
Saturday is the date tomorrow
Saturday is the date tomorrow
Saturday is the day tomorrow
Saturday is the day tomorrow
Saturday is the day in dayton tomorrow
Saturday is the day in dayton tomorrow
Saturday is the day after Friday
The last day of the week is Friday
$ cat phrase.txt | sed -e "s/.*$regex.*/\1/"
Satur
Satur
Satur
Satur
Satur
Satur
Satur
Satur
Satur
Fri
我很好奇是否有人对 sed-fu 有更多的了解,可以给出更好的答案。:-)
答案3
这与 mgjk 的答案很接近,但边界匹配的方法略有不同。
echo $phrase | sed 's/.*[^[:alpha:]]\([[:alpha:]]*\)day.*/\1/'
Satur
因为.*
会吞下任何东西,所以你必须先匹配“不是我想要的字符”,然后是“我想要的字符”。因此,$regex
你可以存储
[^[:alpha:]]\([[:alpha:]]*\)day
它并非没有缺点(如果“星期六”是行首,则当前形式不起作用),但如果您打算使用 justsed
而不是更强大的工具,那么它可能对您来说就足够了。您也可以使用两部分正则表达式来解决“行首”问题,但随后它又开始变得更加复杂,这是您不想要的。如果您的标准发生变化,则存在许多解决方案。