我下面有一个示例文本文件(test_long_sentence.txt),我想 grep 包含 test1 的所有行,排除不需要的数据。
如何在报价结束前 grep 数据?
test_long_sentence.txt
This is some unwanted data blah blah blah
20 /test1/catergory="Food"
20 /test1/target="Adults, \"Goblins\", Elderly,
Babies, \"Witch\",
Faries"
20 /test1/type="Western"
This is some unwanted data blah blah blah
20 /test1/theme="Halloween"
命令:
grep "test1" test_long_sentence.txt
实际输出:
20 /test1/catergory="food"
20 /test1/target="Adults, \"Goblins\", Elderly,
20 /test1/type="Western"
20 /test1/theme="Halloween"
预期输出:
20 /test1/catergory="food"
20 /test1/target="Adults, \"Goblins\", Elderly,
Babies, \"Witch\",
Faries"
20 /test1/type="Western"
20 /test1/theme="Halloween"
PS:我无法控制编辑test_long_sentence.txt。所以请不要要求我将其编辑为一行。
答案1
使用 awk
$ awk '/test1/{line=$0; while (!(line ~ /[^\\]".*[^\\]"/)) {getline; line=line "\n" $0}; print line}' sentence.txt
20 /test1/catergory="Food"
20 /test1/target="Adults, \"Goblins\", Elderly,
Babies, \"Witch\",
Faries"
20 /test1/type="Western"
20 /test1/theme="Halloween"
/test1/
是一个条件。如果当前行包含与 regex 匹配的内容test1
,则执行花括号中的命令。这些命令是:
line=$0
当前行的内容保存在变量“line”中。
while (!(line ~ !/[^\\]".*[^\\]"/)) {getline; line=line "\n" $0}
如果当前内容
line
不包含两个未转义的引号,则获取下一行,getline
并将其附加到line
vialine=line "\n" $0
print line
现在该变量
line
包含两个未转义的引号,我们将其打印出来。
对于那些喜欢将命令分散在多行中的人,可以将与上面相同的命令编写为:
awk '
/test1/{
line=$0
while (!(line ~ /[^\\]".*[^\\]"/)) {
getline
line=line "\n" $0
}
print line
}' sentence.txt
使用 sed
$ sed -n '/test1/{:a; /[^\\]".*[^\\]"/{p;b}; N; ba}' sentence.txt
20 /test1/catergory="Food"
20 /test1/target="Adults, \"Goblins\", Elderly,
Babies, \"Witch\",
Faries"
20 /test1/type="Western"
20 /test1/theme="Halloween"
怎么运行的:
-n
这告诉 sed 不要打印任何内容,除非我们明确要求它打印。
/test1/{...}
对于任何包含 的行
test1
,我们执行大括号中的命令,它们是::a
这定义了一个标签
a
。/[^\\]".*[^\\]"/{p;b}
如果模式空间当前包含两个未转义的引号,我们将打印模式空间 ,
p
然后跳过其余指令并分支 ,b
以从下一行开始。N
如果我们到达这里,这意味着当前没有两个未转义的引号。我们将下一行读入模式空间。
ba
我们回到标签
a
并重复该标签后面的命令。
答案2
这将适用于awk
而不是grep
针对该特定文件:
awk 'NR==3,NR==7;NR==11' test_long_sentence.txt
为了将来解决此问题,您可以运行cat -n
该文件以查看要包含和排除的行。
答案3
这是一个简单的 Perl 脚本,用于连接输入中的连续行。它假设:
连续的行将与单个空格字符连接。
“行”从任何以数字和空格开头的输入行开始,一直持续到:
- 一个空白的像
- 另一行以数字和空格开头
空行以及空行之间的所有行都将被忽略(即丢弃)。
这可能与您的实际输入文件不完美匹配,但确实与您的问题中提供的示例输入匹配。根据需要修改代码以适合您的输入。
#!/usr/bin/perl
my $skip=1; # start with skip = true.
my $line='';
while(<>) {
chomp;
if (m/^\d+\s+/) { # / this comment is only here to fix SE\'s syntax highlighting
$skip=0;
print $line,"\n" if ($line);
$line = $_;
} elsif (m/^\s*$/) {
if ($line ne '') { print $line, "\n"; $line = ''};
$skip = 1 - $skip;
} elsif (! $skip) {
$line .= " $_";
};
};
另存为,例如,./join-lines.pl
使可执行文件chmod +x ./join-lines.pl
,并运行如下:
$ ./join-lines.pl test_long_sentence.txt
20 /test1/catergory="Food"
20 /test1/target="Adults, \"Goblins\", Elderly, Babies, \"Witch\", Faries"
20 /test1/type="Western"
20 /test1/theme="Halloween"
然后可以根据需要将其输入grep
或其他工具中。
请注意,对于当前样本输入, 的输出./join-lines.pl test_long_sentence.txt | grep test1
(除了 可能的匹配着色之外grep
)与上面的输出相同,因为所有样本行都包含“test1”。您可以更有用地 grep 查找其他匹配项,例如:
$ ./join-lines.pl test_long_sentence.txt | grep Witch
20 /test1/target="Adults, \"Goblins\", Elderly, Babies, \"Witch\", Faries"
如果您需要能够重现完全相同的输入(但没有空白和不需要的行),那么不要用空格连接行,而是使用" ===NL=== "
您绝对需要的字符(例如 TAB)或更长的字符串(例如 )某些永远不会出现在输入中。例如
} elsif (! $skip) {
$line .= "\t$_";
};
或者
} elsif (! $skip) {
$line .= " ===NL=== $_ ";
};
然后可以将连接字符串转换回换行符,例如sed
(使用制表符作为连接字符):
$ ./join-lines.pl test_long_sentence.txt | grep Witch | sed -e 's/\t/\n/g'
20 /test1/target="Adults, \"Goblins\", Elderly,
Babies, \"Witch\",
Faries"
另一个例子,使用更长的字符串来连接行:
./join-lines.pl test_long_sentence.txt | grep Witch | sed -e 's/ ===NL=== /\n/g'