Sed
如何使用相同數量的重複字元獲取兩個字元串之間的內容?
本質上,我試圖獲取兩個字元串之間的內容,但是使用相同的字元重複 N 次,如下所示:
=== This is a test === ==== Another test ==== == Last test ==
當然,以上只是一個例子。這是我嘗試過的和他們的結果:
sed -u '/==/!d;s//&\n/;s/.*\n//;:a;/==/bb;$!{n;ba};:b;s//\n&/;P;D' testfile
給
= This is a test = Another test Last test
如果我只使用上述之一
testfile
:Last test
這將給出想要的結果(儘管添加了太多的換行符,但這對於這個例子來說很好)。
僅當存在這些重複字元的單個實例或者它是包含內容的一對唯一字元串時,上述方法才有效…
如何使用相同數量的重複字元獲取兩個字元串之間的內容?我更喜歡使用
grep
,sed
或awk
為此。
tl;博士
$ sed '/^==*$/,//{//!p};d' testfile This is a test Another test Last test
乍一看,一個簡單的範圍可以列印所有對(不需要循環):
$ sed -n '/^=/,//p' testfile === This is a test === ==== Another test ==== == Last test ==
=
這會列印以開頭的行和下一個重複的正則表達式 (//
)之間的每一行。這可以改進為僅包含
=
:的行/^==*$/
。並刪除所有標記:
$ sed -n '/^==*$/,//H;${x;s/\n==*//g;s/^\n//;p}' testfile This is a test Another test Last test
或者,以更短的形式:
$ sed -n '/^==*$/,//{//d;p}' testfile This is a test Another test Last test
=
要匹配將正則表達式更改為的確切數量:$ sed -n '/^==$/,//{//d;p}' testfile Last test
並且,為了避免該
-n
選項:$ sed '/^==$/,//{//!p};d' testfile Last test
在 awk 中可以這樣做:
$ awk 'p==0 && /^==*$/ {p=1;next} p==1 && /^==*$/ {p=0} p ' testfile This is a test Another test Last test
或者,以不太明確的形式:
awk ' /^==*$/ { p = !p ; next} p ' testfile
我們使用awk實用程序來使用觸發器邏輯從開啟狀態切換到關閉狀態,如下所示:
$ awk -v str="==" ' $0""==str{f=!f;next};f ' testfile Last test
使用 Posixly sed結構,我們可以實現觸發器邏輯:
sed -ne ' /^==$/{ x; # access state info from hold s/^$/0/; # initialize state y/01/10/; # toggle state x; # save state in hold d; # next } G;/\n1/P ' testfile
在擴展模式下使用 GNU 版本的流編輯器sed
-E
$ sed -Ee ' $!N; /^(\S)\1+\n/!D :loop $d;N s/^(.*)\n(.*)\n\1$/\2/;t bloop ' testfile This is a test Another test Last test
筆記:-
- 通過命令保持兩行模式空間
N
。- 繼續拒絕行,直到我們遇到黃金線(=> 模式空間的第一部分僅包含一種類型的非空白字元)
- 一旦找到這樣的一條線,我們就會循環,直到我們在路上遇到至少兩條線的精確複製品。我們已經找到了第一組。
- 這個過程一直重複,直到我們到達 eof。
使用perl中的觸發器運算符
...
,我們可以如下所示:perl -lne 'print if /^(\S)\1+$(?{$a=$_})/ ... $_ eq $a and $_ ne $a; ' testfile
對於固定的預定字元串,搜尋更簡單,因為這樣我們就不必製作正則表達式,而字元串相等測試就足夠了:
$ perl -nlse 'print if $_ eq $a ... $_ eq $a and $_ ne $a; ' -- -a=== testfile
$ sed -Ee ' /^==$/!d $!N :a $d;N s/^(.*)\n(.*)\n\1$/\2/;t ba ' testfile