Linux

從另一個命令進行管道傳輸時,將原始模式空間限制為匹配的字元串

  • February 3, 2021

我有一個文本文件,我想用連字元替換裡面的所有空格[[]]括號從不嵌套並且總是匹配)。下面是一個例子:

$ cat test.txt 
abc [[foo]] xyz
abc [[foo bar]] xyz
abc [[foo bar baz]] xyz [[something else]]

所以想要的輸出是:

abc [[foo]] xyz
abc [[foo-bar]] xyz
abc [[foo-bar-baz]] xyz [[something-else]]

我想我可以使用sed匹配括號內的字元串,然後使用e標誌再次執行結果sed以進行替換。然而問題在於,不僅匹配的字元串作為命令執行,而且整個模式空間(似乎是整行):

$ sed -E 's@(\[\[)(.+)(\]\])@sed -e "s/ /-/g" <<< "\1\2\3"@gpe' test.txt 
abc sed -e "s/ /-/g" <<< "[[foo]]" xyz
sh: 1: Syntax error: redirection unexpected

abc sed -e "s/ /-/g" <<< "[[foo bar]]" xyz
sh: 1: Syntax error: redirection unexpected

abc sed -e "s/ /-/g" <<< "[[foo bar baz]]" xyz
sh: 1: Syntax error: redirection unexpected

有沒有辦法將通過e標誌執行的內容限制為匹配的字元串?如果沒有,我將如何解決這個問題sed

我認為沒有辦法限制e修飾符傳遞給外殼的內容。但是你可以做這樣的事情:

$ sed -E ':a;s@(.*\[\[)([^][]* [^][]*)(\]\].*)@printf "%s%s%s" "\1" "$(printf "\2" | sed "s/ /-/g")" "\3"@e;ta' test.txt
abc [[foo]] xyz
abc [[foo-bar]] xyz
abc [[foo-bar-baz]] xyz [[something-else]]

請注意,多個替換的處理是通過循環完成的 - 由於匹配的貪婪,它實際上以相反的順序進行替換。

另請注意,可能不支持輸入重定向的e用途(因此使用管道等效項)。/bin/sh``<<<``printf "\2" | sed "s/ /-/g"


如果 perl 是一個選項,您可以做一些更接近您的原始意圖的事情,例如:

$ perl -pe 's/(?<=\[\[)(.*?)(?=\]\])/$1 =~ s: :-:rg/ge' test.txt
abc [[foo]] xyz
abc [[foo-bar]] xyz
abc [[foo-bar-baz]] xyz [[something-else]]

由於 perl 提供了一個非貪婪的修飾符,這可以更正常地使用外部替換上的標誌?來處理每行的多個替換。g

引用自:https://unix.stackexchange.com/questions/632275