Bash 如何获取与正则表达式匹配的第一行之后的文件部分?

Bash 如何获取与正则表达式匹配的第一行之后的文件部分?,bash,shell,scripting,grep,Bash,Shell,Scripting,Grep,我有一个大约1000行的文件。我想要文件中与grep语句匹配的行后面的部分 即: $ cat file | grep 'TERMINATE' # It is found on line 534 因此,我希望文件从第535行到第1000行进行进一步处理 如何才能做到这一点?使用bash参数展开,如下所示: content=$(cat file) echo "${content#*TERMINATE}" 作为一个简单的近似值,您可以使用 grep -A100000 TERMINATE f

我有一个大约1000行的文件。我想要文件中与grep语句匹配的行后面的部分

即:

$ cat file | grep 'TERMINATE'     # It is found on line 534
因此,我希望文件从第535行到第1000行进行进一步处理


如何才能做到这一点?

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

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

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

grep -A100000 TERMINATE file
它greps表示
终止
,并在该行之后输出多达100000行

从手册页

-A NUM,--after context=NUM

在匹配行之后打印尾随上下文的行数。 将包含组分隔符(--)的行放置在 连续的匹配组。使用-o或--only匹配 选项,则此选项无效,并发出警告


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

其中re是regexp


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

以下内容将打印匹配的行
终止
,直到文件结束:

sed -n -e '/TERMINATE/,$p'
tail -n "+$(grep -n 'TERMINATE' file | head -n 1 | cut -d ":" -f 1)" file
tail -n "+$(($(grep -n 'TERMINATE' file | head -n 1 | cut -d ":" -f 1)+1))" file
解释:
-n
禁用
sed
在其上执行脚本后打印每行的默认行为,
-e
指示脚本到
sed
/TERMINATE/,$
是地址(行)范围选择,表示与
TERMINATE
正则表达式匹配的第一行(如grep)到文件的末尾(
$
),而
p
是打印当前行的打印命令

这将从匹配
的行后面的行开始打印,直到文件结束:
(从匹配线后到EOF,不包括匹配线)

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

编辑:

如果要在
终止之前终止

sed -e '/TERMINATE/,$d'
如果您希望在一次传递中在两个不同的文件中终止
前后的两行:

sed -e '1,/TERMINATE/w before
/TERMINATE/,$w after' file
before和after文件将包含带有terminate的行,因此要处理每一行,您需要使用:

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就不会尝试展开
$w
变量(注意,我们现在在脚本周围使用双引号,而不是单引号)

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


编辑:2016-0530

塞巴斯蒂安·克莱门特问:“你将如何用一个变量替换硬编码的
TERMINATE
?”

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

matchtext=TERMINATE
before=before.txt
after=after.txt
sed -e "1,/$matchtext/w $before
/$matchtext/,\$w $after" file
要将变量用于与前面示例匹配的文本,请执行以下操作:

## 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"
在这些情况下,用变量替换文本的要点是:

  • 包含在
    单引号中的变量(
    $variablename
    )不会“展开”,但包含在
    双引号中的变量会“展开”。因此,如果它们包含要用变量替换的文本,则必须将所有
    单引号更改为
    双引号
  • sed
    范围还包含一个
    $
    ,后面紧跟着一个字母,如:
    $p
    $d
    $w
    。它们看起来也像要展开的变量,因此必须用反斜杠[
    \
    转义这些
    $
    字符例如:
    \$p
    \$d
    \$w

  • 如果出于任何原因,您希望避免使用sed,以下内容将打印匹配的行
    TERMINATE
    ,直到文件结束:

    sed -n -e '/TERMINATE/,$p'
    
    tail -n "+$(grep -n 'TERMINATE' file | head -n 1 | cut -d ":" -f 1)" file
    
    tail -n "+$(($(grep -n 'TERMINATE' file | head -n 1 | cut -d ":" -f 1)+1))" file
    
    以下内容将从匹配
    终止的下一行打印到文件末尾:

    sed -n -e '/TERMINATE/,$p'
    
    tail -n "+$(grep -n 'TERMINATE' file | head -n 1 | cut -d ":" -f 1)" file
    
    tail -n "+$(($(grep -n 'TERMINATE' file | head -n 1 | cut -d ":" -f 1)+1))" file
    

    sed可以在一个进程中完成的工作需要两个进程,如果文件在执行grep和tail之间发生变化,结果可能不一致,因此我建议使用sed。此外,如果文件不包含
    TERMINATE
    ,第一个命令将失败。

    此处使用的工具是awk:

    cat file | awk 'BEGIN{ found=0} /TERMINATE/{found=1}  {if (found) print }'
    
    这是如何工作的:

  • 我们将变量“found”设置为零,计算结果为false
  • 如果在正则表达式中找到“TERMINATE”的匹配项,则将其设置为1
  • 如果“found”变量的计算结果为True,请打印:)

  • 如果在非常大的文件上使用其他解决方案,可能会消耗大量内存。

    使用
    sed
    awk
    有很多方法:

    sed -n '/TERMINATE/,$p' file
    
    这将在文件中查找
    终止
    ,并从该行打印到文件末尾

    awk '/TERMINATE/,0' file
    
    这与sed的行为完全相同

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

    例子
    如果我正确理解了您的问题,您确实希望在
    终止
    之后的行,而不包括
    终止
    -行。
    awk
    可以用一种简单的方式完成这项工作:

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

  • 虽然不是最佳实践,但您可以依赖以下事实:所有变量默认为0或空的st
    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