web-dev-qa-db-ja.com

プロセス終了後に自動的に破棄される一時フォルダー

一時ファイルのような一時フォルダーを使用できますか

TMP=$(mktemp ... )
exec 3<>$TMP
rm $TMP

cat <&3

このシェルが終了すると自動的に破棄されるのはどれですか?

10
Bob Johnson

一時ファイルの場合、問題の例ではそれが作成され、ディレクトリからリンクが解除され(「消える」)、スクリプトがファイル記述子を閉じると(おそらく終了時に)、ファイルが占めるスペースがシステムによって回収可能になります。これは、Cなどの言語で一時ファイルを処理する一般的な方法です。

私の知る限り、同じ方法でディレクトリを開くことはできません。少なくとも、ディレクトリを使用できるようにする方法はありません。

スクリプトの終了時に一時ファイルとディレクトリを削除する一般的な方法は、クリーンアップEXITトラップをインストールすることです。以下のコード例では、ファイル記述子を完全に操作する必要がありません。

tmpdir=$(mktemp -d)
tmpfile=$(mktemp)

trap 'rm -f "$tmpfile"; rm -rf "$tmpdir"' EXIT

# The rest of the script goes here.

または、クリーンアップ関数を呼び出すこともできます。

cleanup () {
    rm -f "$tmpfile"
    rm -rf "$tmpdir"
}

tmpdir=$(mktemp -d)
tmpfile=$(mktemp)

trap cleanup EXIT

# The rest of the script goes here.

EXITトラップは、KILLシグナル(トラップできない)を受信して​​も実行されません。つまり、その場合、クリーンアップは実行されません。ただし、INTまたはTERM信号が原因で終了するときに実行されます(bashまたはkshで実行している場合、他のシェルではこれらを追加することができますEXITの後のシグナル(trapコマンドライン)、またはスクリプトの最後に到達したか、exit呼び出しを実行したために正常に終了したとき。

12
Kusalananda

スクリプトが終了したときに実行されるシェル関数を記述します。以下の例では、これを「クリーンアップ」と呼び、次のように終了レベルで実行されるトラップを設定します。0 1 2 3 6

trap cleanup 0 1 2 3 6

cleanup()
{
  [ -d $TMP ] && rm -rf $TMP
}

詳細は this postを参照してください。

6
Dirk Krijgsman

その後にchdirしてから削除することができます。ただし、後でその内部のパスを使用しない場合に限ります。

_#! /bin/sh
dir=`mktemp -d`
cd "$dir"
exec 4>file 3<file
rm -fr "$dir"

echo yes >&4    # OK
cat <&3         # OK

cat file        # FAIL
echo yes > file # FAIL
_

私はチェックしていませんが、Cでopenat(2)をファイルシステムに存在しないディレクトリで使用する場合、おそらく同じ問題です。

RootでLinuxを使用している場合は、別の名前空間で遊ぶことができ、その中で_mount -t tmpfs tmpfs /dir_を使用できます。

スクリプトが(たとえば、SIGKILLで)不潔な出口に強制された場合、標準的な回答(EXITにトラップを設定)は機能しません。機密データが滞る可能性があります。

更新:

名前空間アプローチを実装する小さなユーティリティを次に示します。でコンパイルする必要があります

_cc -Wall -Os -s chtmp.c -o chtmp
_

そして、(ルートとして)_CAP_SYS_ADMIN_ファイル機能が与えられます

_setcap CAP_SYS_ADMIN+ep chtmp
_

(通常の)ユーザーとして実行した場合

_./chtmp command args ...
_

ファイルシステムの名前空間の共有を解除し、tmpfsファイルシステムを_/proc/sysvipc_にマウントし、chdirを実行して、指定された引数でcommandを実行します。 commandnot _CAP_SYS_ADMIN_機能を継承します。

そのファイルシステムは、commandから開始されていない別のプロセスからアクセスできなくなり、commandとその子プロセスがどのように終了しても、(その中に作成されたすべてのファイルとともに)魔法のように消えます。発生します。これはマウントネームスペースの共有を解除するだけであることに注意してください。commandと同じユーザーが実行する他のプロセスとの間にハードバリアはありません。 ptrace(2)、_/proc/PID/cwd_を介して、またはその他の方法で、名前空間内に忍び込むことができます。

「役に立たない」_/proc/sysvipc_のハイジャックはもちろんばかげていますが、代わりに空のディレクトリで_/tmp_をスパムして、削除する必要があるか、この小さなプログラムをフォークで複雑にし、待ちます。あるいは、dirをたとえばに変更できます。 _/mnt/chtmp_そして、インストール時にrootによって作成されます。ユーザー設定可能にしたり、ユーザーが所有するパスに設定したりしないでください。シンボリックリンクトラップや、時間を費やす価値のない他の毛深いものにさらされる可能性があります。

chtmp.c

_#define _GNU_SOURCE
#include <err.h>
#include <sched.h>
#include <stdio.h>
#include <unistd.h>
#include <sys/mount.h>
int main(int argc, char **argv){
        char *dir = "/proc/sysvipc";    /* LOL */
        if(argc < 2 || !argv[1]) errx(1, "usage: %s prog args ...", *argv);
        argv++;
        if(unshare(CLONE_NEWNS)) err(1, "unshare(CLONE_NEWNS)");
        /* "modern" systemd remounts all mount points MS_SHARED
           see the NOTES in mount_namespaces(7); YUCK */
        if(mount("none", "/", 0, MS_REC|MS_PRIVATE, 0))
                err(1, "mount(/, MS_REC|MS_PRIVATE)");
        if(mount("tmpfs", dir, "tmpfs", 0, 0)) err(1, "mount(tmpfs, %s)", dir);
        if(chdir(dir)) err(1, "chdir %s", dir);
        execvp(*argv, argv);
        err(1, "execvp %s", *argv);
}
_
6
qubert

特定のシェルが必要ですか?

Zshがオプションの場合は、zshexpn(1)をお読みください。

<(...)の代わりに=(...)を使用した場合、引数として渡されるファイルは、リストプロセスの出力を含む一時ファイルの名前になります。これは、入力ファイルでlseeklseek(2)を参照)を期待するプログラムの<フォームの代わりに使用できます。

[...]

代替を含むコマンドの最後に&!または&|が表示される場合など、一時ファイルを必要とする置換を伴うジョブがシェルによって否認されると、別の問題が発生します。その場合、シェルにはジョブのメモリがなくなるため、一時ファイルはクリーンアップされません。回避策は、たとえば、サブシェルを使用することです

(mycmd =(myoutput)) &!

forkされたサブシェルはコマンドが終了するのを待ち、一時ファイルを削除します。

プロセスの置換が適切な時間持続することを保証する一般的な回避策は、匿名のシェル関数(関数スコープですぐに実行されるシェルコード)にパラメーターとして渡すことです。たとえば、次のコード:

() {
   print File $1:
   cat $1
} =(print This be the verse)

次のようなものを出力します

File /tmp/zsh6nU0kS:
This be the verse

たとえば、これをライフル(レンジャーファイルマネージャーの一部)で使用してファイルを復号化し、一時ファイルでライフルを実行します。一時ファイルは、サブプロシージャが終了すると削除されます。 ($TERMCMDを設定することを忘れないでください)

# ~/.config/ranger/rifle.conf
...
!ext exe, mime octet-stream$, has gpg, flag t = () { rifle -f F "$1" } =(gpg -dq "$1")
0
Bart