Можем ли мы использовать временные папки, такие как временные файлы
TMP=$(mktemp ... )
exec 3<>$TMP
rm $TMP
cat <&3
который будет уничтожен автоматически после выхода из оболочки?
Можем ли мы использовать временные папки, такие как временные файлы
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
вызов.
.
и ..
запись. (Протестировано на Linux, я не знаю, совместимо ли это на разных платформах.)
exec another-command
явно.
Напишите shell-функцию, которая будет выполнена, когда ваш скрипт завершит работу. В приведенном ниже примере я называю это «очистка» и устанавливаю ловушку для выполнения на уровнях выхода, например: 0 1 2 3 6
trap cleanup 0 1 2 3 6
cleanup()
{
[ -d $TMP ] && rm -rf $TMP
}
Смотрите этот пост для получения дополнительной информации.
cleanup
перед чистым выходом (0) и при получении SIGHUP (1), SIGINT (2), SIGQUIT (3) и SIGABRT (6). он не будет работать cleanup
при выходе из сценария из-за SIGTERM, SIGSEGV, SIGKILL, SIGPIPE и т. д. Это явно недостаточно.
Вы можете зайти в него, а затем удалить его, при условии, что впоследствии вы не будете пытаться использовать пути внутри него:
#! /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
Я не проверял, но это, скорее всего, та же проблема при использовании openat (2) в C с каталогом, который больше не существует в файловой системе.
Если вы root и в Linux, вы можете играть как с отдельным пространством имен, так и mount -t tmpfs tmpfs /dir
внутри него.
Канонические ответы (ставить ловушку на EXIT) не работают, если ваш скрипт принудительно завершает нечистый выход (например, с помощью SIGKILL); это может привести к зависанию конфиденциальных данных.
Обновить:
Вот небольшая утилита, которая реализует подход пространства имен. Это должно быть скомпилировано с
cc -Wall -Os -s chtmp.c -o chtmp
и данные CAP_SYS_ADMIN
возможности файла (как root) с
setcap CAP_SYS_ADMIN+ep chtmp
Когда запускается (как обычный) пользователь как
./chtmp command args ...
он откроет пространство имен своей файловой системы, смонтирует файловую систему tmpfs /proc/sysvipc
, вставит в нее chdir и запустит command
с заданными аргументами. неcommand
будет наследовать возможности.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);
}
rm $PWD
работа, оболочка еще в этом каталоге. Но никакие новые файлы не могут быть помещены в эту «папку». Только вы можете читать / писать с файлами & 3, & 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
Например, я использую это в винтовке (часть файлового менеджера рейнджера) для расшифровки файла, а затем запускаю винтовку для временного файла, который удаляется после завершения подпроцессов. (не забудьте установить $TERMCMD
)
# ~/.config/ranger/rifle.conf
...
!ext exe, mime octet-stream$, has gpg, flag t = () { rifle -f F "$1" } =(gpg -dq "$1")