ファイルの真ん中に特定の行を表示するクイックUNIXコマンド?


206

サーバーの問題をデバッグしようとすると、私の唯一のログファイルは20 GBのログファイルです(タイムスタンプもありません。なぜ人々はSystem.out.println()ログとして使用するのですか?運用中ですか?)

grepを使用して、調べたいファイルの領域、347340107行を見つけました。

のようなことをする以外に

head -<$LINENUM + 10> filename | tail -20 

... headログファイルの最初の3億4700万行を読み取る必要がある場合、行347340100-347340200(たとえば)をコンソールにダンプする迅速で簡単なコマンドはありますか?

update grepがマッチの前後のコンテキストを出力できることを完全に忘れていました...これはうまくいきます。ありがとう!


私はgrepがファイル全体を検索する必要があると想像しますが、これを行うにはCPUの負荷が少ない方法が必要です。
ojblass 2009

回答:


69

GNU-grepを使えば、あなたはただ言うことができます

grep --context = 10 ...

7
または、より具体的には10行前:grep -B 10 ...または10行後:grep -A 10 ...
Boy Baukema '21

17
このコマンドは機能せず、sed -n '<start>、<end> p'の下では機能しています
Basav

5
これは、一致が最上位にある場合でもファイル全体を処理するため、実際には必要なものではありません。この時点で、ヘッド/テールまたはテール/ヘッドのコンボはより効果的です。
Sklivvz

3
これは、質問されたとおりに特定のを出力する方法を提供しないため、質問された質問をまったく満たしていません。
Chris Rasys 2016年

1
これは実際に尋ねられたものではありません。@matt b、この答えを受け入れないのはなぜですか?
user1271772

390

行番号はわかっているが他に何もない場合(grepは不可能)、他の2つの解決策を見つけました。

20行目から40行目が必要だとすると、

sed -n '20,40p;41q' file_name

または

awk 'FNR>=20 && FNR<=40' file_name

6
+1:印刷後に終了することもできます。ファイルが非常に大きい場合、パフォーマンスが向上する場合があります。
ジェイパルシン2014

awk 'NR> = 20 && NR <= 40' file_name
Sudipta Basak

2
sed -n '20、40p; 41q 'file_nameで終了します。
Snigdha Batra 2015

1
具体的には、これらは開始行番号と終了行番号です。あなたは大きなファイルである場合、それは「12345678,12345699p」になります
コードAbominator

1
@CodeAbominatorのコメントに加えて、行で終了する41qようにsedに指示します。41
Brice

116
# print line number 52
sed -n '52p' # method 1
sed '52!d' # method 2
sed '52q;d' # method 3,  efficient on large files 

大きなファイルで効率的な方法3

特定の行を表示する最速の方法


方法3を1行ではなく範囲を使用するように調整する方法を理解しようとしていますが、sed-fooがタスクに対応していないと思います。
Xiong Chiamiov 2013

9
@XiongChiamiov 1-500を印刷するためのsed -n '1,500p; 501q'はどうですか?
2014

3
最初の2行は/方法は、あまり効率的である理由は、それらはライン52を印刷した後、#3が停止する一方、最後まで、ライン52の後にすべての行を処理し続けることである
flow2k

1
この答えは、すべての議論が何をするかを説明することから利益を得るでしょう。
Bram Vanroy

25

いいえ、ファイルは行でアドレス指定できません。

nの開始を見つける一定時間の方法はありませんテキストファイル。ファイルをストリーミングして改行を数える必要があります。

あなたが仕事をしなければならない最も単純な/最速のツールを使用してください。後者の方がはるかに複雑であるため、私にとって、を使用headすることは、よりもはるかに意味がgrepあります。「grep遅い」と言っているわけではありませんが、実際にはそうではありませんが、headこのケースよりも高速であるとは驚きます。head基本的に、それはのバグでしょう。


2
行がバイト単位の固定幅でない限り、ファイルの先頭から改行文字をカウントせずにファイルポインターを移動する場所がわかりません。
Joseph Lust 2013年

これは質問に対する答えを提供しません。批評したり、著者に説明を要求するには、投稿の下にコメントを残してください。
exhuma

@exhumaそうですね。書き直しました。私は7年前に私はミイラになりました。:)
アンワインド

20

何について:

tail -n +347340107 filename | head -n 100

テストはしませんでしたが、うまくいくと思います。


いいえ、バージョンとOSによって異なりますが、通常、末尾の最後のキロバイトは256に制限されています。
AnttiRytsölä2015年

💪yessire Miller
dctremblay

13

私はただ入るのが好きless

  • 入力50%してファイルの途中に移動し、
  • 43210G 行43210に行く
  • :43210 同じことをする

そしてそのようなもの。

さらに良いvことに、その場所で(もちろん、vimで!)編集を開始します。これでvim、同じキーバインディングがあることに注意してください!


12

私は最初にファイルをこのようないくつかの小さなものに分割します

$ split --lines=50000 /path/to/large/file /path/to/output/file/prefix

そして、結果のファイルに対してgrepを実行します。


同意して、そのログアップを解除し、それを適切に行うためのcronジョブを作成します。logrotateなどを使用して、巨大になりすぎないようにします。
タンジ08年

9

