답변:
임시 파일의 경우 문제의 예제는 파일을 만든 다음 디렉토리에서 링크를 해제하고 ( "사라짐") 스크립트가 파일 설명자를 닫을 때 (아마도 종료시) 파일에서 차지하는 공간 시스템에서 회수 할 수 있습니다. 이것은 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
요구.
.
and ..
항목 도 없습니다 . (리눅스에서 테스트 한 결과 플랫폼간에 일관성이 있는지 모르겠습니다.)
exec another-command
명백하게 호출되는 경우에도 EXIT 트랩이 실행되지 않습니다 .
스크립트가 끝나면 스크립트가 실행될 쉘 함수를 작성하십시오. 아래 예제에서 나는 그것을 'cleanup'이라고 부르고 다음과 같이 출구 레벨에서 실행될 트랩을 설정합니다. 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의 스크립트 종료 이것은 분명 부족한 경우.
나중에 그 안에 경로를 사용하지 않으면 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 파일 시스템을 마운트하고 /proc/sysvipc
chdir을 command
지정한 후 주어진 인수로 실행 합니다. command
것 없는 상속 CAP_SYS_ADMIN
기능을.
해당 파일 시스템은에서 시작되지 않은 다른 프로세스에서 액세스 할 수 없으며 , 그 방법에 관계없이 자식과 자식이 죽을 command
때 파일 내부에서 생성 된 모든 파일과 함께 마술처럼 사라집니다 command
. 이것은 마운트 네임 스페이스를 공유하지 않는 것입니다 command
. 동일한 사용자가 실행하는 프로세스와 다른 프로세스 간에는 하드 장벽이 없습니다 . 그들은 여전히 통해 하나의 네임 스페이스 내부에 몰래 수 ptrace(2)
, /proc/PID/cwd
또는 다른 수단에 의해.
"무용지물"의 하이재킹은 /proc/sysvipc
물론 어리석은 일이지만, 대안은 /tmp
비어있는 디렉토리를 가진 스팸 으로,이 작은 프로그램을 제거하고 포크와 기다림으로 크게 복잡하게 만드는 것일 수 있습니다. 대안 적으로, dir
예를 들어로 변경 될 수있다. /mnt/chtmp
설치시 루트로 작성하십시오. 사용자가 구성 할 수 없도록하고 사용자 소유 경로로 설정하지 마십시오. 시간이 걸리지 않는 symlink 트랩 및 기타 털이 많은 물건에 노출 될 수 있습니다.
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)
.
<(...) 대신 = (...)를 사용하면 인수로 전달 된 파일은 목록 프로세스의 출력을 포함하는 임시 파일의 이름이됩니다. 이 상하는 해당 프로그램에 대한 <form 대신 사용될 수있다
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")