所问的问题这里要求在模式匹配之前和之后输入一些行。
但这里的目标是获取行号并从文件中获取行号之前和之后的一些行
例如:
seq 10
1
2
3
4
5
6
7
8
9
10
如果行号为 6,则应在该行之前提供 4 个数字,在该行之后提供 3 个数字。那是
2
3
4
5
6
7
8
9
答案1
z=6 # focus line
x=4 # lines before
y=3 # lines after
start=$(( z - x ))
end=$(( z + y ))
使用sed
:
seq 10 | sed -n "$start,${end}p"
2
3
4
5
6
7
8
9
这只是使用 print ( p
) 命令来sed
打印明确的行范围。使用 忽略其他行-n
。
使用awk
:
seq 10 | awk -v start="$start" -v end="$end" 'NR >= start { print } NR >= end { exit }'
2
3
4
5
6
7
8
9
这与 Stéphane Chazelas 的答案类似,但在 中实现awk
;脚本在读取start
行数后开始输出输入行。在行数处end
,脚本退出。
两种替代方案都将显示输入数据的一部分,从x
line 之前的行开始,到line 之后的行z
结束。y
z
答案2
使用 POSIX shell:
$ before=4 after=3 line=6
$ seq 10 | sed "$((line-before)),\$!d; $((line+after))q"
2
3
4
5
6
7
8
9
翻译为:
- d
!
从范围中删除除 ( ) 之外的任何行行 - 之前第一项到最后($
)。 - q适合于行+之后第三行
这样我们就不用费心去阅读过去的内容了行+之后th行。
然而,这意味着sed
如果该命令在发送数据后不久继续发送数据,则该命令将通过 SIGPIPE 中止,这可能是所希望的,也可能不是所希望的。
答案3
只是为了完整性:
$ l=60;seq 100 |head -n$((l+3)) |tail -n+$((l-4))
56
57
58
59
60
61
62
63
谣言和各种基准测试表明 head + tail 的组合比任何其他工具都要快得多:
$ a=1000000000
$ time seq $a |awk 'NR>=499998{print}NR >= 500004 { exit }'
499998
499999
500000
500001
500002
500003
real 0m0.158s
user 0m0.152s
sys 0m0.004s
$ time seq $a |sed -n "499998,500003p"
499998
499999
500000
500001
500002
500003
real 1m30.249s
user 1m21.284s
sys 0m12.312s
$ time seq $a |sed "$((500000-2)),\$!d; $((500000+3))q" #Stephan's Solution
499998
499999
500000
500001
500002
500003
real 0m0.052s
user 0m0.044s
sys 0m0.004s
$ time seq $a |head -n$((500000+3)) |tail -n+$((500000-2))
499998
499999
500000
500001
500002
500003
real 0m0.024s
user 0m0.024s
sys 0m0.004s
$ time seq $a |sed -n "499998,500003p;500004q"
499998
499999
500000
500001
500002
500003
real 0m0.056s
user 0m0.048s
sys 0m0.004s
答案4
# define line range constants
before=4
line=6
after=3
# setup the sed commands s.t. pattern space holds $before number
# of lines before we hit the line number $line and $after after
s='$!N'
p=`seq -s "$s" "$before"`
a=`seq -s "$s" 0 "$after"`
N=${p//[0-9]/;}
n=${a//[0-9]/;}
# main...
seq 10 |
sed -e "
1{ $N }
\$d;N
$line!D
$n;q
"
另一种方法是读取文件并将 设为 ,FS
以便\n
字段(现在是行)位于@F
.剩下的就是围绕第 6 行以及之前的 4 个元素和之后的 3 行进行切片:
perl -alF\\n -0777ne '$,=$\;print @F[6-4-1..6+3-1]' yourfile
结果
2
3
4
5
6
7
8
9