一時ファイルのような一時フォルダーを使用できますか
TMP=$(mktemp ... )
exec 3<>$TMP
rm $TMP
cat <&3
このシェルが終了すると自動的に破棄されるのはどれですか?
一時ファイルの場合、問題の例ではそれが作成され、ディレクトリからリンクが解除され(「消える」)、スクリプトがファイル記述子を閉じると(おそらく終了時に)、ファイルが占めるスペースがシステムによって回収可能になります。これは、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
呼び出しを実行したために正常に終了したとき。
スクリプトが終了したときに実行されるシェル関数を記述します。以下の例では、これを「クリーンアップ」と呼び、次のように終了レベルで実行されるトラップを設定します。0 1 2 3 6
trap cleanup 0 1 2 3 6
cleanup()
{
[ -d $TMP ] && rm -rf $TMP
}
詳細は this postを参照してください。
その後に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
を実行します。 command
はnot _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);
}
_
特定のシェルが必要ですか?
Zshがオプションの場合は、zshexpn(1)
をお読みください。
<(...)の代わりに=(...)を使用した場合、引数として渡されるファイルは、リストプロセスの出力を含む一時ファイルの名前になります。これは、入力ファイルで
lseek
(lseek(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")