我发现了一个类似的问题这里,但这并不完全是我想要的。
假设我有一个像这样的文本文件:
[...]
age: 10
country: United States
city: New York
name: John
age: 27
country: Canada
city: Toronto
name: Robert
age: 32
country: Mexico
city: Guadalajara
name: Pedro
[...]
我想匹配以“name: Robert”开头的行,并打印前 3 行以及匹配的结果,只得到这些行:
age: 27
country: Canada
city: Toronto
name: Robert
我如何在终端中执行此操作?
答案1
使用grep
$ grep -B3 '^name: Robert$' input_file
age: 27
country: Canada
city: Toronto
name: Robert
答案2
您已经有了最好的方法,只需使用grep -B
,但您也可以在“段落模式”下使用 perl 。此模式由开关启用-00
,意味着“行”现在由两个连续的换行符定义,基本上是一个段落。这可以让您执行以下操作:
$ perl -00 -ne 'print if /name: Robert\b/' file
age: 27
country: Canada
city: Toronto
name: Robert
$
awk
您还可以通过将记录分隔符 ( RS
) 设置为空 ( )来执行相同的操作''
:
$ awk -v RS='' '/name: Robert$/' file
age: 27
country: Canada
city: Toronto
name: Robert
$
awk 的另一个优点是不会像 perl 那样打印额外的换行符。
答案3
数据的格式与 GNU recutils 使用的“recfile 格式”相同。这意味着我们可以像这样查询您的文件:
$ recsel -e 'name = "Pedro"' file
age: 32
country: Mexico
city: Guadalajara
name: Pedro
要获取 20 岁或以上每个人的姓名:
$ recsel -e 'age >= 20' -P name file
Robert
Pedro
ETC。
请参阅info recutils
或GNU reutils 网站了解更多信息。
答案4
使用行编辑器,ed
我们首先选择目标行(g//),然后在其周围创建一个范围(-3,.),并在该范围上运行命令(p)
ed -s inp <<\eof
g/^name: Robert$/-3,.p
eof
## Gnu sed in extended regex mode
## collect 4 lines in pattern space then print the whole pattern space on match else clip first line and append the next
sed -E ':1;$!{N;/(.*\n){3}/!b1;/\nname: Robert$/b};D' file
# using the -p option to autoprint current record
perl -00 -pe '($_)=/((?:.*\n){3}name: Robert\n)/' file
输出:
age: 27
country: Canada
city: Toronto
name: Robert