質問はここパターンマッチの前後のいくつかの行を要求します。
しかし、ここでの目的は、行番号を取得し、その前後の行をファイルから取得することです。
例えば:
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
どちらの選択肢も、行の前の行から行の後のz
行まで入力データの一部を表示します。y
z
答え2
POSIX シェルの場合:
$ 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ウイットオン行 + 後行目
そうすれば、私たちは行 + 後行目。
ただし、これは、データを供給するコマンドが、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
を に設定することです。 残っているのは、6 行目とその前の 4 つの要素、および後の 3 行をスライスすることです。\n
@F
perl -alF\\n -0777ne '$,=$\;print @F[6-4-1..6+3-1]' yourfile
結果
2
3
4
5
6
7
8
9