web-dev-qa-db-ja.com

特定のラインX(パターン付き)から他の特定のラインY(パターン付き)への猫のみ

" 巨大なファイルの猫の行xから行y "への少し拡張された問題:

私は巨大なファイル(2-3GB)を持っています。 「foo:」の行から「goo:」の行までだけcat/printしたいのですが。 「foo:」と「goo:」はファイルに一度だけ現れると仮定します。 「foo:」は「goo:」に進みます。

これまでのところ、これが私のアプローチです。

  • まず、「foo:」と「goo:」の行を見つけます:grep -nr "foo:" bigfile
  • 戻り値 123456: foo: hello world!および654321: goo: good bye!
  • これらの開始行番号と終了行番号、および違い(654321-123456 = 530865)がわかれば、選択的な猫を作成できます。
  • tail -n+123456 bigfile | head -n 530865

私の質問は、行番号定数を式(grep ...など)で効果的に置き換えるにはどうすればよいですか?

簡単なPythonスクリプトを書くことはできますが、コマンドを組み合わせるだけでそれを実現したいと思います。

3
Nullptr
sed -n '/foo/,/goo/p;/goo/q' <bigfile

それはそれらの行だけを印刷するでしょう。行番号が必要な場合は、=を追加します。

sed -n '/foo/=;/goo/=;//q' <bigfile

qは、呼び出されたときに入力をquitsするため、重要です。そうでない場合、sedは最後までinfileを読み取り続けます。

foo/goo行を印刷したくない場合は、代わりに次のように実行できます。

GNU sed

sed -n '/foo/,/goo/!d;//!p;/goo/q
' <<\DATA
line1
foo 
line3
line4
line5
goo 
line7
DATA

出力

line3
line4
line5

そして他のものと:

sed -n '/foo/G;/\n/,/goo/!d;//q;/\n/!p 
' <<\DATA
line1
foo 
line3
line4
line5
goo 
line7
DATA    

出力

line3
line4
line5

ただし、いずれにしても、検索の最後の行に到達するとすぐに入力を終了します。

9
mikeserv

サブシェルで何かを使用して行番号を取得し、別のユーティリティがファイルを印刷できるようにするという現在のアプローチを放棄しても問題がない場合、これは純粋なawkでほとんど問題なく実行できます。

行自体ではなく、行betweenfoo:goo:を印刷する場合は、次を使用できます( 元々ここから取得 =):

awk '/goo:/ { exit }; flag; /foo:/ { flag = 1 }' bigFile

上記のexitsは、終了トークン(goo:)を検出し、printがtrueの場合はflagsであり、flagをtrue(1、実際には)オープニングトークン(foo:)に達したとき。

ただし、出力にトークン行を含めたい場合は、コマンドは実際にはさらに単純です。 @ jasonwryanが言及

awk '/foo:/,/goo:/' bigFile

行番号だけを取得し、実際に同じユーティリティでファイルを印刷しないことに夢中になっている場合は、次のように開始トークンと終了トークンの行番号を取得できます。

awk '/foo:|goo:/ { print NR }' bigFile
5
HalosGhost

代替のsed one:

sed '/foo/,$!d;/goo/q'
4

定数を式に置き換えるには、 コマンド置換 を使用できます。

コマンドの出力を式に置き換えるには、$(command)を使用します

この場合、適切なコマンドラインは次のとおりです。

tail -n+$(grep -nr "foo:" bigfile | cut -d':' -f1) bigfile | \
head -n$(($(grep -nr "goo:" bigfile | cut -d':' -f1)-$(grep -nr "foo:" bigfile | cut -d':' -f1)+1))

これにより、foo:を含む行からgoo:を含む行までのすべての行が出力されます。

1
Falafel Phil