103

bash スクリプトから一時ファイルを作成しています。処理の最後にそれらを削除していますが、スクリプトはかなり長い間実行されているため、実行中に強制終了するか、単に CTRL-C を実行すると、一時ファイルは削除されません。
これらのイベントをキャッチして、実行が終了する前にファイルをクリーンアップする方法はありますか?

また、これらの一時ファイルの名前と場所に関するベスト プラクティスはありますか?
私は現在、使用するかどうかわかりません:

TMP1=`mktemp -p /tmp`
TMP2=`mktemp -p /tmp`
...

TMP1=/tmp/`basename $0`1.$$
TMP2=/tmp/`basename $0`2.$$
...

それとも、より良い解決策がありますか?

4

8 に答える 8

133

通常、すべての一時ファイルを配置するディレクトリを作成し、その直後に、スクリプトの終了時にこのディレクトリをクリーンアップするための EXIT ハンドラを作成します。

MYTMPDIR="$(mktemp -d)"
trap 'rm -rf -- "$MYTMPDIR"' EXIT

すべての一時ファイルを の下$MYTMPDIRに置くと、ほとんどの場合、スクリプトが終了したときにすべて削除されます。ただし、SIGKILL (kill -9) でプロセスを強制終了すると、すぐにプロセスが強制終了されるため、その場合、EXIT ハンドラーは実行されません。

于 2009-03-26T18:42:28.733 に答える
109

トラップ」を設定して、終了時に実行するか、control-c でクリーンアップすることができます。

trap '{ rm -f -- "$LOCKFILE"; }' EXIT

あるいは、私のお気に入りの UNIX 主義の 1 つは、ファイルを開いて、まだ開いている間にそのファイルを削除することです。ファイルはファイルシステムに残り、読み書きできますが、プログラムが終了するとすぐにファイルは消えます。ただし、bashでそれを行う方法がわかりません。

ところで: 独自のソリューションを使用する代わりに mktemp を支持する 1 つの引数: ユーザーが、プログラムが巨大な一時ファイルを作成することを予期している場合、TMPDIR/var/tmp などのより大きな場所に設定することをお勧めします。mktemp はそれを認識しますが、手巻きのソリューション (2 番目のオプション) は認識しません。たとえば、私はよく使用TMPDIR=/var/tmp gvim -d foo barします。

于 2009-03-26T18:32:01.427 に答える
28

trapコマンドを使用して、スクリプトの終了や CTRL-C などのシグナルを処理したいと考えています。詳細については、Greg の Wikiを参照してください。

一時ファイルについては、使用basename $0することをお勧めします。また、十分な一時ファイル用のスペースを提供するテンプレートを提供することもお勧めします。

tempfile() {
    tempprefix=$(basename "$0")
    mktemp /tmp/${tempprefix}.XXXXXX
}

TMP1=$(tempfile)
TMP2=$(tempfile)

trap 'rm -f $TMP1 $TMP2' EXIT
于 2009-03-26T18:34:49.343 に答える
11

選択された答えはbashismであることに注意してください。これは、ソリューションを意味します

trap "{ rm -f $LOCKFILE }" EXIT

dashは bash でのみ機能します ( shell がまたは classicの場合は Ctrl+c をキャッチしませんsh) が、互換性が必要な場合でも、トラップするすべてのシグナルを列挙する必要があります。

また、スクリプトがシグナル「0」(別名 EXIT) のトラップを終了すると、コマンドが二重に実行されることにも注意してtrapください。

EXIT シグナルがある場合、すべてのシグナルを 1 行にスタックしない理由です。

それをよりよく理解するには、変更なしで異なるシステム間で機能する次のスクリプトを見てください。

#!/bin/sh

on_exit() {
  echo 'Cleaning up...(remove tmp files, etc)'
}

on_preExit() {
  echo
  echo 'Exiting...' # Runs just before actual exit,
                    # shell will execute EXIT(0) after finishing this function
                    # that we hook also in on_exit function
  exit 2
}


trap on_exit EXIT                           # EXIT = 0
trap on_preExit HUP INT QUIT TERM STOP PWR  # 1 2 3 15 30


sleep 3 # some actual code...

exit 

このソリューションは、最終的な終了(関数)の直前に実際のシグナルが発生したときにコードの一部を実行できるため、より多くの制御を提供し、preExit必要に応じて実際の EXIT シグナル(終了の最終段階)でいくつかのコードを実行できます。

于 2017-01-09T19:57:05.433 に答える
5

$$で予測可能なファイル名を使用する代わりの方法は、ギャップのあるセキュリティホールであり、決してそれを使用することを考えるべきではありません。シングルユーザーPC上の単純なパーソナルスクリプトであっても。それはあなたが得るべきではない非常に悪い習慣です。BugTraqは「安全でない一時ファイル」インシデントでいっぱいです。一時ファイルのセキュリティ面の詳細については、ここここ、およびここを参照してください。

私は当初、安全でないTMP1とTMP2の割り当てを引用することを考えていましたが、考え直してみると、それはおそらく良い考えではないでしょう。

于 2009-03-28T23:35:00.730 に答える
2

安全な方法で /tmp にファイルを作成する which を使用tempfileすることをお勧めします。その命名について心配する必要はありません。

tmp=$(tempfile -s "your_sufix")
trap "rm -f '$tmp'" exit
于 2011-07-21T09:35:26.690 に答える
-5

mktemp で作成された tmp ファイルをわざわざ削除する必要はありません。とにかく後で削除されます。

'$$' プレフィックスよりも多くの一意のファイルを生成するため、可能であれば mktemp を使用してください。また、一時ファイルを作成して明示的に /tmp に配置するクロスプラットフォームの方法のように見えます。

于 2009-03-26T18:33:45.900 に答える