tee -aはファイルを再作成しません

tee -aはファイルを再作成しません

Raspberry Pi 3 Debian 最新リリースで次のコマンドを実行しています。

cat /dev/ttyUSB0 | tee -a /media/pi/KINGSTON/klima.out | grep -F $ | tee -a /media/pi/KINGSTON/log

コマンドは正常に動作し、期待どおりに動作します。ただし、ファイルを (手動または CRON で) 削除するとklima.out、ファイルは再作成されません。コマンドは実行され続け、ログ ファイルには引き続き追加されますが、ファイルはklima.out戻りません (バッファリングも行われません)。境界を超えて大きくならないように、週に 1 回削除したいと思います。何か提案はありますか?

答え1

パイプラインが長時間実行されており、実行中にログ ファイルを削除しようとしているものと想定しています。

ファイルを削除しても、teeプロセスは書き込み用にファイルを開いたままにするため、ディスク領域はシステムに戻されません。ファイルを参照するすべての開いているファイル記述子が閉じられるまで、ディスク領域はシステムに戻されません。

ファイル記述子が削除前に割り当てられている限り、削除されたファイルに書き込むことはまったく問題ありません。

ファイルを再作成し、古い (現在は名前のない) ログ ファイルによって占有されていたスペースを再利用できるようにするには、パイプラインを再起動する必要があります。

パイプラインを再起動する必要がないようにするには、切り捨てるつまり、ファイルを削除せずにサイズをゼロに切り詰めます。これにより、teeファイルを再度開かなくてもファイルへの追加を続行できます。

ファイルの切り捨ては実行できるjlliagreが答えたように、またはtruncate(GNU coreutils の一部である非標準ユーティリティ)を使用します。

truncate -s 0 /media/pi/KINGSTON/klima.out

見るマニュアルtruncateそのユーティリティに関する詳細情報。

答え2

ファイル ブロックを回復したい場合は、リンクを解除するのではなく、ファイルを空にする必要があります。

このポータブルな方法は、ほとんどのシェルで動作するはずです。

: > /media/pi/KINGSTON/klima.out

ファイルのリンクを解除すると (つまりrm)、ディレクトリ エントリが削除されますが、ファイルがリーダーまたはライターによって開かれている限り、ファイルの内容 (inode) には影響しません。

答え3

システムがファイルをどのように処理しているか理解していません。

ファイル エントリを削除しますが、プログラムがハンドルを保持している限り、ファイルは存在し続けます。そのため、エントリが削除されたことは tee に通知されず、ファイルに書き込みが行われます。

ハードリンク (ln コマンドによって作成) により、一意のファイルに多数のエントリを含めることができます。

ファイルに書き込む行ごとにファイルを閉じたり開いたりする独自の tee バージョンを作成することもできますが、非常に多くのシステム コールが生成されるため、パフォーマンスが非常に低くなります。

以下は、入力を複数のファイルに分割するシェル関数です。

splitSizeInKio=100

splitInput(){
    local PS4='+splitInput+ '
    set -x
    local i=0
    local fname="$1"
    local ii

    while true
    do if [ $i -lt 10 ]
       then ii=0$i
       else ii=$i
       fi
       local outfile="$fname".$ii
       dd of="$outfile" bs=1024 count=$splitSizeInKio
       i=$((i+1))
    done
}

(サイズではなく行数を指定する場合は、「dd」の代わりに「head」を使用できます。)

bash では、次のように「プロセス置換」を使用できます。

prog1 | tee >( splitInput somefilename ) | prog2

関連情報