Linux

如何在 linux 下以 php/preg 方式使用命令行提取一些擷取組?

  • August 31, 2021

鑑於在 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列印第一個擷取組)。

GNUgrep支持-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

那個假設大寫iI. 這意味著在例如大寫的語言環境中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-zvsA-Z英文字母,你可以再次將 locale 固定為 C。

  • 至少.具有 GNU 實現的regexp 運算符永遠不會匹配不是有效字元一部分的字節序列。sed例如,在 UTF-8 語言環境中,這意味著它不會匹配具有第 8 位集的單字節字元集中的字元。或者換句話說,要使sed解決方案正常工作,輸入文件中使用的字元集必須與使用者語言環境中的字元集相同。

  • perl,pcregrep並且 GNU 實用程序通常可以處理任意長度的行,並且包含任意字節值(但請注意上面的警告),並且會將最後一個換行符之後的額外數據視為額外行。這些實用程序的其他實現可能不會。

  • 上面的模式依次與輸入中的每一行匹配。這意味著它們不能匹配多於一行的輸入。something="\w+"對於不能跨越多行的模式來說不是問題,但在一般情況下,如果您希望您的模式匹配可能跨越多行的文本,例如something=".*?",那麼您需要:

    • 更改您處理的記錄類型。grep --null, sed -zsed僅限 GNU),perl -0, awk -v RS='\0'(僅限 GNUawk和最新版本mawk)可以處理 NUL 分隔的記錄而不是行(換行符分隔的記錄),GNUawk可以使用任何正則表達式作為記錄分隔符(使用-v RS='regexp'),perl any byte value (with-0ooo`)。
    • pcregrep有一個-M多行模式。
    • 使用perlslurp 模式,其中整個輸入是一個記錄(使用-0777)然後,對於 perl 和 pcre ,請注意.除非啟用標誌,否則不會匹配換行符s,例如使用pcregrep -Mio1 '(?s)something="(.*?)"'orperl -C -l -0777 -ne 'print for /something="(.*?)"/gis'
  • 請注意,某些版本的grepandpcregrep-zor的錯誤-M,而 regexp 引擎通常會對匹配 regexp 的工作量有一些內置限制。

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