Створення тимчасових файлів у bash


150

Чи є об'єктивно кращі способи створення тимчасових файлів у скриптах bash?

Я зазвичай просто називаю їх, що мені спадає на думку, наприклад, tempfile-123, оскільки він буде видалений, коли сценарій закінчиться. Чи є якийсь недолік у цьому, крім перезапису можливого tempfile-123 у поточну папку? Або є якась перевага у створенні тимчасового файлу більш ретельним способом?


1
Не використовуйте тимчасові файли. Використовуйте натомість тимчасові каталоги. І не використовуйте mktemp. Дивіться тут, чому: codeproject.com/Articles/15956/…
закінчення

17
@ceving Ця стаття просто неправильна, принаймні, якщо вона застосовується до команди оболонки mktemp (на відміну від виклику бібліотеки mktemp). Оскільки mktemp створює сам файл із обмежувальним umask, атака, що задається, працює лише в тому випадку, якщо зловмисник працює під тим самим обліковим записом, що і аттаке ... в цьому випадку гра вже втрачена. Про кращі практики у світі сценаріїв оболонок дивіться на mywiki.wooledge.org/BashFAQ/062
Чарльз Даффі

Ви також можете використовувати tempfile(1)в системах, у яких є.
Призупинено до подальшого повідомлення.

Відповіді:


179

Сторінка mktemp(1)man пояснює це досить добре:

Традиційно багато скриптів оболонки приймають назву програми разом із pid як суфікс і використовують це як тимчасове ім'я файлу. Така схема називання передбачувана, а перемогу, яку вона створює, легко виграти нападнику. Більш безпечний, хоч і все ще неповноцінний підхід - це зробити тимчасовий каталог, використовуючи ту ж саму схему іменування. Хоча це дозволяє гарантувати, що тимчасовий файл не буде перетворений, він все ще дозволяє просту атаку відмови в службі. З цих причин пропонується використовувати mktemp замість цього.

У сценарії я викликаю mktemp щось подібне

mydir=$(mktemp -d "${TMPDIR:-/tmp/}$(basename $0).XXXXXXXXXXXX")

який створює тимчасовий каталог, в якому я можу працювати, і в якому я можу сміливо називати фактичні файли чимось читабельним та корисним.

mktempне є стандартним, але він існує на багатьох платформах. "X" s, як правило, перетворюється на деяку випадковість, і більше, ймовірно, буде більш випадковим; однак деякі системи (попел для зайнятих ящиків для одного) обмежують цю випадковість значно більше, ніж інші


До речі, безпечне створення тимчасових файлів важливе для простого сценарію оболонок. Ось чому python має tempfile , perl має File :: Temp , ruby ​​має Tempfile тощо…


1
Параметр -t застарілий: gnu.org/software/coreutils/manual/html_node/…
Tibor Vass

7
Здається, найбезпечніший і кросплатформенний спосіб використання mktemp- це поєднання з basenameподібним чином mktemp -dt "$(basename $0). XXXXXXXXXX". Якщо використовується без basenameвас, можливо, ви отримаєте помилку на зразок цього mktemp: неправильний шаблон, `/tmp/MOB-SAN-JOB1-183-ScriptBuildTask-7300464891856663368.sh.XXXXXXXXXXX ', містить роздільник каталогів .
i4niac

7
Ігноруйте друкарські помилки (додатковий простір). mktemp -dt "$(basename $0).XXXXXXXXXX"це правильний шлях.
i4niac

3
@ i4niac: вам потрібно процитувати це $0, в землі ОС X є пробілиmktemp -dt "$(basename "$0").XXXXXX"
Орвелофіл

11
Також може бути приємно видалити tempdir в кінці виконання сценарію:trap "rm -rf $mydir" EXIT
KumZ

43

Так, використовуйте mktemp .

Він створить тимчасовий файл всередині папки, призначений для зберігання тимчасових файлів, і це гарантує вам унікальне ім’я. Він виводить ім'я цього файлу:

> mktemp
/tmp/tmp.xx4mM3ePQY
>

19

Можливо, ви захочете подивитися mktemp

Утиліта mktemp приймає заданий шаблон імені файлу і перезаписує його частину для створення унікального імені файлу. Шаблоном може бути будь-яке ім'я файлу з деякою кількістю доданих до нього "Xs", наприклад /tmp/tfile.XXXXXXXXXXX. Кінцеві "X" замінюються комбінацією поточного номера процесу та випадкових літер.

Детальніше: man mktemp


11

Чи є якась перевага у створенні тимчасового файлу більш ретельним способом

Тимчасові файли, як правило, створюються у тимчасовому каталозі (наприклад, /tmp), де всі інші користувачі та процеси мають доступ до читання та запису (будь-який інший скрипт може створити там нові файли). Тому сценарій повинен бути обережним щодо створення файлів, таких як використання з потрібними дозволами (наприклад, читати лише для власника, див. help umask), А ім'я файлу не слід легко здогадатися (в ідеалі випадково). Інакше, якщо назви файлів не є унікальними, це може створити конфлікт із тим самим сценарієм, який виконувався кілька разів (наприклад, умова перегонів) або якийсь зловмисник може або захопити якусь конфіденційну інформацію (наприклад, коли дозволи занадто відкриті і ім'я файлу легко здогадатися), або створити / замінити файл власною версією коду (наприклад, заміна команд або запитів SQL залежно від того, що відбувається зберігається).


Ви можете використовувати наступний підхід для створення тимчасового каталогу:

TMPDIR=".${0##*/}-$$" && mkdir -v "$TMPDIR"

або тимчасовий файл:

TMPFILE=".${0##*/}-$$" && touch "$TMPFILE"

Однак це все ще передбачувано і не вважається безпечним.

Відповідно man mktemp, ми можемо читати:

Традиційно багато скриптів оболонки приймають назву програми разом із pid як суфікс і використовують це як тимчасове ім'я файлу. Така схема називання передбачувана, а перемогу, яку вона створює, легко виграти нападнику.

Щоб бути безпечним, рекомендується використовувати mktempкоманду для створення унікального тимчасового файлу чи каталогу ( -d).


2
не зовсім те, що просили. Однак це може бути ідеальним рішенням.
jpbochi

1
@jpbochi Я вдосконалив відповідь на вирішення питання. Дайте мені знати, якщо це допомагає.
kenorb

2
Це дійсно покращує відповідь. Хоча моя заява вже була вашою. Не можете більше голосувати. Одним із пропозицій я є пояснити, що ${0##*/}і $$розгорнути, або посилання на якусь документацію про це.
jpbochi

0

mktemp є, мабуть, найбільш універсальним, особливо якщо ви плануєте працювати з файлом деякий час.

Ви також можете використовувати оператор підстановки процесу, <() якщо файл вам потрібен лише тимчасово як вхід до іншої команди, наприклад:

$ diff <(echo hello world) <(echo foo bar)
Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.