sed 中的非貪婪匹配

sed 中的非貪婪匹配

在 bash 腳本中,我有以下變數:

file_name='this_is_the_hart_part.csv'

使用

var2=$(echo $file_name | sed -e 's/_{2}\(.*\)_{3}/\1/')

我想提取子字串“the”(變數 $file_name 中的底線數字 2 和 3 之間)。

但我得到的 $var2 等於 $file_name。我該如何更改我的 sed 命令?

答案1

支援的正規表示式類型sed不允許與 進行非貪婪匹配*

您想要獲得第三個_分隔欄位。這是最簡單的方法cut

cut -d '_' -f 3

或者,與awk

awk -F '_' '{ print $3 }'

或者,在 shell 中,連續刪除前兩個此類字段,然後修剪末尾:

str=${file_name#*_}
str=${str#*_}
str=${str%%_*}

"$str"就是the最後這個詞。使用最後一個變體可能是這三種方法中最快、最可靠的方法。

變數替換${variable#*_}將產生一個字串,該字串的$variable前導位直到並包括第一個下劃線被刪除。將${variable%%_*}刪除從第一個底線到結尾的所有內容$variable。這些是標準變數替換。

在檔案名上使用變數替換的好處是它可以處理包含換行符的檔案名,而 或或awksed不會cut。一般來說,不要對檔案名稱使用面向行的文字編輯工具。

此外,您正在使用echo $file_name.由於$file_name未加引號,因此它將經歷單字分割(預設情況下,在也是空格、製表符和換行符的每個字元上$IFS),並且產生的單字(如果它們包含檔案名稱通配符)將與當前目錄中的檔案名稱進行匹配通過外殼。檔案名稱中的反斜線也可能消失或產生不必要的效果(即使您引用副檔名)。當未加引號時,shellksh也會對 的值進行大括號擴展。$file_name

答案2

首先要注意的sed文字預設情況下一次只處理一行的實用程序,而檔案名稱可以包含任何字元(包括換行符)甚至非字元(可以是非字元)文字)。

也,不加引號的變數有非常特殊的意義,你幾乎不想這樣做,這也是潛在非常危險

也,你不能用來echo輸出任意數據,printf而是使用

另外,類似 Bourne 的 shell 中的變數賦值語法是:var=value,而不是$var=value

echo您可以使用以下命令將(或更好的是printf)的整個輸出載入到sed的模式空間:

printf '%s\n' "$filename" | sed -e :1 -e '$!{N;b1' -e '}'

然後,您可以新增程式碼來提取第二個和第三個之間的部分_

var2=$(
  printf '%s\n' "$filename" |
   sed -ne :1 -e '$!{N;b1' -e '}' -e 's/^\([^_]*_\)\{2\}\([^_]*\)_.*/\2/p'
)

非貪婪部分是透過使用[^_]*(一系列非_字元)來解決的,這與.*保證我們不匹配過去的_邊界相反(儘管在許多實現中它仍然會被非字元阻塞)。

在這種情況下,您可以改用 shell 參數擴充運算子:

case $filename in
  (*_*_*_*) var2=${filename#*_*_}; var2=${var2%%_*};;
  (*)       var2=;;
esac

如果檔案名稱不是文字或您要提取的部分以換行符號結尾(並且也會更有效),則效果會更好。

有些 shell 喜歡zshksh93有更高級的運算子:

  • zsh

    拆分_並取得第三個欄位:

    var2=${"${(@s:_:)filename}"[3]}
    

    使用${var/pattern/replacement}和 反向引用(在這種情況下,您需要先驗證變數是否包含至少 3 個下劃線,否則不會有任何替換)。

    set -o extendedglob
    var2=${filename/(#b)*_*_(*)_*/$match[1]}
    
  • ksh93

    var2=${filename/*_*_@(*)_*/\1}
    

答案3

@Kusalananda 是對的,這sed是錯誤的工具,你不能進行非貪婪匹配。但是您可以使用非貪婪匹配的解決方法: [^_]*將匹配任何不是的字符_

所以在你的情況下你可以這樣做:

printf '%s\n' "$file_name" | sed -e 's/^[^_]*_[^_]*_\([^_]*\).*$/\1/g'

但是...對於您的用例,您應該更好地使用其他工具...

相關內容