Ответы:
tmpfile=$(mktemp /tmp/abc-script.XXXXXX)
: ...
rm "$tmpfile"
Вы можете убедиться, что файл удаляется при выходе из сценария (включая убийства и сбои), открыв файловый дескриптор файла и удалив его. Файл остается доступным (для сценария; на самом деле не для других процессов, но /proc/$PID/fd/$FD
является обходным путем), пока дескриптор файла открыт. Когда он закрывается (что делает ядро автоматически при выходе из процесса), файловая система удаляет файл.
tmpfile=$(mktemp /tmp/abc-script.XXXXXX)
exec 3>"$tmpfile"
rm "$tmpfile"
: ...
echo foo >&3
/proc
- за исключением систем, у которых его нет.
exec 3> "$tmpfile"
? Разве это не полезно, если tmpfile - это отдельный скрипт?
cat <&3
даст Bad file descriptor
. Буду признателен, если вы исправите или удалите это; дезинформация не очень помогает.
Используйте mktemp
для создания временного файла или каталога:
temp_file=$(mktemp)
Или для направления:
temp_dir=$(mktemp -d)
В конце скрипта вы должны удалить временный файл / dir:
rm ${temp_file}
rm -R ${temp_dir}
mktemp создает файл в /tmp
каталоге или в каталоге, указанном с --tmpdir
аргументом.
trap "rm -f $temp_file" 0 2 3 15
сразу после создания файла, чтобы при выходе из скрипта или его остановке ctrl-C
файл все равно удалялся.
EXIT
это единственный крюк для trap
?
kill -9 $somepid
. Этот конкретный сигнал убийства - insta-death, и больше ничего не происходит.
bash -c 'echo $$; trap "echo foo" 0; sleep 5'
EXIT
достаточно.
Если вы используете систему, в которой есть 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
?
tmpfile
прежнему удаляется до выхода из скрипта, но не тогда, когда скрипт получает другие сигналы.
That's not what happens
?
mktemp
возникла в HP / UX с другим синтаксисом. Тодд С. Миллер создал в середине 90-х другой вариант для OpenBSD (скопированный FreeBSD и NetBSD), а затем сделал его также доступным в качестве отдельной утилиты (www.mktemp.org). Это тот тип, который обычно использовался в Linux, пока mktemp
в 2007 году в GNU coreutils не была добавлена (в основном совместимая) утилита. Просто сказать, что нельзя сказать, mktemp
что это утилита GNU.
Некоторые оболочки имеют встроенную функцию.
zsh
«s =(...)
форма замещения процесса использует временный файл. Например, =(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
Этот файл автоматически удаляется после завершения команды.
Здесь-файлы или здесь-строки в 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/null
если документ здесь пуст).
mktemp
Утилиты POSIX нет . Однако в POSIX указан mkstemp(template)
API C , а m4
стандартная утилита предоставляет этот API с mkstemp()
функцией m4 с тем же именем.
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
Вы можете открыть файл для чтения один раз и перемотать его между двумя операциями чтения, однако нет никакой утилиты POSIX, которая могла бы выполнить эту перемотку ( lseek()
), поэтому вы не можете сделать это переносимо в сценариях POSIX ( zsh
( sysseek
встроенный) и ksh93
( <#((...))
оператор) могут сделай это хотя).
<()
=(...)
.
Вот несколько улучшенный ответ в строке 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
Мой рабочий процесс обычно с временными файлами из-за некоторого сценария bash, который я тестирую. Я хочу, чтобы tee
это было так, чтобы я мог видеть, что он работает, и сохранить результаты для следующей итерации моего процесса. Я создал файл с именемtmp
#!/bin/bash
echo $(mktemp /tmp/$(date +"%Y-%m-%d_%T_XXXXXX"))
так что я могу использовать его как
$ some_command --with --lots --of --stuff | tee $(tmp)
Причина, по которой мне нравится дата-время, отформатированное перед случайными значениями, заключается в том, что он позволяет мне легко найти файл tmp, который я только что создал, и мне не нужно думать о том, как назвать его в следующий раз (и сосредоточиться только на получении своего чертового скрипта работать).