如何在匹配grep表达式的行之后获取文件的一部分? (第一场比赛)

时间:2011-08-18 06:57:40

标签: bash shell scripting grep

我有一个大约1000行的文件。我希望我的文件的一部分在与我的grep语句匹配的行之后。

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

所以,我希望来自行535 to line 1000的文件进行进一步处理。

我该怎么做?

12 个答案:

答案 0 :(得分:273)

以下内容将打印匹配TERMINATE的行,直到文件末尾:

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

解释: -n禁用在{1}}上执行其脚本后打印每一行的默认行为,sed表示脚本为-e },sed是一个地址(行)范围选择,意味着第一行与/TERMINATE/,$正则表达式(如grep)匹配到文件末尾(TERMINATE),{{1是打印当前行的打印命令。

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

p

解释: TERMINATE是一个地址(行)范围选择,意味着第一行输入的第一行与sed -e '1,/TERMINATE/d' 正则表达式匹配,{{1删除命令是删除当前行并跳到下一行。由于1,/TERMINATE/默认行为是打印行,它会在TERMINATE之后打印行到输入结尾。

修改

如果您想要d之前的行:

sed

如果你想在一次通过的2个不同文件中TERMINATE之前和之后的两行:

TERMINATE

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

sed -e '/TERMINATE/,$d'

<强> EDIT2:

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

TERMINATE

但是你必须转义sed -e '1,/TERMINATE/w before /TERMINATE/,$w after' file 意味着最后一行,所以shell不会尝试扩展head -n -1 before tail -n +2 after 变量(注意我们现在在脚本周围使用双引号而不是单引号)

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


修改 2016-0530

SébastienClément问道:“你如何用变量替换硬编码的before=before.txt after=after.txt sed -e "1,/TERMINATE/w $before /TERMINATE/,\$w $after" file ?”

您可以为匹配的文本创建一个变量,然后以与上一个示例相同的方式执行此操作:

$

将匹配文本的变量用于前面的示例:

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

在这些情况下,用变量替换文本的重点是:

  1. ## 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" )不会“展开”,但$variablename [single quotes]中的变量会出现。因此,如果它们包含要用变量替换的文本,则必须将所有'更改为double quotes
  2. "范围也包含single quotes,后面跟着一个字母,如:double quotessed$。它们看起来也像要扩展的变量,因此您必须使用反斜杠[$p]转义那些$d个字符,例如:$w$,{{1} }。

答案 1 :(得分:60)

作为简单的近似,您可以使用

grep -A100000 TERMINATE file

TERMINATE进行grep,并在该行后输出最多100000行。

来自手册页

  

-A NUM, --after-context=NUM

     

在匹配行后打印NUM行尾随上下文。   放置一个包含组分隔符( - )的行   连续的比赛组。使用-o或--only匹配   选项,这没有效果,并给出警告。

答案 2 :(得分:26)

这里使用的工具是awk:

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

这是如何运作的:

  1. 我们将变量'found'设置为零,评估为false
  2. 如果找到与正则表达式匹配的'TERMINATE',我们将其设置为1。
  3. 如果我们的'found'变量的计算结果为True,则打印:)
  4. 如果您在非常大的文件上使用它们,其他解决方案可能会占用大量内存。

答案 3 :(得分:7)

使用bash参数扩展,如下所示:

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

答案 4 :(得分:7)

如果我正确理解了您的问题,您确实需要 TERMINATE之后的行,而不包括TERMINATE行。 awk可以通过简单的方式完成此操作:

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

说明:

  1. 虽然不是最佳实践,但您可以依赖于所有变量默认为0或空字符串(如果未定义)的事实。因此,第一个表达式(if(found) print)将不会打印任何内容。
  2. 打印完成后,我们检查这是否是起动线(不应包括在内)。
  3. 这将打印 TERMINATE - 行后的所有行

    <强>概括

    • 您的文件包含开始 - 和结束 -lines,您希望这些行之间的行排除 开始< / strong> - 和结束 -lines。
    • 开始 - 结束 -lines可以通过与该行匹配的正则表达式定义。

    示例:

    $ 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. 如果找到结束 -line,则不应进行打印。请注意,此检查是在 实际打印之前完成的,以便从结果中排除结束 -line。
    2. 如果设置了found,则打印当前行。
    3. 如果找到开始 -line,则设置found=1以便打印以下行。请注意,此检查在 实际打印后完成,以从结果中排除开始 -line。
    4. 注意:

      • 代码依赖于以下事实:如果未定义,则所有awk-vars默认为0或空字符串。这是有效的,但可能不是最佳做法,因此您可以在awk-expression的开头添加BEGIN{found=0}
      • 如果找到多个 start-end -blocks,则会全部打印出来。

答案 5 :(得分:4)

grep -A 10000000'TERMINATE'文件

  • 比sed快得多,特别是在真正的大文件上工作。它可以工作多达1000万行(或者你输入的任何东西),所以没有任何伤害使它足以处理你所击中的任何东西。

答案 6 :(得分:3)

如果出于任何原因,您希望避免使用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可以执行的操作需要2个进程,如果文件在执行grep和tail之间发生更改,则结果可能会不连贯,因此我建议使用sed。此外,如果文件dones不包含TERMINATE,则第一个命令失败。

答案 7 :(得分:2)

使用sedawk

可以通过多种方式完成此操作
sed -n '/TERMINATE/,$p' file

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

awk '/TERMINATE/,0' file

这与sed完全相同。

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

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

答案 8 :(得分:0)

jfgagne提供的优秀clang答案的替代方案,并且不包括匹配的行:

答案 9 :(得分:0)

这可能是一种做法。如果您知道文件的哪一行,那么您的grep单词和文件中有多少行:

grep -A466'TERMINATE'文件

答案 10 :(得分:-1)

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

其中re是regexp。

另一种选择是grep的--after-context标志。你需要传入一个数字来结束,使用文件上的wc应该给出正确的值来停止。将此与-n和您的匹配表达式结合使用。

答案 11 :(得分:-2)

这些将打印从最后找到的行“TERMINATE”到文件结尾的所有行:

transition