
原來的字串是這樣的:
str-str001-002_01
str-str005-006_05
我想在數字之前和下劃線之後提取字串,所以它會是這樣的:
str-str_01
str-str_05
我記得 sed 可以將模式分成這樣的組:
sed -n 's/\(^.*\)\([0-9]-[0-9]\)\(.*$\)/\1\3/p'
但它列印:
str-str0002_01
然後我記得[0-9]只是一個數字,所以我用+號或*號嘗試了它。然後它給出空結果。
ps:透過使用
echo 'str-str001-002_01' | sed -n 's/\(^.*\)\([0-9]-[0-9]\)\(.*$\)/\2/p'
我可以看到它匹配1-0
。
然後我嘗試了:
echo 'str-str001-002_01' | sed -n 's/\(^.*\)\([0-9]\+-[0-9]\+\)\(.*$\)/\2/p'
它留下了前 2 個數字,並且只匹配
1-002
那麼如何使其匹配001-002
答案1
這提供了所需的輸出:
sed -nE 's/^([^0-9]*).*_([^_]+)$/\1_\2/p'
您的範例的輸出
str-str_01
str-str_05
解釋
sed -nE 's/…/…/p'
- 使用 ERE,除非它們匹配,否則不要列印行^
- 錨定到行的開頭([^0-9]*)
- 匹配盡可能長的模式,即至少一個非數字字符.*_
- 盡可能匹配(包括什麼都不匹配),後面跟“_
”([^_]+)
- 匹配盡可能長的不是底線的模式(至少一個字元)$
- 錨定到行尾\1_\2
- 將整行替換為第一個(…)
匹配項「_
」和第二個(…)
匹配項
您的嘗試未按預期工作的原因是因為*
(and +
) 是貪婪的 - 它將消耗盡可能多的與前面的原子匹配的字元。因此,對於(.*)([0-9]+)
應用於類似的ERE abc123
,.*
將消耗abc12
,留下[0-9]+
匹配3
。你需要一個「不是數字" 限制第一個符合:([^0-9]*)([0-9]+)
得到abc
和123
。
答案2
$ cat file
str-str001-002_01
str-str005-006_05
$ sed 's/[0-9]\{3\}-[0-9]\{3\}//' file
str-str_01
str-str_05
這裡的替換指令是匹配並刪除NNN-NNN
其中NNN
的三位數。
匹配最後一個數字,用以1,
代替3
:
$ sed 's/[0-9]\{1,\}-[0-9]\{1,\}//' file
str-str_01
str-str_05
這對應於+
在擴展正則表達式中的使用。預設使用的正規表示式sed
是「基本」正規表示式,並且+
會符合文字加字元。大多數sed
實作也支援擴展表達式-E
:
$ sed -E 's/[0-9]+-[0-9]+//' file
str-str_01
str-str_05
使用*
,如[0-9]*-[0-9]*
,將不起作用,因為它會匹配破折號str-str
(其周圍有零位數字)。
如果您覺得確實必須匹配整條線並捕獲您想要保留的位,那麼您也可以這樣做。以下命令捕獲初始非數字和最後一位,包括下劃線:
$ sed 's/\([^0-9]*\).*\(_.*\)/\1\2/' file
str-str_01
str-str_05
然而,恕我直言,這有點難以破譯,並對您在問題中從未提到的字符串的開頭和結尾做出假設。例如,開頭不能包含要刪除的數字之前的數字,並且字串的結尾將在最後的下劃線,如果字串的該部分中有多個下劃線,則不必在要刪除的數字之後。
您始終可以進一步添加此表達式以確保僅NNN-NNN
不捕獲該位,但這會使該表達式更難以理解。