쉘 스크립트에서 임시 파일을 작성하는 방법


155

스크립트를 실행하는 동안 /tmp디렉토리에 임시 파일을 만들고 싶습니다 .

해당 스크립트를 실행 한 후에는 해당 스크립트로 정리됩니다.

쉘 스크립트에서 어떻게합니까?

답변:


198
tmpfile=$(mktemp /tmp/abc-script.XXXXXX)
: ...
rm "$tmpfile"

파일 설명자를 파일로 열고 삭제하여 스크립트가 종료 (킬 (kill) 및 충돌 포함) 할 때 파일이 삭제되도록 할 수 있습니다. /proc/$PID/fd/$FD파일 디스크립터가 열려있는 한 파일 은 스크립트에 사용할 수 있습니다 (실제로 다른 프로세스는 아니지만 해결 방법입니다). 파일 시스템이 닫히면 (프로세스가 종료 될 때 커널이 자동으로 수행함) 파일 시스템이 파일을 삭제합니다.

tmpfile=$(mktemp /tmp/abc-script.XXXXXX)
exec 3>"$tmpfile"
rm "$tmpfile"
: ...
echo foo >&3

4
좋은 대답, 충돌이 +1 인 경우 파일 디스크립터가 포함 된 우아한 솔루션
혼돈

2
/proc-시스템이없는 시스템을 제외하고.
Dennis Williamson

4
무엇을 exec 3> "$tmpfile"합니까? tmpfile이 독립형 스크립트 인 경우에만 유용하지 않습니까?
Alexej Magura

5
작성된 FD를 어떻게 읽습니까?
eckes

3
"cat <3 또는 이와 유사한 것을 사용할 수 있습니다." 실제로 3 @ dragon788이라는 파일에서 읽습니다. 또한, cat <&3줄 것이다 Bad file descriptor. 고치거나 제거하면 고맙겠습니다. 잘못된 정보는별로 도움이되지 않습니다.
다니엘 파렐

65

mktemp임시 파일 또는 디렉토리를 작성하는 데 사용하십시오 .

temp_file=$(mktemp)

또는 이분법의 경우 :

temp_dir=$(mktemp -d)

스크립트가 끝나면 임시 파일 / dir을 삭제해야합니다.

rm ${temp_file}
rm -R ${temp_dir}

mktemp는 /tmp디렉토리 또는 --tmpdir인수 와 함께 주어진 술집에 파일을 작성합니다 .


20
trap "rm -f $temp_file" 0 2 3 15파일을 만든 직후에 스크립트를 종료하거나 ctrl-C파일 과 함께 중지 할 때 파일이 여전히 제거 되도록 사용할 수 있습니다 .
wurtel

1
@ wurtel EXIT유일한 후크 경우 어떻게됩니까 trap?
Hauke ​​Laging

4
@HaukeLaging 그런 다음 Ctrl + C로 스크립트를 중지하면 트랩이 시작되지 않습니다. 주목해야 할 것은 TRAP이 도움이되지 않는다는 것 kill -9 $somepid입니다. 그 특별한 킬 신호는 다른 일이 일어나지 않아 타협합니다.
dragon788

5
@ dragon788 시도해 보셨습니까? 당신은해야합니다. bash -c 'echo $$; trap "echo foo" 0; sleep 5'
Hauke ​​Laging

트래핑 EXIT이면 충분합니다.
Kusalananda

15

mktemp 가있는 시스템을 사용하는 경우 다른 답변으로 사용해야합니다.

POSIX toolchest 사용시 :

umask 0177
tmpfile=/tmp/"$0"."$$"."$(awk 'BEGIN {srand();printf "%d\n", rand() * 10^10}')"
trap 'rm -f -- "$tmpfile"' INT TERM HUP EXIT
: > "$tmpfile"

EXIT유일한 후크 라면 어떻게됩니까 trap?
Hauke ​​Laging

@HaukeLaging : tmpfile스크립트 종료 전에 여전히 제거되지만 스크립트가 다른 신호를 수신 한 경우에는 제거되지 않습니다.
cuonglm 2018 년

여기서 일어나는 일은 아닙니다 (GNU bash, 버전 4.2.53).
Hauke ​​Laging

@HaukeLaging : 무슨 뜻 That's not what happens인가요?
cuonglm

3
mktempHP / UX에서 다른 구문으로 시작되었습니다. Todd C. Miller는 90 년대 중반 (FreeBSD와 NetBSD에서 복사)에 OpenBSD 용으로 다른 것을 만들고 나중에 독립형 유틸리티 (www.mktemp.org)로도 사용할 수있게했습니다. mktemp2007 년에 GNU coreutils에 (대부분 호환되는) 유틸리티가 추가 될 때까지 Linux에서 일반적으로 사용 된 mktemp도구입니다. 실제로 말할 수없는 것은 GNU 유틸리티입니다.
Stéphane Chazelas

14

일부 쉘에는 기능이 내장되어 있습니다.

zsh

zsh=(...)공정 대체의 형태는 임시 파일을 사용합니다. 예를 들어 =(echo test),가 포함 된 임시 파일의 경로로 확장됩니다 test\n.

