Відповіді:
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
. Цей конкретний сигнал вбивства - це смерть, і нічого іншого не відбувається.
bash -c 'echo $$; trap "echo foo" 0; sleep 5'
EXIT
досить.
Якщо ви працюєте в системі, яка має mktemp , вам слід використовувати її як інші відповіді.
З інструментальним інструментом POSIX:
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 не була додана (в основному сумісна) утиліта. Просто сказати, що реально не можна сказати 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
( <#((...))
оператор) зробіть це, хоча).
<()
=(...)
.
Ось трохи покращена відповідь у рядку Хауке Лагінга:
#!/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, який я щойно створив, і мені не потрібно думати про те, як назвати його наступного разу (і зосередитися на тому, щоб просто отримати мій сценарій dang працювати).