Possiamo usare cartelle temporanee come file temporanei
TMP=$(mktemp ... )
exec 3<>$TMP
rm $TMP
cat <&3
quale verrà distrutto automaticamente dopo l'uscita di questa shell?
Possiamo usare cartelle temporanee come file temporanei
TMP=$(mktemp ... )
exec 3<>$TMP
rm $TMP
cat <&3
quale verrà distrutto automaticamente dopo l'uscita di questa shell?
Risposte:
Nel caso di un file temporaneo, il tuo esempio nella domanda lo creerebbe, quindi lo scollegerebbe dalla directory (facendolo "scomparire"), e quando lo script chiude il filedescriptor (probabilmente al termine), lo spazio occupato dal file sarebbe recuperabile dal sistema. Questo è un modo comune per gestire i file temporanei in lingue come C.
Per quanto ne so, non è possibile aprire una directory allo stesso modo, almeno non in alcun modo che renderebbe utilizzabile la directory.
Un modo comune per eliminare file e directory temporanei al termine di uno script è l'installazione di una EXIT
trappola di pulizia . Gli esempi di codice riportati di seguito evitano di dover destreggiarsi completamente con i filedescriptor.
tmpdir=$(mktemp -d)
tmpfile=$(mktemp)
trap 'rm -f "$tmpfile"; rm -rf "$tmpdir"' EXIT
# The rest of the script goes here.
Oppure puoi chiamare una funzione di pulizia:
cleanup () {
rm -f "$tmpfile"
rm -rf "$tmpdir"
}
tmpdir=$(mktemp -d)
tmpfile=$(mktemp)
trap cleanup EXIT
# The rest of the script goes here.
La EXIT
trappola non verrà eseguita alla ricezione del KILL
segnale (che non può essere intrappolato), il che significa che non verrà eseguita alcuna pulizia. Verrà comunque eseguito al termine a causa di un segnale INT
o TERM
(se in esecuzione con bash
o ksh
, in altre shell potresti voler aggiungere questi segnali dopo EXIT
nella trap
riga di comando) o quando esci normalmente a causa dell'arrivo alla fine dello script o dell'esecuzione di un exit
chiamata.
.
e ..
. (Testato su Linux, non so se sia coerente su tutte le piattaforme.)
exec another-command
ovviamente.
Scrivi una funzione shell che verrà eseguita al termine dello script. Nell'esempio seguente lo chiamo 'cleanup' e imposto una trap da eseguire ai livelli di uscita, come: 0 1 2 3 6
trap cleanup 0 1 2 3 6
cleanup()
{
[ -d $TMP ] && rm -rf $TMP
}
Vedi questo post per maggiori informazioni.
cleanup
prima di un'uscita pulita (0) e alla ricezione di SIGHUP (1), SIGINT (2), SIGQUIT (3) e SIGABRT (6). essa non eseguito cleanup
quando lo script si chiude a causa di SIGTERM, SIGSEGV, SIGKILL, SIGPIPE, ecc Questo è chiaramente carente.
Puoi chdir in esso e quindi rimuoverlo, a condizione che non provi a utilizzare i percorsi al suo interno in seguito:
#! /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
Non ho verificato, ma è probabilmente lo stesso problema quando si utilizza openat (2) in C con una directory che non esiste più nel file system.
Se sei root e su Linux, puoi giocare con uno spazio dei nomi separato e mount -t tmpfs tmpfs /dir
al suo interno.
Le risposte canoniche (imposta una trappola su EXIT) non funzionano se lo script viene forzato in un'uscita impura (ad es. Con SIGKILL); che può lasciare in giro dati sensibili.
Aggiornare:
Ecco una piccola utility che implementa l'approccio dello spazio dei nomi. Dovrebbe essere compilato con
cc -Wall -Os -s chtmp.c -o chtmp
e date CAP_SYS_ADMIN
le capacità dei file (come root) con
setcap CAP_SYS_ADMIN+ep chtmp
Quando eseguito (come un normale) utente come
./chtmp command args ...
annullerà la condivisione del suo spazio dei nomi di filesystem, monterà un filesystem tmpfs /proc/sysvipc
, lo inserirà in chdir ed eseguirà command
con gli argomenti forniti. command
sarà non ereditare le CAP_SYS_ADMIN
funzionalità.
Quel filesystem non sarà accessibile da un altro processo da cui non è stato avviato command
e scomparirà magicamente (con tutti i file che sono stati creati al suo interno) quando command
e i suoi figli muoiono, indipendentemente da come ciò accada. Si noti che si tratta solo di annullare la condivisione dello spazio dei nomi mount - non ci sono barriere tra command
e altri processi eseguiti dallo stesso utente; potevano ancora intrufolarsi nel suo spazio dei nomi tramite ptrace(2)
, /proc/PID/cwd
o con altri mezzi.
Il dirottamento dell '"inutile" /proc/sysvipc
è, ovviamente, sciocco, ma l'alternativa sarebbe stata quella di inviare spam /tmp
con directory vuote che avrebbero dovuto essere rimosse o complicare notevolmente questo piccolo programma con fork e attese. In alternativa, dir
può essere modificato ad es. /mnt/chtmp
e lo hanno creato da root all'installazione; non renderlo configurabile dall'utente e non impostarlo su un percorso di proprietà dell'utente in quanto ciò potrebbe esporvi a trappole symlink e altre cose pelose su cui non vale la pena spendere tempo.
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);
}
rm $PWD
lavoro, shell è ancora in quella directory. Ma non è possibile inserire nuovi file in questa "cartella". Solo tu puoi fare è leggere / scrivere con il file & 3, e 4. Quindi questo è ancora "file temporaneo", non "cartella temporanea".
Hai bisogno di una shell specifica?
Se zsh è un'opzione, leggi zshexpn(1)
:
Se viene utilizzato = (...) anziché <(...), il file passato come argomento sarà il nome di un file temporaneo contenente l'output del processo di elenco. Questo può essere usato al posto del <modulo per un programma che prevede di
lseek
(vederelseek(2)
) sul file di input.[...]
Un altro problema sorge ogni volta che un lavoro con una sostituzione che richiede un file temporaneo viene rinnegato dalla shell, incluso il caso in cui
&!
o&|
appare alla fine di un comando contenente una sostituzione. In tal caso il file temporaneo non verrà ripulito poiché la shell non ha più memoria del lavoro. Una soluzione alternativa consiste nell'utilizzare una subshell, ad esempio,(mycmd =(myoutput)) &!
poiché la subshell biforcuta attenderà il completamento del comando, quindi rimuoverà il file temporaneo.
Una soluzione generale per garantire che una sostituzione del processo duri per un periodo di tempo appropriato è passarla come parametro a una funzione shell anonima (un pezzo di codice shell che viene eseguito immediatamente con l'ambito della funzione). Ad esempio, questo codice:
() { print File $1: cat $1 } =(print This be the verse)
produce qualcosa di simile al seguente
File /tmp/zsh6nU0kS: This be the verse
Ad esempio, lo uso in rifle (parte del file manager ranger) per decrittografare un file e quindi eseguo rifle sul file temporaneo, che viene eliminato al termine dei processi secondari. (non dimenticare di impostare $TERMCMD
)
# ~/.config/ranger/rifle.conf
...
!ext exe, mime octet-stream$, has gpg, flag t = () { rifle -f F "$1" } =(gpg -dq "$1")