簡體   English   中英

使用? 與sed

[英]Using ? with sed

我只想獲取可能會或可能不會gzip壓縮的文件的編號。 但是,似乎sed中的正則表達式不支持? 這是我嘗試過的:

echo 'file_1.gz'|sed -n 's/.*_\\(.*\\)\\(\\.gz\\)?/\\1/p'

一無所獲。 然后我加了一個? 到要分析的字符串:

echo 'file_1.gz?'|sed -n 's/.*_\\(.*\\)\\(\\.gz\\)?/\\1/p'

並得到:

1

所以,看起來像? sed不支持大多數正則表達式中使用的代碼,對嗎? 好吧,我只想sed給file_1file_1.gz賦予1 如果執行時間很關鍵,在bash腳本中執行此操作的最佳方法是什么?

相當於x? \\(x\\|\\)

但是,許多版本的sed支持啟用“擴展正則表達式”的選項,其中包括? 在GNU sed中,標志為-r 請注意,這還會更改未轉義的括號以進行分組。 例如:

echo 'file_1.gz'|sed -n -r 's/.*_(.*)(\.gz)?/\1/p'

實際上,您的正則表達式中還有另一個錯誤,那就是如果有一個錯誤,那么括號中的貪婪.*將會吞噬“ .gz”。 據我所知,sed沒有與*等價的非貪婪,但是您可以使用| 解決此問題。 | sed(以及許多其他正則表達式實現)中的將使用最左邊的匹配項,因此您可以執行以下操作:

echo 'file_1.gz'|sed -r 's/(.*_(.*)\.gz)|(.*_(.*))/\2\4/'

這將嘗試與.gz匹配,並且僅在不起作用時嘗試不帶.gz的匹配。 實際上,第2或第4組中只有一個存在(因為它們位於同一|相對兩側),因此我們只是將它們連接起來以獲得所需的值。

如果您要查找問題中給出的特定示例的答案,或者為什么要使用? 錯誤地(無論語法如何),請參閱Laurence Gonsalves的答案

如果您正在尋找為什么要回答一般性問題的答案? 不像您所期望的那樣在sed中顯示其特殊含義:

默認情況下,sed使用“ POSIX基本正則表達式語法”,因此必須將問號轉義為\\? 以應用其特殊含義,否則匹配文字問號。 或者,可以使用-r--regexp-extended選項來使用“擴展的正則表達式語法”,這將轉義已轉義和未轉義的特殊字符(包括?的含義?

用GNU sed文檔的話(在Linux上通過運行'info sed'查看):

基本和擴展正則表達式之間的唯一區別在於幾個字符的行為:'?','+',括號和大括號('{}')。 基本的正則表達式要求您將它們轉義為特殊字符,而使用擴展的正則表達式時,如果希望它們與文字字符匹配,則必須轉義它們。

並說明了該選項:

-r --regexp-extended

使用擴展的正則表達式,而不是基本的正則表達式。 擴展的正則表達式是`egrep'接受的。 它們可以更清晰,因為它們通常反斜杠較少,但它們是GNU擴展,因此使用它們的腳本不可移植。

更新資料

現在,較新版本的GNU sed表示:

-E -r --regexp-extended

使用擴展的正則表達式,而不是基本的正則表達式。 擴展的正則表達式是'egrep'接受的。 它們可以更清晰,因為它們的反斜杠通常較少。 從歷史上講,這是GNU擴展,但是自那以后,'-E'擴展已被添加到POSIX標准( http://austingroupbugs.net/view.php?id=528 )中,因此請使用'-E'進行移植。 多年來,GNU sed接受'-E'作為未記錄的選項,而* BSD sed多年以來也接受'-E',但是使用'-E'的腳本可能無法移植到其他較舊的系統。

因此,如果您需要保留與古代GNU sed的兼容性,請堅持使用-r 但是,如果您希望在更現代的系統(例如Linux + Mac支持)上更好的跨平台可移植性,請使用-E (但請注意,GNU sed和BSD sed之間仍然存在一些古怪之處和不同之處,因此您必須確保您的腳本在任何情況下都是可移植的)。

echo 'file_1.gz'|sed -n 's/.*_\(.*\)\?\(\.gz\)/\1/p'

作品。 您必須將退貨放到正確的位置,並且必須逃避。

在獲取/解析字段時,應使用優於sed awk

$ awk -F'[._]' '{print $2}' <<<"file_1"
1
$ awk -F'[._]' '{print $2}' <<<"file_1.gz"
1

或者,您可以只使用Bash的參數擴展,如下所示:

 var=file_1.gz; 
 temp=${var#*_}; 
 file=${temp%.*}
 echo $file

注意 :在var=file_1也適用

一個函數,無論文件擴展名如何,均應返回文件名中“ _”后的數字:

realname () {
  local n=${$1##*/}
  local rn="${n%.*}"
  sed 's/^.*\_//g' ${$rn:-$n}
}

解決方案的一部分在於轉義問號或使用-r選項。

sed 's/.*_\([^.]*\)\(\.\?[^.]\+\)\?$/\1/'

要么

sed -r 's/.*_([^.]*)(\.?[^.]+)?$/\1/'

適用於:

file_1.gz
file_12.txt
file_123

導致:

1
12
123

我只是意識到這可以很簡單地做一些事情:

echo 'file_1.gz'|sed -n 's/.*_\\([0-9]*\\).*/\\1/p'

注意[0-9]*而不是.* @Laurence Gonsalves的回答使我意識到上一篇文章的貪婪。

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM