一致した行の前の n 行目、一致した行、一致した行から n 行目 (n は 2 より大きい) を印刷します。
ここに私のデータ ファイルの例を示します (以下の行番号はデータの一部ではなく、識別のためだけのものです)。私が検索しているパターンは、ファイル内の「blah」ですexample.txt
。
$ cat example.txt
1. a
2. b
3. c
4. d
5. blah
6. e
7. f
8. g
9. h
10. blah
11. i
12. f
13. g
14. h
そして、出力は次のようになります:
1. b
2. blah
3. g
4. f
5. blah
6. g
ワンライナーを提案してください!
答え1
awk -vn=3 '/blah/{print l[NR%n];print;p[NR+n]};(NR in p);{l[NR%n]=$0}'
これは重複がないことを前提としています。重複がある場合は、関連するすべての行が印刷されますが、複数回印刷される可能性があり、必ずしも入力と同じ順序であるとは限りません。
これを回避するには、次のように記述します。
awk -vn=3 '/blah/{p[NR-n]p[NR]p[NR+n]};(NR-n in p){print l[NR%n]}
{l[NR%n]=$0};END{for(i=NR-n+1;i<=NR;i++)if (i in p) print l[i%n]}'
次のような入力の場合:
1
2
3
4
blah1
5
6
blah2
blah3
7
8
9
10
最初のものは次のようになります:
2
blah1
blah1
blah2
blah2
5
blah3
8
9
2 番目は次のように出力されます:
2
blah1
5
blah2
blah3
8
9
答え2
以下は Perl のワンライナーです:
$ perl -ne '$n=3;push @lines,$_; END{for($i=0;$i<=$#lines;$i++){
if ($lines[$i]=~/blah/){
print $lines[$i-$n],$lines[$i],$lines[$i+$n]}}
}' example.txt
b
blah
g
f
blah
g
周囲の行の数を変更するには、 ( は希望する数)に変更します。$n=3;
一致するパターンを変更するには、を に変更します。$n=N
N
if ($lines[$i]=~/blah/)
if ($lines[$i]=~/PATTERN/)
数字が実際にファイルの一部である場合は、次のようにすることができます。
$ perl -ne '$n=3;push @lines,$_; END{for($i=0;$i<=$#lines;$i++){
if ($lines[$i]=~/blah/){
print $lines[$i-$n],$lines[$i],$lines[$i+$n]}}
}' example.txt | perl -pne 's/\d+/$./'
1. b
2. blah
3. g
4. f
5. blah
6. g
答え3
以下は @terdon の回答と似ていますが、メモリには 2n+1 の関連行のみが保持されます。
my $n = shift;
my $pattern = shift;
my @lines = ("\n") x (2*$n+1);
while (<>) {
shift @lines;
push @lines, $_;
if ($lines[$n] =~ m/$pattern/) {
print $lines[0], $lines[$n], $lines[-1];
}
}
次のように実行します:perl example.pl 3 blah example.txt
答え4
あまり効率的ではありません。grep を使用して行番号を取得し、sed を使用して行番号を出力します。
for n in `grep -n blah example.txt | sed -e s/:.*//`
do
sed -n -e "$[$n-3]p" -e "$[$n]p" -e "$[$n+3]p" example.txt
done
結果的に
2. b
5. blah
8. g
7. f
10. blah
13. g
いずれかの数値が範囲外になった場合は、おそらく失敗するでしょう。