多行 gensub

多行 gensub

我有一個文件,其中有許多隨機行,例如

aaa bbb
ccc ddd
eee mark: 98 fff
ggg ggg jjjj iii
jjj kkkk

我想使用 awk 並且僅使用 gensub 來匹配上面的數字“98”。到目前為止,我有下面的程式碼,我認為它不起作用,因為我需要讓 gensub 將“\n”視為任何其他字元。

cat file.txt | awk 'printf(gensub(/^.*mark: ([0-9]+).*$/,"\\1","g"))}'

我需要上面程式碼的輸出僅為“98”。我怎麼做?

編輯

即使當我使用 s 或 m 修飾符時,它也不起作用,因為據我所知,“s”修飾符應該使正則表達式 treat 。作為包括 \n 在內的任何字元。

答案1

您似乎認為awk將其輸入視為多行字串。事實並非如此。當您對檔案執行 awk 腳本時,該腳本將被套用到文件的每一行分別地。所以,你的gensub每行運行一次。您實際上可以做您想做的事情,awk但它確實不是完成這項工作的最佳工具。

據我所知,您有一個大文件,只想列印後面的數字mark:和空格。如果是這樣,所有這些方法都比閒逛更簡單gensub

  1. grep與 Perl 相容的正規表示式一起使用( -P)

    $ grep -oP 'mark:\s*\K\d+' file 
    98
    

    -o製造商只grep列印該行的匹配部分。這\K是一個 PCRE 結構,意思是「忽略此點之前匹配的任何內容」。

  2. sed

    $ sed -n 's/.*mark:\s*\([0-9]\+\).*/\1/p' file
    98
    

    抑制-n正常輸出。只有當替換成功時,p最後才會列印。sed正規表示式本身會捕捉後面的一串數字mark:和 0 個或多個空白字符,並用捕獲的內容替換整行。

  3. 珀爾

    $ perl -ne 'print if s/.*mark:\s*(\d+).*/$1/' file
    98
    

    告訴-nperl 逐行讀取輸入檔並套用 給定的腳本-e。該腳本將列印替換成功的所有行。

如果你真的非常想使用gensub,你可以這樣做:

$ awk '/mark:/{print gensub(/.*mark:\s*([0-9]+).*/,"\\1","g")}' file
98

就我個人而言,我會在 awk 中這樣做:

$ awk '/mark:/{gsub(/[^0-9]/,"");print}' file
98

由於您似乎試圖讓 awk 接收多行輸入,因此您可以這樣做(假設檔案中沒有 NULL 字元):

$ awk '{print(gensub(/^.*mark: ([0-9]+).*$/,"\\1","g"))}' RS='\0' file
98

RS='\0'將輸入記錄分隔符號(即定義 的「行」awk)設為\0。由於文件中沒有此類字符,因此會awk立即讀取整個內容。

答案2

使其正常工作的最小改變是:

cat file | awk '/mark:/{printf( "%s\n",gensub(/^.*mark: ([0-9]+).*$/,"\\1","g"))}'

/mark:/ 是選擇包含「mark:」的行。
但是,那麼,為什麼需要 printf 呢?這也將起作用:

cat file | awk '/mark:/{print(gensub(/^.*mark: ([0-9]+).*$/,"\\1","g"))}'

但這將是一個“對貓的無用利用",因為 awk 可以直接從檔案中讀取:

awk '/mark:/{print(gensub(/^.*mark: ([0-9]+).*$/,"\\1","g"))}' file

編輯:

根據使用者請求:如何在檔案和字串上使用正規表示式。

好吧,根據您設定的規則:僅使用 gensub 的 awk 是不可能的。
此外,匹配的想法是.*mark: ([0-9]+).*用括號內的匹配替換所有內容,這意味著需要匹配整個文件才能提取一部分。這就是創建 grep 的原因之一。

只需使用:

grep -oP "mark: \K([0-9]+)" file

或者:

echo "$string" | grep -oP "mark: \K([0-9]+)"

你就會得到結果。

相關內容