我有一个文件,其中有许多随机行,例如
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]+)"
你就会得到结果。