私はファイルの最後の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行あります。
誰かが私に問題がどこにあるか説明できますか?
問題は、シェルがコマンドを実行する前にコマンドパイプラインを設定していることです。これは「入力と出力」の問題ではなく、ファイルのコンテンツが、tailが実行される前にすでになくなっているということです。それは次のようになります:
>
_出力ファイルを書き込み用に開き、切り捨てますtail
を実行します。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)"
の出力を同じファイルにリダイレクトします。最初にファイルをクリアするファイルリダイレクトの別の解決策は、次のように sponge
パッケージからmoreutils
を使用することです。
tail -n 50 /home/pi/Documents/test | sponge /home/pi/Documents/test
これは、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
一時ファイルを削除することもできますが、そのたびにその内容が上書きされます。
少し異なるトラックでは、logrotate(8)
を使用して、ログファイルを定期的にバックアップし、名前の付いたファイルに増分してから、古いファイルを削除できます。
これは、メインシステムログファイルを管理して、ファイルが長くなりすぎるのを防ぐ方法です。
シェルリダイレクトの主な問題を確認したので、最後の50行までファイルをプルーニングする別の方法を次に示します。
file=/path/to/the/file
n=$(( $(wc -l < "$file") - 50 ))
[[ $n -gt 0 ]] && sed -i 1,${n}d "$file"
ハードワークは、-i
の "インプレース編集"機能を使用して(GNU)sedによって行われます。この機能は、一時ファイルに出力を作成することにより、内部で機能します。残りの行は、sedの操作のための数学を設定します。
wc
)の行を数え、50を減算します。それをn
に割り当てます。n
が正の場合、sedコマンドを実行して、1行目からn行目を削除します。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状況に応じてその他を変更します)。