![多行 gensub](https://rvso.com/image/76424/%E5%A4%9A%E8%A1%8C%20gensub.png)
我有一個文件,其中有許多隨機行,例如
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
:
grep
與 Perl 相容的正規表示式一起使用(-P
)$ grep -oP 'mark:\s*\K\d+' file 98
-o
製造商只grep
列印該行的匹配部分。這\K
是一個 PCRE 結構,意思是「忽略此點之前匹配的任何內容」。sed
$ sed -n 's/.*mark:\s*\([0-9]\+\).*/\1/p' file 98
抑制
-n
正常輸出。只有當替換成功時,p
最後才會列印。sed
正規表示式本身會捕捉後面的一串數字mark:
和 0 個或多個空白字符,並用捕獲的內容替換整行。珀爾
$ perl -ne 'print if s/.*mark:\s*(\d+).*/$1/' file 98
告訴
-n
perl 逐行讀取輸入檔並套用 給定的腳本-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]+)"
你就會得到結果。