匹配后如何打印所有行至文件末尾?


48

输入文件1为:

dog 123 4335
cat 13123 23424 
deer 2131 213132
bear 2313 21313

我给匹配从中的模式other file(如dog 123 4335从file2)。

我匹配该行的模式,dog 123 4335并且在打印不匹配行的所有行后,我的输出是:

cat 13123 23424
deer 2131 213132
bear 2313 21313

如果仅使用无行地址仅使用模式,例如1s 如何匹配并打印行?


其他文件可以仅包含一个要搜索的模式,也可以仅包含每行一个模式,然后从搜索到的文件中第一个找到的行开始搜索吗?
Ciro Santilli新疆改造中心法轮功六四事件

Answers:


27

假设您想使用GNU将整个行与您的模式匹配sed,则可以这样做:

sed -n '/^dog 123 4335$/ { :a; n; p; ba; }' infile

等效标准:

sed -ne '/^dog 123 4335$/{:a' -e 'n;p;ba' -e '}' infile

使用以下输入(infile):

cat 13123 23424 
deer 2131 213132
bear 2313 21313
dog 123 4335
cat 13123 23424 
deer 2131 213132
bear 2313 21313

输出为:

cat 13123 23424 
deer 2131 213132
bear 2313 21313

说明:

  • /^dog 123 4335$/ 搜索所需的模式。
  • :a; n; p; ba;是一个循环,该循环从输入(n)获取新行,将其打印(p),然后分支回到标签a :a; ...; ba;

更新资料

这是一个更贴近您需求的答案,即file2中的模式,从file1中grepping:

tail -n +$(( 1 + $(grep -m1 -n -f file2 file1 | cut -d: -f1) )) file1

嵌入式grep和cut从file2中找到包含模式的第一行,此行号加一个传递到尾部,那里加一个以跳过包含模式的行。

如果要从最后一场比赛而不是第一场比赛开始,那就是:

tail -n +$(( 1 + $(grep -n -f file2 file1 | tail -n1 | cut -d: -f1) )) file1

请注意,并非所有版本的tail都支持加号。


这是sed中n和p命令的第一个示例,我发现这似乎不希望将sed放得太远。从我的简短测试来看,sed -n '/^dog 123 4335$/ { :a; p; n; ba; }' infile(在切换了p和n的情况下)似乎成功也包含了匹配的行。
Josiah Yoder

26

如果只有一个足够短的文件grep可能会起作用:

grep -A5000 -m1 -e 'dog 123 4335' animals.txt

5000只是我对“合理短”的猜测,因为它grep找到了第一个匹配项并与接下来的5000行一起输出(文件不需要那么多)。如果您不想要比赛本身,则需要将其切断,例如

grep -A5000 -m1 -e 'dog 123 4335' animals.txt | tail -n+2


如果您不希望将第一个但最后一个匹配项用作分隔符,则可以使用以下命令:

tac animals.txt | sed -e '/dog 123 4335/q' | tac

该行animals.txt以与行相反的顺序读取,并输出到并包含行,dog 123 4335然后再次反转以恢复正确的顺序。

同样,如果您不需要结果中的匹配项,请附加尾部。(您还可以使sed表达式复杂化,以在退出前丢弃其缓冲区。)


根据我的测试,GNU grep 3.0在后续上下文中输出的行数不超过132行(无论指定值如何)。
ruvim

22

在实践中,我可能大部分时间都使用Aet3miirah的答案,而alexey的答案在想要浏览各行时也很棒(也适用于less)。太太,我真的很喜欢另一种方法(这与吉尔斯的回答相反:

sed -n '/dog 123 4335/,$p'

当使用-n标志调用时,sed默认情况下不再打印其处理的行。然后,我们使用2地址格式表示从行匹配/dog 123 4335/开始应用命令,直到文件结尾(以表示$)。有问题的命令是p,它显示当前行。因此,这意味着“打印从一个匹配项/dog 123 4335/到最后一行的所有行”。


3
dog尽管这里不需要打印行。
斯特凡Chazelas

1
这看起来是最好的答案(并且适用于我自己的情况),但也需要进行调整以跳过匹配的行。
PavelŠimerda'16

1
sed -n'/ dog 123 4335 /,$ p'| sed'1d'将删除狗行
Kemin Zhou '18

1
sed -n '/dog 123 4335/,$p' | tail -n +2将删除匹配以及
吉拉德mayani

15
sed -e '1,/dog 123 4335/d' file1

如果需要从文件读取模式,请将其替换为sed命令。如果文件包含sed模式:

sed -e "1,/$(cat file2)/d" file1

如果文件包含要查找的文字字符串,请用引号将所有特殊字符引起来。我假设文件只包含一行。

sed -e "1,/$(sed 's/[][\\\/^$.*]/\\&/g' file2)/d" file1

如果要使匹配成为整行,而不仅仅是子字符串,请将模式包装在中^…$

sed -e "1,/^$(sed 's/[][\\\/^$.*]/\\&/g' file2)\$/d" file1

6
如果模式在第一行,那将行不通。GNU sed都有0,/dog.../d了点。
斯特凡Chazelas

14

$ more +/"dog 123 4335" file1


4
它也适用于less
brandizzi

3
在终端上比较聪明,但是如果您将其通过管道连接到其他类似的设备上,则实际上不会起作用tac
jcomeau_ictx

我正在这样使用它,$更多+ /“匹配我的话” file1 >> file2
AMB

1
也许在POSIX 7中+已被替换-ppubs.opengroup.org/onlinepubs/9699919799/utilities/more.html,但尚未在util-linux 2.20.1中实现。而且这还会打印skipping..和一些额外的换行符(对于我期望的stderr,可能会很好)。
Ciro Santilli新疆改造中心法轮功六四事件

从那以后也许情况发生了变化?我的评论获得3票赞成,因此在当时可能是有意义的……
jcomeau_ictx

11

awk

awk 'BEGIN {getline pattern < "other file"}
   NR == 1, $0 ~ pattern {next}; {print}' < "input file"

5

一种使用awk的方法:

awk 'NR==FNR{a[$0];next}f;($0 in a){f=1}'  file2 file1

其中file2包含您的搜索模式。首先,file2的所有内容都存储在数组“ a”中。处理file1时,将针对该数组检查每一行,并仅在不存在时才打印。


我认为OP希望按照模式输出每一行。
雷神

@Thor:感谢您指出来,现在就更新了……
Guru

做得很好 :)。
2012年

