【问题标题】:grep / awk / perl / sed - print all lines that match X, ignore lines that only have YX and include lines that have YX ZXgrep / awk / perl / sed - 打印所有匹配 X 的行,忽略只有 YX 的行并包括有 YX ZX 的行
【发布时间】:2014-11-14 02:14:40
【问题描述】:
我有一个文件 (tmp.txt),如下所示:
first
first rst
allrst
printf "first\nfirst rst\nallrst\n" > tmp.txt;
我想要:
first rst
allrst
有没有办法搜索“rst”,但如果 rst 只在第一个找到,则排除匹配项?
我试过了:
awk '(/rst/ && /first/) || (/rst/ && !/first/)' tmp.txt
【问题讨论】:
标签:
regex
perl
awk
sed
grep
【解决方案1】:
使用不带-P 选项的grep:
grep 'rst' file | grep -v '^first$'
first rst
allrst
使用grep -P
grep -P '^(?!first$).*rst' file
first rst
allrst
【解决方案3】:
或vks回答的变体
^(.*(?<!fi)rst.*)$
Demo
^ Start of string
( Capturing Group \1
. Any character except line break
* (zero or more)(greedy)
(?<! Negative Look-Behind
fi "fi"
) End of Negative Look-Behind
rst "rst"
. Any character except line break
* (zero or more)(greedy)
) End of Capturing Group \1
$ End of string
【解决方案4】:
Perl 中的正则表达式是/^.*(?<!fi)rst.*/m
^ .*
(?<! fi )
rst .*
【解决方案5】:
你没有定义,rst 必须在行尾,所以这可能符合你的要求:
grep -P '(?<!fi)rst' file
【解决方案6】:
这可能对你有用(GNU sed):
sed 'h;s/first//g;/rst/!d;g' file
复制当前行。删除所有first 并检查rst 的剩余行。如果字符串在更改的行中,则打印副本,否则删除该行。
【解决方案7】:
这满足您的所有要求:
perl -ne 'print if /^(?=.*first)(?=.*(?<!fi)rst)/; next if /first/; print if /rst/'
- 行有“第一个”和一个非第一个“rst”:打印它
- 行有“第一”:跳过它
- 行有“rst”:打印它
或者,正如你的标题所暗示的,象征性地
perl -ne '
BEGIN {$x="rst"; $y="fi"; $z="(?<!fi)"}
print if /^(?=.*$y$x)(?=.*$z$x)/; next if /$y$x/; print if /$x/
'
【解决方案8】:
恕我直言,模式没有精确指定。如果该行包含afirst 或rstfirst,应该怎么办?所以我创建了两个版本。我假设每一行都包含字符串rst。不是,它不需要打印。我更喜欢 awk 解决方案而不是 perl,因为后者使用更多资源来启动,并且此任务并不真正需要它。
第一个版本检查所有包含rst,但不等于first 的单词。如果找到,则打印该行。
awk '/rst/ {
for(i=1;i<=NF&&$i~/rst/&&$i=="first";++i);
}i<=NF' inputfile
输入文件:
first
first rst
allrst
afirst
rstfirst
输出:
first rst
allrst
afirst
rstfirst
另一种解决方案检查所有rst,然后添加前两个字符(如果适用)。如果结果字符串不是first,则打印该行。 (类似于sln 的负后视缓冲区perl 解决方案)
awk '/rst/ {
for(s=$0;i=index(s,"rst");s=substr(s,i+1))
if (i<2 || substr(s,i-2,5)!="first") {print; break}
}' inputfile
输出:
first rst
allrst
rstfirst
我希望这会有所帮助!
【解决方案9】:
sed -n '1!{/rst/p}' tmp.txt
如果不在第一行,则打印与该行中模式 rst 的匹配项,或者如果您想计算 rst 但不单独在 first 中 - 仅当 rst 也在另一个字符串中时:
sed -n '/[^f][^i]rst/p' tmp.txt
或者如果你想使用 Bash shell,你可以更灵活地满足类似的要求:
while read -r a; do
num_first=$(echo "$a" | grep -c 'first');
num_rst=$(echo "$a" | sed 's/first//g' | grep -c 'rst');
if [[ $num_rst+1 -gt $num_first ]]; then
echo "$a";
fi done < tmp.txt
此代码先使用 grep 计数,然后使用 rst - 只有当 rst 大于字符串时才会打印字符串。
作为单行:
while read -r a; do num_first=$(echo "$a" | grep -c 'first');num_rst=$(echo "$a" | sed 's/first//g' | grep -c 'rst'); if [[ $num_rst+1 -gt $num_first ]]; then echo "$a"; fi done < myfile