
一時ファイルなどの一時フォルダを使用できますか?
TMP=$(mktemp ... )
exec 3<>$TMP
rm $TMP
cat <&3
シェルが終了した後に自動的に破壊されるのは何ですか?
答え1
一時ファイルの場合、質問の例では一時ファイルを作成し、ディレクトリのリンクを解除し(「消える」設定)、スクリプトがファイル記述子を閉じると(おそらく終了時に)、システムはファイルが占有しているスペースを回復します。これは、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
答え2
後でそのパスを使用しない場合は、そのパスに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)を使用すると、同じ問題が発生する可能性が高くなります。
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ファイルシステムをここにマウントし、chdirを指定して与えられた引数で実行します/proc/sysvipc
。 〜するcommand
command
いいえ継承されたCAP_SYS_ADMIN
能力。
ファイルシステムは起動されていない他のプロセスからアクセスできず、何が起こってもサブプロセスがcommand
終了すると魔法のように消えます(そこに作成されたすべてのファイルと共に)。command
これは、マウントネームスペースのみを共有解除することに注意してください。command
同じユーザーが実行している他のプロセス間で、まだ異なる方法でその名前空間にこっそり入ることができptrace(2)
ます/proc/PID/cwd
。
「役に立たない」ハイジャックは/proc/sysvipc
もちろん愚かですが、代わりに/tmp
削除する必要がある空のディレクトリにスパムを送信したり、ブランチやスタンバイを介してこの小さなプログラムを非常に複雑にすることです。または、dir
次のように変更できます。/mnt/chtmp
そして、インストール時にルートとして生成します。ユーザーが構成できるようにしないでください。ユーザーが所有するパスに設定しないでください。これを行うと、シンボリックリンクトラップや時間を費やす価値のないその他の問題が発生する可能性があります。
chmp.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);
}
答え3
スクリプトが完了したら、実行するシェル関数を作成します。次の例では、「クリーン」と呼び、終了レベルで実行するようにトラップを設定します。例:0 1 2 3 6
trap cleanup 0 1 2 3 6
cleanup()
{
[ -d $TMP ] && rm -rf $TMP
}
バラよりこれ詳しくは投稿してください。
答え4
特定のエンクロージャが必要ですか?
zshがオプションの場合は、以下をお読みくださいzshexpn(1)
。
<(...)の代わりに=(...)を使用すると、引数として渡されたファイルはリストプロセスの出力を含む一時ファイルの名前になります。これは、入力ファイルが必要な
lseek
(参照)プログラムの<形式の代わりに使用できます。lseek(2)
[...]
&!
代替を含むコマンドを含めるか、コマンドの&|
最後に一時ファイルを必要とする代替操作を含む操作をシェルが拒否するたびに、別の問題が発生します。この場合、シェルはもはやジョブのメモリを所有しないため、一時ファイルは消去されません。解決策はサブシェルを使用することです。例えば、(mycmd =(myoutput)) &!
分岐したサブシェルは、コマンドが完了するのを待ってから一時ファイルを削除するためです。
プロセスの置き換えが適切な時間継続されるようにする一般的な回避策は、それを匿名シェル関数(関数の範囲内ですぐに実行されるシェルコードスニペット)に引数として渡すことです。たとえば、次のコードは次のようになります。
() { print File $1: cat $1 } =(print This be the verse)
出力は次のようになります。
File /tmp/zsh6nU0kS: This be the verse
たとえば、ライフル(Rangerファイルマネージャの一部)でこれを使用してファイルを復号化し、サブプロセスが終了したときに削除される一時ファイルでライフルを実行します。 (設定することを忘れないでください$TERMCMD
)
# ~/.config/ranger/rifle.conf
...
!ext exe, mime octet-stream$, has gpg, flag t = () { rifle -f F "$1" } =(gpg -dq "$1")