$ {cat $file; ls -l /dev/fd/3; echo test2 >&3; cat $file} 3<> ${file::==(echo test)}
test
lrwx------ 1 stephane stephane 64 Jan 30 11:19 /dev/fd/3 -> /tmp/zshMLbER0
test2

명령이 완료되면 해당 파일이 자동으로 제거됩니다.

Linux의 bash / zsh

여기에서 파일 또는 여기 - 문자열의 bash와는 zsh삭제 된 임시 파일로 구현됩니다.

따라서 할 경우 :

exec 3<<< test

파일 디스크립터 3이 포함 된 삭제 된 임시 파일에 연결되어 있습니다 test\n.

다음을 통해 컨텐츠를 얻을 수 있습니다.

cat <&3

Linux의 경우 다음을 통해 해당 파일을 읽거나 쓸 수도 있습니다 /dev/fd/3

$ exec 3<<< test
$ cat <&3
test
$ echo foo > /dev/fd/3
$ cat /dev/fd/3
foo

(일부 다른 쉘은 파이프를 사용하거나 /dev/nullhere 문서가 비어 있으면 사용할 수 있습니다 ).

POSIX

mktempPOSIX 유틸리티 가 없습니다 . 그러나 POSIX는 mkstemp(template)C API를 지정 하고 m4표준 유틸리티는 mkstemp()동일한 이름으로 m4 함수 를 사용하여 해당 API를 노출합니다 .

mkstemp()함수가 호출 될 때 존재하지 않는 임의 부분이있는 파일 이름을 제공합니다. 레이스가없는 방식으로 권한이 0600 인 파일을 만듭니다.

그래서 당신은 할 수 있습니다 :

tmpfile=$(
  echo 'mkstemp(template)' |
    m4 -D template="${TMPDIR:-/tmp}/baseXXXXXX"
) || exit

그러나 종료시 정리를 처리해야하지만 파일을 고정 된 횟수만큼 읽고 쓸 필요가있는 경우 here-doc / here-와 같이 만든 후 바로 파일을 열고 삭제할 수 있습니다. 위의 문자열 접근 방식 :

tmpfile=$(
  echo 'mkstemp(template)' |
    m4 -D template="${TMPDIR:-/tmp}/baseXXXXXX"
) || exit

# open once for writing, twice for reading:
exec 3> "$tempfile" 4< "$tempfile" 5< "$tempfile"

rm -f -- "$tmpfile"

cmd >&3   # store something in the temp file
exec 3>&- # fd no longer needed

# read the content twice:
cat <&4
cat <&5

한 번 읽기 위해 파일을 열고 두 번의 읽기 사이에서 되감기를 할 수 있지만 되감기 ( lseek())를 수행 할 수있는 POSIX 유틸리티 는 없으므로 POSIX 스크립트 ( zsh( sysseek기본 제공) 및 ksh93( <#((...))연산자) 에서 이식 가능하지 않음 ) 그래도).


1
Bash의 프로세스 대체<()
WinnieNicklaus

3
@WinnieNicklaus, 예. 임시 파일을 사용하지 않으므로 여기와 관련이 없습니다. 프로세스 대체는 ksh에 의해 도입되었으며 bash 및 zsh에 의해 복사되었으며 zsh는이를 세 번째 형식으로 확장했습니다 =(...).
Stéphane Chazelas

7

Hauke ​​Laging의 라인에서 약간 개선 된 답변이 있습니다.

#!/bin/bash

tmpfile=$(mktemp)  # Create a temporal file in the default temporal folder of the system

# Lets do some magic for the tmpfile to be removed when this script ends, even if it crashes
exec {FD_W}>"$tmpfile"  # Create file descriptor for writing, using first number available
exec {FD_R}<"$tmpfile"  # Create file descriptor for reading, using first number available
rm "$tmpfile"  # Delete the file, but file descriptors keep available for this script

# Now it is possible to work with the temporal file
echo foo >&$FD_W
echo bar >&$FD_W  # Note that file descriptor always concatenates, not overwrites

cat <&$FD_R

2
내용은 한 번만 사용할 수 있습니다. 즉, cat <& $ FD_R을 두 번째로 수행하면 출력이 생성되지 않습니다. unix.stackexchange.com/questions/166482/…를 참조하십시오 . 프로그램 충돌시 파일을 자동으로 삭제하지만 여러 번 액세스 할 수있는 방법이 있습니까?
smihael

0

일반적으로 임시 파일이있는 워크 플로는 테스트중인 bash 스크립트 때문입니다. 나는 tee그것이 작동하고 있음을 알 수 있고 프로세스의 다음 반복을 위해 출력을 저장하고 싶습니다. 라는 파일을 만들었습니다tmp

#!/bin/bash
echo $(mktemp /tmp/$(date +"%Y-%m-%d_%T_XXXXXX"))

내가 그것을 사용할 수 있도록

$ some_command --with --lots --of --stuff | tee $(tmp)

임의의 값보다 형식이 지정된 날짜 시간을 좋아하는 이유는 내가 방금 만든 tmp 파일을 찾을 수 있기 때문에 다음 번에 이름을 지정할 대상을 생각할 필요가 없습니다. 일하다).

당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.