exコマンド、標準のUnixエディター(Vimの一部)を使用できます。例:

  • 1行を表示します(例:2行目):

    ex +2p -scq file.txt

    対応するsed構文: sed -n '2p' file.txt

  • 行の範囲(例:2〜5行):

    ex +2,5p -scq file.txt

    sed構文: sed -n '2,5p' file.txt

  • 指定された行から最後まで(たとえば、5番目からファイルの最後まで):

    ex +5,p -scq file.txt

    sed構文: sed -n '2,$p' file.txt

  • 複数のライン範囲(例:2-4および6-8ライン):

    ex +2,4p +6,8p -scq file.txt

    sed構文: sed -n '2,4p;6,8p' file.txt

上記のコマンドは、次のテストファイルでテストできます。

seq 1 20 > file.txt

説明:

  • + または -cコマンドが続く-ファイルが読み取られた後に(vi / vim)コマンドを実行します、
  • -s -サイレントモード、現在の端末をデフォルト出力としても使用し、
  • q-cエディターを終了するコマンドが続き!ます(強制終了を実行するために追加するなど-scq!)。


6

取得する ack

Ubuntu / Debianのインストール:

$ sudo apt-get install ack-grep

次に実行します:

$ ack --lines=$START-$END filename

例:

$ ack --lines=10-20 filename

から$ man ack

--lines=NUM
    Only print line NUM of each file. Multiple lines can be given with multiple --lines options or as a comma separated list (--lines=3,5,7). --lines=4-7 also works. 
    The lines are always output in ascending order, no matter the order given on the command line.

1
これは、私にとって、ここでのすべての答えの中で最も直感的な構文を持つコマンドのように見えます。
nzn

2019年1月10日のバージョン2.999_06から、--linesパラメーターは削除されました。
1

4

sedは、行を数えるためにもデータを読み取る必要があります。ショートカットが可能になる唯一の方法は、操作するファイルにコンテキスト/順序があることです。たとえば、固定幅の時刻/日付などが前に付いているログ行がある場合、look unixユーティリティを使用して、特定の日付/時刻のファイルをバイナリ検索できます。


4

使用する

x=`cat -n <file> | grep <match> | awk '{print $1}'`

ここで、一致が発生した行番号を取得します。

これで、次のコマンドを使用して100行を印刷できます

awk -v var="$x" 'NR>=var && NR<=var+100{print}' <file>

または、「sed」も使用できます

sed -n "${x},${x+100}p" <file>

複数の一致がある場合は、「awk 'NR == 1 {print $ 1}」を最初の一致などに使用します
Ramana Reddy

2

ではsed -e '1,N d; M q'、あなたが行を印刷するよM.これを通じてN + 1は、おそらく少し良く、その後でgrep -C、それはパターンにラインを一致させようとしませんよう。


-eここではオプションです。
flow2k

2

Sklivvzの答えに基づいて、.bash_aliasesファイルに挿入できる便利な関数を次に示します。ファイルの先頭から印刷する場合、巨大なファイルで効率的です。

function middle()
{
    startidx=$1
    len=$2
    endidx=$(($startidx+$len))
    filename=$3

    awk "FNR>=${startidx} && FNR<=${endidx} { print NR\" \"\$0 }; FNR>${endidx} { print \"END HERE\"; exit }" $filename
}

1

<textfile>そのによってaから行を表示するには<line#>、次のようにします。

perl -wne 'print if $. == <line#>' <textfile>

正規表現で行の範囲を表示するためのより強力な方法が必要な場合-なぜgrepがこれを行うのに悪い考えであるかは言いませんが、これはかなり明白なはずです-この単純な式は、 〜20GBのテキストファイルを処理するときに必要なシングルパス:

perl -wne 'print if m/<regex1>/ .. m/<regex2>/' <filename>

(ヒント:正規表現が含ま/れている場合は、m!<regex>!代わりに次のようなものを使用してください)

これは<filename>、に一致<regex1>する行まで(およびそれを含む)一致する行から印刷し<regex2>ます。

いくつかの微調整でそれをさらに強力にする方法をウィザードが理解する必要はありません。

最後に:perlは成熟した言語であるため、速度とパフォーマンスを優先するために多くの隠れた拡張機能があります。これを念頭に置くと、元々は大きなログファイル、テキスト、データベースなどを処理するために開発されたため、このような操作には当然の選択です。


実際には、私にはそのようには見えません。なぜなら、1つのperlコマンドを実行するとき、言うよりも2つ以上のプログラムを実行する場合(ページのさらに下)を実行するからです。同じように複雑な(またはそれ以上の)ページの下に水から吹き飛ばされなかったため、読む必要があるという説明... sheesh
osirisgothra

ユーザーが一連の行を要求したことに注意してください-あなたの例は簡単に適応させることができます。
Sklivvz


0

perlで簡単!ファイルから1、3、5行目を取得したい場合は、/ etc / passwdと言います。

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

1
あなたはawkでそれは簡単だと言いますが、代わりにperlでそれをしましたか?
囚人2017年

0

出力に行番号を追加するよう提案された(Ramana Reddyによる)他の1つの回答だけに驚いています。以下は、必要な行番号を検索し、出力に色を付けます。

file=FILE
lineno=LINENO
wb="107"; bf="30;1"; rb="101"; yb="103"
cat -n ${file} | { GREP_COLORS="se=${wb};${bf}:cx=${wb};${bf}:ms=${rb};${bf}:sl=${yb};${bf}" grep --color -C 10 "^[[:space:]]\\+${lineno}[[:space:]]"; }

コード付きの回答は、削除のフラグが付けられる傾向があります。これが問題をどのように解決するかについてのコメントを追加していただけますか?
グラハム
弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.