如何在 linux 下以 php/preg 方式使用命令行提取一些擷取組?
鑑於在 Linux 環境中存在許多用於操作字元串的包(grep、awk、sed、…),我想要一個軟體以類似 php/preg 的語法提取擷取組。
也許最接近的是,
grep -P
但我不明白它是如何工作的。像這樣的東西
cat file.txt | grep -P '/something="([\w]+)"/i'
似乎不僅僅給我擷取組內的內容。有人可以為我提供一些工作範例嗎?許多人請,並解釋了一些變體和限制!
編輯:我看到某處用於
sed
此目的,但我仍然對它的語法有點困惑。
pcregrep -io1 'something="(\w+)"' myfile.txt
(
-i
對於不區分大小寫的匹配,-o1
列印第一個擷取組)。GNU
grep
支持-P
(如果使用 perl 兼容的正則表達式支持建構)和-o
. 然而,它-o
僅限於列印整個匹配的部分。但是,您可以使用 perl 環視運算符來解決這個問題:grep -iPo '(?<=something=")\w+(?=")' myfile.txt
(即,匹配單片語件字元序列的正則表達式,前提是它跟在它
something="
後面並且後面跟著"
)。或者最近足夠的PCRE:
grep -iPo 'something="\K\w+(?=")' myfile.txt
(
\K
重置匹配字元串的開頭)。但如果你要使用 perl 正則表達式,你不妨使用
perl
:perl -C -lne 'print for /something="(\w+)"/ig' myfile.txt
使用 GNU 或 BSD
sed
,每行只返回最右邊的匹配:sed -nE 's/.*something="(\w+)".*/\1/pi' myfile.txt
可移植(因為擴展的正則表達式支持和不區分大小寫的匹配是非標準擴展,並非所有
sed
實現都支持):sed -n 's/.*[sS][oO][mM][eE][tT][hH][iI][nN][gG]="\([[:alnum:]_]\{1,\}\)".*/\1/p' myfile.txt
那個假設大寫
i
是I
. 這意味著在例如大寫的語言環境中i
,İ
行為將與以前的解決方案不同。一個標準/攜帶式解決方案,可以找到一行中的所有事件:
awk '{while(match(tolower($0), /something="[[:alnum:]_]+"/)) { print substr($0, RSTART+11, RLENGTH-12) $0 = substr($0, RSTART+RLENGTH-1)}}' myfile.txt
如果輸入包含小寫版本的長度(以字元數計)不同的文本,則可能無法正常工作。
陷阱:
所有這些解決方案在C/POSIX 以外的語言環境中匹配
\w
(和)的內容會有所不同。[[:alnum:]_]
在任何情況下,它至少應該包括下劃線、所有十進制阿拉伯數字和拉丁英文字母表中的字母(大寫和小寫)。如果您只想要這些,請將語言環境修復為 C。如前所述,不區分大小寫的匹配非常依賴於語言環境。如果你只關心
a-z
vsA-Z
英文字母,你可以再次將 locale 固定為 C。至少
.
具有 GNU 實現的regexp 運算符永遠不會匹配不是有效字元一部分的字節序列。sed
例如,在 UTF-8 語言環境中,這意味著它不會匹配具有第 8 位集的單字節字元集中的字元。或者換句話說,要使sed
解決方案正常工作,輸入文件中使用的字元集必須與使用者語言環境中的字元集相同。
perl
,pcregrep
並且 GNU 實用程序通常可以處理任意長度的行,並且包含任意字節值(但請注意上面的警告),並且會將最後一個換行符之後的額外數據視為額外行。這些實用程序的其他實現可能不會。上面的模式依次與輸入中的每一行匹配。這意味著它們不能匹配多於一行的輸入。
something="\w+"
對於不能跨越多行的模式來說不是問題,但在一般情況下,如果您希望您的模式匹配可能跨越多行的文本,例如something=".*?"
,那麼您需要:
- 更改您處理的記錄類型。
grep --null
,sed -z
(sed
僅限 GNU),perl -0
,awk -v RS='\0'
(僅限 GNUawk
和最新版本mawk
)可以處理 NUL 分隔的記錄而不是行(換行符分隔的記錄),GNUawk
可以使用任何正則表達式作為記錄分隔符(使用-v RS='regexp'),
perlany byte value (with
-0ooo`)。pcregrep
有一個-M
多行模式。- 使用
perl
slurp 模式,其中整個輸入是一個記錄(使用-0777
)然後,對於 perl 和 pcre ,請注意.
除非啟用標誌,否則不會匹配換行符s
,例如使用pcregrep -Mio1 '(?s)something="(.*?)"'
orperl -C -l -0777 -ne 'print for /something="(.*?)"/gis'
請注意,某些版本的
grep
andpcregrep
有-z
or的錯誤-M
,而 regexp 引擎通常會對匹配 regexp 的工作量有一些內置限制。