5

如果输入是可查找的常规文件:

使用GNU grep

{ grep  -xFm1 'dog 123 4335' >&2
  cat; } <infile 2>/dev/null >outfile

sed

{ sed -n '/^dog 123 4335$/q'
  cat; } <infile >outfile

grep名为w / -moption的GNU 会在比赛中退出输入-它将在找到最后一个匹配点后立即离开其(可搜索的)输入fd。因此,调用grepw /会-m1在文件中找到模式的第一个匹配项,并将输入偏移量恰好留在正确的位置,cat以便将模式中的第一个匹配项之后的所有内容写入文件到stdout中。

即使没有GNU,grep您也可以执行与POSIX兼容的完全相同的操作sed-当sed q指定uits时,将其输入偏移量保留在正确的位置。但是,GNU sed以这种方式不符合标准,因此,sed除非您使用GNU -u开关对其进行调用,否则上述内容可能不适用于GNU 。


注意,sed这里展示了流共享不是特别(虽然,是的,所引用的标准具体确实例如sed作为实用因此能够)中所示的自由形式的和有条件地协同工作流。值得注意的是,所有标准实用程序都应经过指定和指定,以便相互协作并共享输入流的光标位置,而不会使下一个读取器完全失败。grep -q应该这样做;grep找到输入中的任何匹配项后,应该安静地返回,并且默认情况下,标准不应该消耗任何剩余的输入。
mikeserv '18 -10-29

4

我对这个问题的回答,而没有在第二个文件中存储模式。这是我的测试文件:

$ cat animals.txt 
cat 13123 23424 
deer 2131 213132
bear 2313 21313
dog 123 4335
cat 13123 23424 
deer 2131 213132
bear 2313 21313

GNU sed:

 $ sed '0,/^dog 123 4335$/d' animals.txt 
 cat 13123 23424 
 deer 2131 213132
 bear 2313 21313

Perl:

$ perl -ne 'print unless 1.../^dog 123 4335$/' animals.txt
cat 13123 23424 
deer 2131 213132
bear 2313 21313

在文件中带有模式的Perl变体:

$ cat pattern.txt 
dog 123 4335
$ perl -ne 'BEGIN{chomp($p=(<STDIN>)[0])};print unless 1../$p/;' animals.txt < pattern.txt
cat 13123 23424 
deer 2131 213132
bear 2313 21313

2

Wth ed

ed -s file1 <<< '/dog 123 4335/+1,$p'

这将p在此处字符串中向ed 发送一个rint命令;+1dog 123 4335匹配之后直到文件结尾(),打印命令的范围限制为一个$


1

如果您不介意创建一个临时文件并且可以csplit使用它,那么可以这样做:

sh -c 'csplit -sf"$1_" "$1" "%^$(cat "$2")%+1" && cat "${1}_00"' sh file1 file2

注意file1是输入文件,file2是模式文件(如问题所述)。

上述命令的长格式为:

sh -c 'csplit --quiet --prefix="$1_" "$1" "%^$(cat "$2")%+1" && cat "${1}_00"' sh file1 file2

csplit --quiet --prefix="file1_" "file1" "%^$(cat "file2")%+1" && cat "file1_00"

csplit如果没有上述prefix标记,则会创建文件xx00(前缀为xx,后缀为00)。上面的标志会创建文件file1_00。如果没有该quiet标志,它将打印输出文件的大小(结果文件的大小)。


0

由于没有明确禁止awk,因此这是我的产品,假设“ cat”是匹配项。

awk '$0 ~ /cat/ { vart = NR }{ arr[NR]=$0 } END { for (i = vart; i<=NR ; i++) print arr[i]  }' animals.txt

0

匹配后如何打印所有行至文件末尾?

另一种表达方式是“如何从第一行中删除所有行,直到匹配(包括)”,这可以sed写为:

sed -e '1,/MATCH PATTERN/d'

1
唯一的问题是,当模式在第一行时...
don_crissti 2015年


我想我们需要一个委员会来决定。
poige

1
@poige:不,你提供了相同的答案不太全面
托尔

@don_crissti,那sed -e '0,/MATCH PATTERN/d'又如何呢?
Velkan
By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.