[bash] 예기치 않은 bash 종료에서 생성 된 임시 파일 제거

bash 스크립트에서 임시 파일을 만들고 있습니다. 처리가 끝날 때 삭제하지만 스크립트가 꽤 오랫동안 실행되고 있기 때문에 실행 중에 종료하거나 CTRL-C를 실행하면 임시 파일이 삭제되지 않습니다.
실행이 끝나기 전에 이러한 이벤트를 포착하고 파일을 정리할 수있는 방법이 있습니까?

또한 해당 임시 파일의 이름과 위치에 대한 모범 사례가 있습니까?
현재 다음을 사용하는지 잘 모르겠습니다.

TMP1=`mktemp -p /tmp`
TMP2=`mktemp -p /tmp`
...

TMP1=/tmp/`basename $0`1.$$
TMP2=/tmp/`basename $0`2.$$
...

아니면 더 나은 해결책이 있습니까?



답변

종료 할 때 실행하도록 ” trap “을 설정 하거나 정리하기 위해 control-c에서 실행할 수 있습니다.

trap "{ rm -f $LOCKFILE; }" EXIT

또는 내가 가장 좋아하는 유닉스 리즘 중 하나는 파일을 연 다음 열려있는 동안 삭제하는 것입니다. 파일은 파일 시스템에 남아 있으며 읽고 쓸 수 있지만 프로그램이 종료되면 파일이 사라집니다. 그래도 bash에서 어떻게할지 모르겠습니다.

BTW : 자신의 솔루션을 사용하는 대신 mktemp를 선호하는 한 가지 주장 : 사용자가 프로그램이 거대한 임시 파일을 생성 할 것으로 예상하면 TMPDIR/ var / tmp와 같이 더 큰 어딘가로 설정하고 싶을 수 있습니다 . mktemp는 손으로 굴린 솔루션 (두 번째 옵션)은 인식하지 못합니다. TMPDIR=/var/tmp gvim -d foo bar예를 들어 나는 자주 사용 합니다.


답변

일반적으로 모든 임시 파일을 저장할 디렉터리를 만든 다음 스크립트가 종료 될 때이 디렉터리를 정리하는 EXIT 처리기를 만듭니다.

MYTMPDIR=$(mktemp -d)
trap "rm -rf $MYTMPDIR" EXIT

모든 임시 파일을 아래에두면 $MYTMPDIR대부분의 상황에서 스크립트가 종료 될 때 모두 삭제됩니다. SIGKILL (kill -9)로 프로세스를 종료하면 프로세스가 즉시 종료되므로이 경우 EXIT 핸들러가 실행되지 않습니다.


답변

trap 명령 을 사용하여 스크립트 종료 또는 CTRL-C와 같은 신호를 처리 하려고합니다 . 자세한 내용은 Greg의 Wiki 를 참조하십시오.

basename $0임시 파일의 경우 충분한 임시 파일을위한 공간을 제공하는 템플릿을 제공 할뿐만 아니라 사용 하는 것이 좋습니다.

tempfile() {
    tempprefix=$(basename "$0")
    mktemp /tmp/${tempprefix}.XXXXXX
}

TMP1=$(tempfile)
TMP2=$(tempfile)

trap 'rm -f $TMP1 $TMP2' EXIT


답변

선택한 답변은 bashism이며 이는 다음과 같은 솔루션을 의미합니다.

trap "{ rm -f $LOCKFILE }" EXIT

bash에서만 작동합니다 (shell이 dash또는 classic 인 경우 Ctrl + c를 잡지 못함 sh). 호환성을 원한다면 트랩하려는 모든 신호를 열거해야합니다.

또한 스크립트가 신호 “0”(일명 EXIT)에 대한 트랩을 종료 할 때 항상 수행되어 trap명령이 두 번 실행된다는 점에 유의하십시오 .

EXIT 신호가 있으면 모든 신호를 한 줄에 쌓지 않는 이유입니다.

더 잘 이해하려면 변경없이 다른 시스템에서 작동하는 다음 스크립트를 살펴보십시오.

#!/bin/sh

on_exit() {
  echo 'Cleaning up...(remove tmp files, etc)'
}

on_preExit() {
  echo
  echo 'Exiting...' # Runs just before actual exit,
                    # shell will execute EXIT(0) after finishing this function
                    # that we hook also in on_exit function
  exit 2
}


trap on_exit EXIT                           # EXIT = 0
trap on_preExit HUP INT QUIT TERM STOP PWR  # 1 2 3 15 30


sleep 3 # some actual code...

exit

이 솔루션은 최종 종료 ( preExit함수) 직전에 실제 신호 발생시 일부 코드를 실행할 수 있고 필요한 경우 실제 EXIT 신호 (종료 최종 단계)에서 일부 코드를 실행할 수 있으므로 더 많은 제어를 제공합니다.


답변

예측 가능한 파일 이름을 $$와 함께 사용하는 대안은 틈이있는 보안 허점이며 절대로 사용에 대해 생각해서는 안됩니다. 단일 사용자 PC의 단순한 개인 스크립트 일지라도. 당신이 얻지 말아야 할 아주 나쁜 습관입니다. BugTraq 은 “안전하지 않은 임시 파일”사고로 가득 차 있습니다. 임시 파일의 보안 측면에 대한 자세한 내용 은 여기 , 여기여기 를 참조 하십시오 .

처음에는 안전하지 않은 TMP1 및 TMP2 할당을 인용 할 생각 이었지만 다시 생각 하면 좋은 생각 이 아닐 것입니다 .


답변

tempfile안전한 방식으로 / tmp에 파일을 생성하는 것을 선호 하며 이름 지정에 대해 걱정할 필요가 없습니다.

tmp=$(tempfile -s "your_sufix")
trap "rm -f '$tmp'" exit


답변

나는 너무 많은 사람들이 파일 이름에 공백이 없을 것이라고 생각한다고 믿을 수 없습니다. $ TMPDIR이 “임시 디렉토리”에 할당되면 세계가 충돌합니다.

zTemp=$(mktemp --tmpdir "$(basename "$0")-XXX.ps")
trap "rm -f ${zTemp@Q}" EXIT

파일 이름의 작은 따옴표 및 캐리지 리턴과 같은 공백 및 기타 특수 문자는 적절한 프로그래밍 습관의 요구 사항으로 코드에서 고려해야합니다.