如何获得符合grepexpression式的行之后的文件部分? (第一场比赛)

我有一个约1000行的文件。 我希望我的文件的部分在符合我的grep语句的行之后。

$ cat file | grep 'TERMINATE' // Its found on line 534 

所以,我想要从第535 to line 1000进行进一步处理。

我该怎么做 ?

以下将打印匹配TERMINATE的行直到文件结尾:

 sed -n -e '/TERMINATE/,$p' 

说明: -n在执行脚本之后禁用每行打印sed的默认行为, -e表示脚本为sed/TERMINATE/,$是地址(行)范围select,表示匹配TERMINATE正则expression式的第一行(如grep)到文件结尾( $ ), p是打印当前行的打印命令。

这将从行匹配TERMINATE到文件末尾的行打印:
(从匹配行到EOF之后,不包括匹配行)

 sed -e '1,/TERMINATE/d' 

说明: 1,/TERMINATE/是一个地址(行)范围select,意思是第一行input到与TERMINATE正则expression式匹配的第一行, d是删除当前行并跳到下一行的delete命令。 由于sed默认行为是打印行,它将在TERMINATE之后打印行到input结束。

编辑:

如果你想在TERMINATE之前的行:

 sed -e '/TERMINATE/,$d' 

如果你想在TERMINATE之前和之后的两行不同的文件在一个单一的通行证:

 sed -e '1,/TERMINATE/w before /TERMINATE/,$w after' file 

之前和之后的文件将包含终止行,因此处理每个你需要使用:

 head -n -1 before tail -n +2 after 

EDIT2:

如果您不想在sed脚本中对文件名进行硬编码,您可以:

 before=before.txt after=after.txt sed -e "1,/TERMINATE/w $before /TERMINATE/,\$w $after" file 

但是,那么你必须逃避最后一行的$ ,所以shell不会尝试扩展$wvariables(注意我们现在在脚本周围使用双引号而不是单引号)。

我忘了告诉脚本中的文件名后新行是重要的,以便sed知道文件名结束。

编辑: 2016-0530

SébastienClément问道:“你将如何用variablesreplace硬编码的TERMINATE

您将为匹配的文本创build一个variables,然后以与前一个示例相同的方式进行操作:

 matchtext=TERMINATE before=before.txt after=after.txt sed -e "1,/$matchtext/w $before /$matchtext/,\$w $after" file 

在前面的例子中为匹配的文本使用一个variables:

 ## Print the line containing the matching text, till the end of the file: ## (from the matching line to EOF, including the matching line) matchtext=TERMINATE sed -n -e "/$matchtext/,\$p" 
 ## Print from the line that follows the line containing the ## matching text, till the end of the file: ## (from AFTER the matching line to EOF, NOT including the matching line) matchtext=TERMINATE sed -e "1,/$matchtext/d" 
 ## Print all the lines before the line containing the matching text: ## (from line-1 to BEFORE the matching line, NOT including the matching line) matchtext=TERMINATE sed -e "/$matchtext/,\$d" 

在这些情况下,用variablesreplace文本的重点是:

  1. single quotes [ ' ]中包含的variables( $variablename )将不会“展开”,而是double quotes [ " ]中的variables将会。因此,如果包含要replace的文本,则必须将所有single quotes更改为double quotes一个variables。
  2. sed范围还包含一个$ ,紧接着是一个字母,例如: $p$d$w 。 它们也会看起来像要扩展的variables,所以你必须用$ \$p\$d\$w这样的反斜杠来转义这些$字符。

作为一个简单的近似值,你可以使用

 grep -A100000 TERMINATE file 

这会导致TERMINATE并在该行之后输出最多100000行。

从手册页

-A NUM, --after-context=NUM

匹配行后,打印NUM行结尾的上下文。 在连续的匹配组之间放置一个包含组分隔符( – )的行。 使用-o或–only-matching选项,这不起作用,并给出警告。

这里使用的工具是awk:

 cat file | awk 'BEGIN{ found=0} /TERMINATE/{found=1} {if (found) print }' 

这个怎么用:

  1. 我们将variables'found'设置为零,评估为false
  2. 如果在正则expression式中find“TERMINATE”匹配,我们将其设置为1。
  3. 如果我们的“发现”variables评估为真,打印:)

