如何获得符合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不会尝试扩展$w
variables(注意我们现在在脚本周围使用双引号而不是单引号)。
我忘了告诉脚本中的文件名后新行是重要的,以便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文本的重点是:
- 在
single quotes
['
]中包含的variables($variablename
)将不会“展开”,而是double quotes
["
]中的variables将会。因此,如果包含要replace的文本,则必须将所有single quotes
更改为double quotes
一个variables。 -
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 }'
这个怎么用:
- 我们将variables'found'设置为零,评估为false
- 如果在正则expression式中find“TERMINATE”匹配,我们将其设置为1。
- 如果我们的“发现”variables评估为真,打印:)
其他解决scheme可能会消耗大量的内存,如果您在非常大的文件上使用它们。
使用bash参数扩展如下:
content=$(cat file) echo "${content#*TERMINATE}"
如果我正确理解你的问题,你需要在 TERMINATE
之后的行,不包括TERMINATE
-line。 awk
可以用一个简单的方法来做到这一点:
awk '{if(found) print} /TERMINATE/{found=1}' your_file
说明:
- 虽然不是最佳实践,但您可以依赖所有variables默认为0或空string(如果未定义)的事实。 所以第一个expression式(
if(found) print
)将不会打印任何东西。 - 打印完成后,我们检查这是否是起始行(不应该包括在内)。
这将打印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 $
说明:
- 如果发现终止线,则不应该进行打印。 请注意,此检查在实际打印之前完成,以将结果排除在结果之外。
- 打印当前行,如果
found
设置。 - 如果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
,则第一个命令失败。
使用sed
或awk
有很多种方法:
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,其中不包含匹配的行:
-
awk '/TERMINATE/ {y=1;next} y'
( https://stackoverflow.com/a/18166628 ) -
awk '/TERMINATE/ ? c++ : c'
awk '/TERMINATE/ ? c++ : c'
( https://stackoverflow.com/a/23984891 ) -
perl -ne 'print unless 1 .. /TERMINATE/'
)
这可能是一个办法。 如果你知道文件的哪一行你有你的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