Linuxでテキストファイルから特定の行を表示するにはどうすればよいですか?


85

誰もが便利なLinux cmdラインユーティリティheadとを知っていると思いますtailheadファイルの最初のX行を印刷できますtailが、同じことを行いますが、ファイルの最後を印刷します。ファイルの中央を印刷するための良いコマンドは何ですか?次のようなものmiddle --start 10000000 --count 20(10'000'000番目から10'000'010番目までの行を印刷)。

大きなファイルを効率的に処理できるものを探しています。試しましたがtail -n 10000000 | head 10、恐ろしく遅いです。


回答:


111
sed -n '10000000,10000020p' filename

次のようにして速度を上げることができます。

sed -n '10000000,10000020p; 10000021q' filename

これらのコマンドでは、このオプション-nによりsed「パターンスペースの自動印刷が抑制されます」。pコマンド「プリント[s]は、現在のパターンスペース」とq「すぐにそれ以上の入力を処理せずに[S] sedスクリプトを終了...」コマンド引用符からあるsed manページ

ところで、あなたのコマンド

tail -n 10000000 filename | head 10

ファイルの最後から1000万行目から開始しますが、「中間」コマンドは最初から1000万行目から始まるように見えます。

head -n 10000010 filename | tail 10

問題は、可変長の行を持つソートされていないファイルの場合、すべてのプロセスが改行をカウントするファイルを通過する必要があることです。それをショートカットする方法はありません。

ただし、ファイルが並べ替えられている場合(タイムスタンプ付きのログファイルなど)、または固定長の行がある場合は、バイト位置に基づいてファイルをシークできます。ログファイルの例では、ここでの Pythonスクリプト*のように、ある範囲の時間でバイナリ検索を実行できます。固定レコード長ファイルの場合、それは本当に簡単です。linelength * linecountファイルに文字を探すだけです。

*私はそのスクリプトにさらに別の更新を投稿する意味を持ち続けています。たぶん、私はこれらの日のうちの1つに近づきます。


以下は、sedチャールズのmiddle関数のバージョンですmiddle() { local s=$1 c=$2; shift 2; sed -n "$s,$(($s + $c -1))p; $(($s + $c))q" "$@"; }。複数のファイル引数、スペースを含むファイル名などを処理します。複数のファイルは、sed通常の場合と同じ方法で連結されているかのように一緒に処理されます(したがって、中間1000 100最初の行の行数が1100行未満の場合、2番目の行の行)。
デニスウィリアムソン

以前のコメントの関数は、ファイル名パラメーターで呼び出すことができます:middle startline count filenameまたは複数のファイル名:middle startline count file1 file2 file3またはリダイレクトで:middle startline count < filenameまたはパイプで:some_command | 中間のスタートラインカウント `またはcat file* | middle startline count
デニスウィリアムソン

sedコマンドの `は 'であってはなりませんか?バックティックでは動作しませんが、一重引用符では正常に動作します。
イアンハンター

@beanland:はい、それはタイプミスです。私はそれを修正しました。ありがとう。
デニスウィリアムソン

1
@kev:答えに説明を追加しました。
デニスウィリアムソン

28

私は次の使用法を見つけました sed

sed -n '10000000,+20p'  filename

それが誰かに役立つことを願っています!


Dennisによって提案された最後の行の引数に代わるものがあることを知っておくと良いでしょう。2番目のsed -n引数として行カウントを使用すると、非常に読みやすくなります。
user3123159

使用例:extract_lines(){sed -n "$1,+$2p" <file>}stdoutに書き込みます。
user3123159

4

ここに投稿するのは初めてです!とにかく、これは簡単です。file.txtというファイルから8872行目を取得するとします。方法は次のとおりです。

cat -n file.txt | grep '^ * 8872'

問題は、この後20行を見つけることです。これを実現するには

cat -n file.txt | grep -A 20 '^ * 8872'

前後の行については、grepマニュアルの-Bおよび-Cフラグを参照してください。


これは技術的には正しいものであり、適度なサイズのファイルでそれを行う興味深い方法ですが、ポスターが要求しているサイズのファイルを操作する際のその有効性に興味があります。
ジェニーD

複数行:cat -n file.txt | grep "^ \ s \ +(10 \ | 20 \ | 30)\ s \ +"
ジェフリーナイト

cat -n file.txt | grep '^ *1'右側に1があるすべての行を生成します。この手法で行1を出力する方法は?私は-n 1 ....に向かうことができることを知っていますが、grepの使い方は?
ショーン87

1

デニスのセッドの答えは、進むべき道です。しかし、bashの下で頭と尻尾だけを使用します。

middle(){head -n $ [$ 1 + $ 2] | tail -n $ 2; }

これは最初の$ 1 + $ 2行を2回スキャンするため、デニスの答えよりもはるかに悪いです。しかし、あなたはそれを使用するためにそれらのすべてのsed文字を覚える必要はありません。


$[...]少なくともBashでは、使用は非推奨です。また、ファイルパラメータがありません。
デニスウィリアムソン

@Dennis:欠落しているパラメーターはありません:のように、これをstdinで使用することになっていますmiddle 10 10 < /var/log/auth.log
チャールズスチュワート

1

特定の行範囲を取得するには、次のコマンドを使用します

awk 'NR < 1220974{next}1;NR==1513793{exit}' debug.log | tee -a test.log

ここで、debug.logは行のないファイルで、1220974行番号から1513793までの行をファイルtest.logに出力するために使用します。行の範囲をキャプチャするのに役立つことを願っています。


serverfault.com/a/641252/140016と同じ答え。ダウン投票。
鹿ハンター

同じ答えではありません。これは、ファイル全体をスキャンし続けるのではなく、最後の行を印刷した後に実際に中断するため、大きなファイルの場合は高速になります。
恐怖症

0

ルビーワンライナーバージョン。

ruby -pe 'next unless $. > 10000000 && $. < 10000020' < filename.txt

誰かに役立つことがあります。DennisとDoxが提供する 'sed'を使用したソリューションは、高速に見える場合でも非常に優れています。




0

numebrs行がわかっている場合、ファイルから1行目、3行目、および5行目を取得したい場合は、/ etc / passwdと言います。

perl -e 'while(<>){if(++$l~~[1,3,5]){print}}' < /etc/passwd

弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.