web-dev-qa-db-ja.com

ログファイルの最後の50行を保持する方法

私はファイルの最後の50行を保持しようとしていますが、毎分温度を保存しています。私はこのコマンドを使用しました:

tail -n 50 /home/pi/Documents/test > /home/pi/Documents/test

しかし、結果は空のテストファイルです。私は、テストファイルの最後の50行をリストし、テストファイルに挿入すると思った。このコマンドを使用すると:

tail -n 50 /home/pi/Documents/test > /home/pi/Documents/test2

正常に動作しています。 test2ファイルには50行あります。

誰かが私に問題がどこにあるか説明できますか?

22
dorinand

問題は、シェルがコマンドを実行する前にコマンドパイプラインを設定していることです。これは「入力と出力」の問題ではなく、ファイルのコンテンツが、tailが実行される前にすでになくなっているということです。それは次のようになります:

  1. シェルは_>_出力ファイルを書き込み用に開き、切り捨てます
  2. シェルは、その出力にファイル記述子1(標準出力用)を使用するように設定します。
  3. シェルはtailを実行します。
  4. tailは実行され、_/home/pi/Documents/test_を開いて何も見つかりません

さまざまな解決策がありますが、重要なのは、問題、実際に何が問題になっているのか、および理由を理解することです。

これはあなたが探しているものを生み出します、

_echo "$(tail -n 50 /home/pi/Documents/test)" > /home/pi/Documents/test
_

説明:

  • $()は、_tail -n 50 /home/pi/Documents/test_を実行するコマンド置換と呼ばれます
  • 引用符は、出力の改行を保持します。
  • _> /home/pi/Documents/test_は、echo "$(tail -n 50 /home/pi/Documents/test)"の出力を同じファイルにリダイレクトします。
31
Rahul

最初にファイルをクリアするファイルリダイレクトの別の解決策は、次のように sponge パッケージからmoreutilsを使用することです。

tail -n 50 /home/pi/Documents/test | sponge /home/pi/Documents/test
8
iobender

これは、bashが最初に>を使用してリダイレクトを処理し、ファイルの内容を削除するためです。次に、コマンドを実行します。 >>を使用すると、最後の50行が現在ファイルにあるものの最後に追加されます。この場合、同じ50行が2回繰り返されます。

コマンドは、別のファイルにリダイレクトするときに期待どおりに機能します。次に、ファイルの最後の50行を同じ名前のファイルに書き込む方法を1つ示します。

tail -50 /home/pi/Documents/test > /home/pi/Documents/test2 && mv /home/pi/Documents/test2 /home/pi/Documents/test

これにより、最初の最後の50行が一時ファイルに書き込まれ、mvを使用して移動されて元のファイルが置き換えられます。

コメントに記載されているように、ファイルがまだ開いている場合、これは機能しません。ファイルを移動すると、新しいiノードも作成され、所有権と権限が変更される場合があります。一時ファイルを使用してこれを行うより良い方法は次のとおりです。

tail -50 /home/pi/Documents/test > /home/pi/Documents/test2 ; cat /home/pi/Documents/test2 > /home/pi/Documents/test

一時ファイルを削除することもできますが、そのたびにその内容が上書きされます。

6
clk

少し異なるトラックでは、logrotate(8)を使用して、ログファイルを定期的にバックアップし、名前の付いたファイルに増分してから、古いファイルを削除できます。

これは、メインシステムログファイルを管理して、ファイルが長くなりすぎるのを防ぐ方法です。

4
CSM

シェルリダイレクトの主な問題を確認したので、最後の50行までファイルをプルーニングする別の方法を次に示します。

file=/path/to/the/file
n=$(( $(wc -l < "$file") - 50 ))
[[ $n -gt 0 ]] && sed -i 1,${n}d "$file"

ハードワークは、-iの "インプレース編集"機能を使用して(GNU)sedによって行われます。この機能は、一時ファイルに出力を作成することにより、内部で機能します。残りの行は、sedの操作のための数学を設定します。

  1. ファイル(wc)の行を数え、50を減算します。それをnに割り当てます。
  2. nが正の場合、sedコマンドを実行して、1行目からn行目を削除します。
4
Jeff Schaller
printf '%s\n' '1,$-50d'   w | ed -s /home/pi/Documents/tes

printfは、コマンド(1行に1つ)をedにパイプするために使用されます。 edコマンドは次のとおりです。

  • 1,$-50d-最後の50行を除くすべてを削除します
  • w-変更されたファイルをディスクに書き戻します

リダイレクトは含まれないため、シェルは出力ファイルが読み取られる前に出力ファイルを上書きできません。

また、ほとんどの形式の「インプレース」編集(通常、一時ファイルを作成してから元のファイル名を変更して「インプレース」編集をシミュレートするだけ)とは異なり、edは実際に元のファイルを編集します。同じiノードを保持します(および所有者、グループ、および権限-tempfile + mvは常に iノードを変更し、may状況に応じてその他を変更します)。

4
cas