如何列印和 之前的行之後的行第三行

如何列印和 之前的行之後的行第三行

所問的問題這裡要求在模式匹配之前和之後輸入一些行。

但這裡的目標是獲取行號並從文件中獲取行號之前和之後的一些行

例如:

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,腳本退出。

兩種替代方案都將顯示輸入資料的一部分,從xline 之前的行開始,到line 之後的行z結束。yz

答案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

相關內容