
と を試してみましたがgrep
、sed
どうもうまくいきませんでした。
約 8 GB のログ ファイルがあります。15 分間の疑わしいアクティビティを分析する必要があります。確認する必要があるログ ファイルの部分を特定し、それらの行を抽出して別のファイルに保存しようとしています。通常の CentOS マシンでこれを行うにはどうすればよいでしょうか?
sed
最後に試したのはこれですが、うまくいきませんでした。この種のコマンドに関しては困惑しています。
sed -n '2762818,2853648w /var/log/output.txt' /var/log/logfile
答え1
sed -n '2762818,2853648p' /var/log/logfile > /var/log/output.txt
p
印刷用です
答え2
おそらく、他の人が言及しているように、これを行う最良の方法はシェル リダイレクトを使用することです。sed
ただし、これは個人的には気に入っていますが、ファイルから一定数の行のみを取得するように設計されている will よりも効率的には機能しない可能性がありますhead
。
head -n[num] | tail -n[num]
このサイトには、大きなファイルの場合は常にパフォーマンスが優れていることを実証する他の回答がありますがsed
、おそらくそれよりもさらに高速なのはパイプを完全に回避することです。
次のようなファイルを作成しました:
echo | dd cbs=5000000 conv=block | tr \ \\n >/tmp/5mil_lines
そして私はそれを実行しました:
{ head -n "$((ignore=2762817))" >&2
head -n "$((2853648-ignore))"
} </tmp/5mil_lines 2>/dev/null |
sed -n '1p;$p'
私は、sed
皆さんに見せるために、最初と最後の行だけを取得するために、そこに all を使用しました...
2762818
2853648
これが機能するのは、コマンドをグループ化して{ ... ; }
、グループの入力をリダイレクトすると、... ; } <input
それらすべてが同じ入力を共有するためです。ほとんどのコマンドは、読み取り中に infile 全体を使い果たすため、通常{ cmd1 ; cmd2; } <infile
はcmd1
infile の先頭から末尾まで読み取り、cmd2
何も残りません。
head
ただし、常に、指示された範囲内で入力ファイル内をシークするため、...
{ head -n [num] >/dev/null
head -n [num]
} <infile
...最初のものは までシークし[num]
て出力をダンプし/dev/null
、2 番目のものは最初のものが終了したところから読み取りを開始します。
できるよ...
{ head -n "$((ignore=2762817))" >/dev/null
head -n "$((2853648-ignore))" >/path/to/outfile
} <infile
この構造は、他の種類の複合コマンドでも機能します。例:
set "$((n=2762817))" "$((2853648-n))"
for n do head "-n$n" >&"$#"; shift
done <5mil_lines 2>/dev/null |
sed -n '1p;$p'
...印刷されます...
2762818
2853648
しかし、次のようにも機能する可能性があります:
d=$((( n=$(wc -l </tmp/5mil_lines))/43 )) &&
until [ "$(((n-=d)>=(!(s=143-n/d))))" -eq 0 ] &&
head "-n$d" >>"/tmp/${s#1}.split"
do head "-n$d" > "/tmp/${s#1}.split" || ! break
done </tmp/5mil_lines
上記のシェルは最初に$n
および$d
変数を次のように設定します...
$n
wc
私のテストファイルで報告された行数/tmp/5mil_lines
$d
- 43は
$n/43
任意に選択された除数です。
- 43は
次に、だけ減分した値until
をより小さい値まで$n
ループします。その際、 に分割カウントを保存し、ループ内でその値を使用して、という名前の出力ファイルを増分します。その結果、反復ごとに、入力ファイル内の ewline で区切られた同数のフィールドが新しい出力ファイルに読み込まれます。ループ中に 43 回均等に分割されます。入力ファイルを 2 回以上読み取ることなくこれを管理します。最初は が行数をカウントするときに行われ、残りの操作では、毎回出力ファイルに書き込むのと同じ数の行のみが読み取られます。$d
$d
$s
>
/tmp/[num].split
\n
wc
実行後、結果を確認したところ...
tail -n1 /tmp/*split | grep .
出力:
==> /tmp/01.split <==
116279
==> /tmp/02.split <==
232558
==> /tmp/03.split <==
348837
==> /tmp/04.split <==
465116
==> /tmp/05.split <==
581395
==> /tmp/06.split <==
697674
==> /tmp/07.split <==
813953
==> /tmp/08.split <==
930232
==> /tmp/09.split <==
1046511
==> /tmp/10.split <==
1162790
==> /tmp/11.split <==
1279069
==> /tmp/12.split <==
1395348
==> /tmp/13.split <==
1511627
==> /tmp/14.split <==
1627906
==> /tmp/15.split <==
1744185
==> /tmp/16.split <==
1860464
==> /tmp/17.split <==
1976743
==> /tmp/18.split <==
2093022
==> /tmp/19.split <==
2209301
==> /tmp/20.split <==
2325580
==> /tmp/21.split <==
2441859
==> /tmp/22.split <==
2558138
==> /tmp/23.split <==
2674417
==> /tmp/24.split <==
2790696
==> /tmp/25.split <==
2906975
==> /tmp/26.split <==
3023254
==> /tmp/27.split <==
3139533
==> /tmp/28.split <==
3255812
==> /tmp/29.split <==
3372091
==> /tmp/30.split <==
3488370
==> /tmp/31.split <==
3604649
==> /tmp/32.split <==
3720928
==> /tmp/33.split <==
3837207
==> /tmp/34.split <==
3953486
==> /tmp/35.split <==
4069765
==> /tmp/36.split <==
4186044
==> /tmp/37.split <==
4302323
==> /tmp/38.split <==
4418602
==> /tmp/39.split <==
4534881
==> /tmp/40.split <==
4651160
==> /tmp/41.split <==
4767439
==> /tmp/42.split <==
4883718
==> /tmp/43.split <==
5000000
答え3
head
おそらく、tail
以下のコマンドの組み合わせの助けを借りてこれを実現できるでしょう。
head -n{to_line_number} logfile | tail -n+{from_line_number} > newfile
from_line_number
およびto_line_number
を必要な行番号に置き換えます。
テスト
cat logfile
This is first line.
second
Third
fourth
fifth
sixth
seventh
eighth
ninth
tenth
##I use the command as below. I extract from 4th line to 10th line.
head -n10 logfile | tail -n+4 > newfile
fourth
fifth
sixth
seventh
eighth
ninth
tenth