[英]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_1
和file_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.