其他解决scheme可能会消耗大量的内存,如果您在非常大的文件上使用它们。

使用bash参数扩展如下:

 content=$(cat file) echo "${content#*TERMINATE}" 

如果我正确理解你的问题,你需要 TERMINATE 之后的行,不包括TERMINATE -line。 awk可以用一个简单的方法来做到这一点:

 awk '{if(found) print} /TERMINATE/{found=1}' your_file 

说明:

  1. 虽然不是最佳实践,但您可以依赖所有variables默认为0或空string(如果未定义)的事实。 所以第一个expression式( if(found) print )将不会打印任何东西。
  2. 打印完成后,我们检查这是否是起始行(不应该包括在内)。

这将打印TERMINATE -line 之后的所有行。


概括:

  • 你有一个开始结束的文件,你需要这些行之间的行, 不包括 开始结束行。
  • 开始结束行可以通过匹配行的正则expression式来定义。

例:

 $ cat ex_file.txt not this line second line START A good line to include And this line Yep END Nope more ... never ever $ awk '/END/{found=0} {if(found) print} /START/{found=1}' ex_file.txt A good line to include And this line Yep $ 

说明:

  1. 如果发现终止线,则不应该进行打印。 请注意,此检查在实际打印之前完成以将结果排除在结果之外。
  2. 打印当前行,如果found设置。
  3. 如果find起始行,则设置found=1以便打印下列行。 请注意,此检查是实际打印之后完成的以便从结果中排除起始行

笔记:

  • 代码依赖于所有awk-vars默认为0或空string(如果未定义)的事实。 这是有效的,但可能不是最好的做法,所以你可以添加一个BEGIN{found=0}到awkexpression式的开头。
  • 如果find多个开始块 ,则全部打印。

如果出于任何原因,你想避免使用sed,下面将打印匹配TERMINATE的行直到文件的结尾:

 tail -n "+$(grep -n 'TERMINATE' file | head -n 1 | cut -d ":" -f 1)" file 

下面将从下面的行匹配TERMINATE直到文件结尾:

 tail -n "+$(($(grep -n 'TERMINATE' file | head -n 1 | cut -d ":" -f 1)+1))" file 

它需要两个进程来完成sed在一个进程中可以执行的操作,如果在执行grep和tail之间文件发生变化,结果会变得不连贯,所以我build议使用sed。 而且,如果文件不包含TERMINATE ,则第一个命令失败。

使用sedawk有很多种方法:

 sed -n '/TERMINATE/,$p' file 

这将在您的文件中查找TERMINATE并从该行打印直到文件末尾。

 awk '/TERMINATE/,0' file 

这与sed行为完全相同。

如果您知道要开始打印的行号,可以将其与NR (logging号,最终表示行号)一起指定:

 awk 'NR>=535' file 

 $ seq 10 > a #generate a file with one number per line, from 1 to 10 $ sed -n '/7/,$p' a 7 8 9 10 $ awk '/7/,0' a 7 8 9 10 $ awk 'NR>=7' a 7 8 9 10 

grep -A 10000000'TERMINATE'文件

  • 比sed快得多,特别是在真正的大文件上工作。 它可以运行多达1000万行(或者你input的任何内容),所以这个大小足以处理你所碰到的任何事情都没有什么坏处。

jfgagne优秀sed答案的替代scheme,其中不包含匹配的行:

这可能是一个办法。 如果你知道文件的哪一行你有你的grep单词和你的文件中有多less行:

grep -A466'TERMINATE'文件

sed是一个更好的工具:sed -n'/ re /,$ p'文件

re是正则expression式。

另一个选项是grep的 – 上下文标志。 你需要传入一个数字来结束,在文件上使用wc应该给出正确的值停止在。 将这与-n和你的匹配expression式结合起来。

这些将打印最后find的行“TERMINATE”的所有行,直到文件结束:

 LINE_NUMBER=`grep -o -n TERMINATE $OSCAM_LOG|tail -n 1|sed "s/:/ \\'/g"|awk -F" " '{print $1}'` tail -n +$LINE_NUMBER $YOUR_FILE_NAME