Czy możemy używać folderów tymczasowych, takich jak pliki tymczasowe
TMP=$(mktemp ... )
exec 3<>$TMP
rm $TMP
cat <&3
które zostaną zniszczone automatycznie po wyjściu z tej powłoki?
Czy możemy używać folderów tymczasowych, takich jak pliki tymczasowe
TMP=$(mktemp ... )
exec 3<>$TMP
rm $TMP
cat <&3
które zostaną zniszczone automatycznie po wyjściu z tej powłoki?
Odpowiedzi:
W przypadku pliku tymczasowego twój przykład w pytaniu utworzy go, a następnie odłączy go od katalogu (sprawiając, że „zniknie”), a gdy skrypt zamknie deskryptor plików (prawdopodobnie po zakończeniu), miejsce zajmowane przez plik byłby możliwy do odzyskania przez system. Jest to powszechny sposób postępowania z plikami tymczasowymi w językach takich jak C.
O ile mi wiadomo, nie można otworzyć katalogu w ten sam sposób, a przynajmniej nie w żaden sposób, który uczyniłby katalog użytecznym.
Częstym sposobem usuwania plików tymczasowych i katalogów po zakończeniu skryptu jest zainstalowanie EXITpułapki czyszczenia . Poniższe przykłady kodu pozwalają uniknąć konieczności żonglowania deskryptorami plików.
tmpdir=$(mktemp -d)
tmpfile=$(mktemp)
trap 'rm -f "$tmpfile"; rm -rf "$tmpdir"' EXIT
# The rest of the script goes here.
Lub możesz wywołać funkcję czyszczenia:
cleanup () {
rm -f "$tmpfile"
rm -rf "$tmpdir"
}
tmpdir=$(mktemp -d)
tmpfile=$(mktemp)
trap cleanup EXIT
# The rest of the script goes here.
EXITPułapka nie zostanie wykonana po otrzymaniu KILLsygnału (który nie może być uwięziony), co oznacza, że nie będzie żadnego czyszczenia wykonywane wtedy. Będzie on jednak wykonywany po zakończeniu z powodu sygnału INTlub TERM(jeśli działa z bashlub kshw innych powłokach, możesz chcieć dodać te sygnały po EXITw trapwierszu poleceń), lub gdy kończy się normalnie z powodu dojścia do końca skryptu lub wykonania exitpołączenie.
.i ... (Testowany w systemie Linux, nie wiem, czy jest spójny na różnych platformach).
exec another-commandoczywiście.
Napisz funkcję powłoki, która zostanie wykonana po zakończeniu skryptu. W poniższym przykładzie nazywam to „porządkiem” i ustawiam pułapkę do wykonania na poziomach wyjścia, np .: 0 1 2 3 6
trap cleanup 0 1 2 3 6
cleanup()
{
[ -d $TMP ] && rm -rf $TMP
}
Zobacz ten post, aby uzyskać więcej informacji.
cleanupprzed czystym wyjściem (0) i po otrzymaniu SIGHUP (1), SIGINT (2), SIGQUIT (3) i SIGABRT (6). będzie nie działać cleanup, gdy wychodzi script powodu SIGTERM, SIGSEGV, SIGKILL, SIGPIPE itp Jest to wyraźnie niewystarczające.
Możesz do niego przejść, a następnie go usunąć, pod warunkiem, że później nie będziesz próbował używać ścieżek:
#! /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
Nie sprawdziłem, ale najprawdopodobniej ten sam problem występuje podczas używania openat (2) w C z katalogiem, który już nie istnieje w systemie plików.
Jeśli jesteś rootem i na Linuksie, możesz grać z oddzielną przestrzenią nazw i mount -t tmpfs tmpfs /dirwewnątrz niej.
Odpowiedzi kanoniczne (ustaw pułapkę na EXIT) nie działają, jeśli twój skrypt jest zmuszony do nieczystego wyjścia (np. Za pomocą SIGKILL); które mogą pozostawić wrażliwe dane.
Aktualizacja:
Oto małe narzędzie, które implementuje podejście do przestrzeni nazw. Należy go skompilować
cc -Wall -Os -s chtmp.c -o chtmp
i dane CAP_SYS_ADMINmożliwości pliku (jako root) za pomocą
setcap CAP_SYS_ADMIN+ep chtmp
Po uruchomieniu (jako normalny) użytkownik jako
./chtmp command args ...
usunie udostępnienie przestrzeni nazw systemu plików, zamontuje system plików tmpfs /proc/sysvipc, chdir i uruchomi commandpodane argumenty. commandbędzie nie dziedziczą CAP_SYS_ADMINmożliwości.
Ten system plików nie będzie dostępny z innego procesu, od którego nie został uruchomiony command, i magicznie zniknie (wraz ze wszystkimi plikami, które zostały w nim utworzone), kiedy commandi jego dzieci umrą, bez względu na to, jak to się stanie. Zauważ, że jest to po prostu udostępnianie przestrzeni nazw montowania - nie ma twardych barier między commandinnymi procesami uruchamianymi przez tego samego użytkownika; wciąż mogli się zakraść w przestrzeni nazw albo przez ptrace(2), /proc/PID/cwdalbo w inny sposób.
Porwanie „bezużytecznego” /proc/sysvipcjest oczywiście głupie, ale alternatywą byłoby spamowanie /tmppustymi katalogami, które należałoby usunąć lub znacznie komplikować ten mały program widelcami i czekaniem. Alternatywnie dirmożna zmienić na np. /mnt/chtmpi niech utworzy go root podczas instalacji; nie konfiguruj go i nie ustawiaj na ścieżkę należącą do użytkownika, ponieważ może to narazić Cię na pułapki dowiązań symbolicznych i inne włochate rzeczy, na których nie warto spędzać czasu.
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 $PWDpraca, skorupa wciąż jest w tym katalogu. Ale w tym „folderze” nie można umieszczać nowych plików. Jedyne, co możesz zrobić, to odczyt / zapis za pomocą plików i 3 oraz 4. Jest to więc nadal „plik tymczasowy”, a nie „folder tymczasowy”.
Czy potrzebujesz konkretnej powłoki?
Jeśli zsh jest opcją, przeczytaj zshexpn(1):
Jeśli zamiast <(...) zostanie użyta wartość = (...), plik przekazany jako argument będzie nazwą pliku tymczasowego zawierającego dane wyjściowe procesu listy. Można tego użyć zamiast formularza <dla programu, który oczekuje
lseek(patrzlseek(2)) w pliku wejściowym.[...]
Kolejny problem pojawia się za każdym razem, gdy powłoka odrzuca zadanie z podstawieniem, które wymaga pliku tymczasowego, w tym przypadek, w którym
&!lub&|pojawia się na końcu polecenia zawierającego podstawienie. W takim przypadku plik tymczasowy nie zostanie wyczyszczony, ponieważ powłoka nie ma już pamięci zadania. Obejściem tego problemu jest użycie podpowłoki, na przykład(mycmd =(myoutput)) &!ponieważ rozwidlona podpowłoka będzie czekać na zakończenie polecenia, a następnie usunie plik tymczasowy.
Ogólnym obejściem zapewniającym, że podstawienie procesu trwa przez odpowiedni czas, jest przekazanie go jako parametru do anonimowej funkcji powłoki (fragment kodu powłoki uruchamiany natychmiast z zakresem funkcji). Na przykład ten kod:
() { print File $1: cat $1 } =(print This be the verse)wyprowadza coś podobnego do następującego
File /tmp/zsh6nU0kS: This be the verse
Na przykład używam tego w karabinie (część menedżera plików ranger), aby odszyfrować plik, a następnie uruchomić karabin na pliku tymczasowym, który zostanie usunięty po zakończeniu podprocesów. (nie zapomnij ustawić $TERMCMD)
# ~/.config/ranger/rifle.conf
...
!ext exe, mime octet-stream$, has gpg, flag t = () { rifle -f F "$1" } =(gpg -dq "$1")