[英]How to grep multi line string with new line characters or tab characters or spaces
我的測試文件包含如下文本:
> cat test.txt
new dummy("test1", random1).foo("bar1");
new dummy("
test2", random2);
new dummy("test3", random3).foo("bar3");
new dummy = dummy(
"test4", random4).foo("bar4");
我正在嘗試匹配所有以分號 (;) 結尾並包含文本“dummy(”) 的單行。然后我需要提取 dummy 內雙引號中存在的字符串。我想出了以下命令,但它只匹配第一個和第三個聲明。
> perl -ne 'print if /dummy/ .. /;/' test.txt | grep -oP 'dummy\((.|\n)*,'
dummy("test1",
dummy("test3",
使用 -o 標志,我希望在 dummy 中的雙引號之間提取字符串。 但這也行不通。 你能給我一個關於如何進行的想法嗎?
預計 output 是:
test1
test2
test3
test4
以下一些答案適用於基本文件結構。 如果 lines 包含超過 1 個換行符,則代碼中斷。 例如輸入換行符較多的文本文件:
new dummy("test1", random1).foo("bar1");
new dummy("
test2", random2);
new dummy("test3", random3).foo("bar3");
new dummy = dummy(
"test4", random4).foo("bar4");
new dummy("test5",
random5).foo("bar5");
new dummy("test6", random6).foo(
"bar6");
new dummy("test7", random7).foo("
bar7");
我提到了以下 SO 鏈接:
@TLP 非常接近:
perl -0777 -nE 'say for map {s/^\s+|\s+$//gr} /\bdummy\(\s*"(.+?)"/gs' test.txt
test1
test2
使用
-0777
將文件作為單個字符串插入/\bdummy\(\s*"(.+?)"/gs
在 "dummy(" 之后找到所有引用的字符串內容(在開始引號之前有可選的空格)
s
標志允許.
匹配換行符。map {s/^\s+|\s+$//gr}
從每個字符串中刪除前導/尾隨空格。這個perl
應該工作:
perl -0777 -pe 's/(?m)^[^(]* dummy\(\s*"\s*([^"]+).*/$1/g' file
test1
test2
test3
test4
以下gnu-grep + tr
也應該有效:
grep -zoP '[^(]* dummy\(\s*"\s*\K[^"]+"' file | tr '"' '\n'
test1
test2
test3
test4
使用您顯示的示例,請嘗試使用 GNU awk
編寫和測試的awk
代碼。
awk -v RS='(^|\n)new[^;]*;' '
RT{
rt=RT
gsub(/\n+|[[:space:]]+/,"",rt)
match(rt,/"[^"]*"/)
print substr(rt,RSTART+1,RLENGTH-2)
}
' Input_file
鑒於:
$ cat file
new dummy("test1", random1).foo("bar1");
new dummy("
test2", random2);
new dummy("test3", random3).foo("bar3");
new dummy = dummy(
"test4", random4).foo("bar4");
你可以這樣使用 GNU grep:
$ grep -ozP '[^;]*\bdummy[^";]*"\s*\K[^";]*[^;]*;' file | tr '\000' '\n' | grep -oP '^[^"]*'
test1
test2
test3
test4
如果這是一個更健壯的;
分隔文本,您可以:
;
上拆分 ;/\bdummy\b/
; 這是ruby
中的所有內容:
ruby -e 'puts $<.read.split(/(?<=;)/).
select{|b| b[/\bdummy\b/]}.
map{|s| s[/(?<=")[^"]*/].strip}' file
# same output
您可以使用Text::ParseWords
來提取引用的字段。
use strict;
use warnings;
use Data::Dumper;
use Text::ParseWords;
my $str = do {
local $/;
<DATA>;
}; # slurp the text into a variable
my @lines = quotewords(q("), 1, $str); # extract fields
my @txt;
for (0 .. $#lines) {
if ($lines[$_] =~ /\bdummy\s*\(/) {
push @txt, $lines[$_+1]; # target text will be in fields following "dummy("
}
}
s/^\s+|\s+$//g for @txt; # trim leading/trailing whitespace
print Dumper \@txt;
__DATA__
new dummy("test1", random1).foo("bar1");
new dummy("
test2", random2);
new dummy("test3", random3).foo("bar3");
new dummy = dummy(
"test4", random4).foo("bar4");
Output:
$VAR1 = [
'test1',
'test2',
'test3',
'test4'
];
基於awk
的解決方案通過FS
處理一切:
<test1.txt gawk -b -e 'BEGIN { RS="^$"
FS="((^|\\n)?"(___="[^\\n")"]+y[(]"(_="[ \\t\\n]*")(__="[\\42]")(_)\
"|"(_="[ \\t]*")(__)(_)"[,]"(___)";]+[;][\\n])+"} sub(OFS=ORS,"",$!--NF)'
test1
test2
test3
test4
gawk
在5.15 secs
時以2 million rows
行為基准,因此除非您的輸入文件超過100 MB
,否則這就足夠了。
*** 警告:避免在此解決方案中使用mawk-1.9.9.6
建議簡單的gawk
腳本(標准 linux awk
):
awk '/dummy/{print gensub("[[:space:]]*","",1,$2)}' RS=';' FS='"' input.txt
RS=';'
將awk
記錄分隔符設置為;
FS='"'
將awk
字段分隔符設置為"
/dummy/
僅過濾與dummy
RexExp 匹配的記錄
gensub("[[:space:]]*","",1,$2)
從第二個字段的開頭修剪任何空白
print gensub("[[:space:]]*","",1,$2)
打印修剪后的第二個字段
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.