Создание файлов и директорий
В прошлых модулях мы научились ориентироваться в файловой системе. Теперь — создавать в ней файлы и папки. На первый взгляд тривиально, но есть нюансы: mkdir -p, touch с правильным mtime, mktemp для безопасных временных файлов. Это рутинные операции DE, которые лучше делать правильно с самого начала.
mkdir: создание директорий
Базовое использование:
$ mkdir new-folder
$ ls
new-folder/
# Ошибка, если уже существует
$ mkdir new-folder
mkdir: cannot create directory 'new-folder': File exists
Опции:
mkdir -p — это самая используемая опция:
$ mkdir -p ~/projects/airflow/dags/etl
# Создаст все 4 уровня: projects, airflow, dags, etl
# Если что-то уже есть — не ошибётся
$ mkdir -p ~/projects/airflow/dags/etl
# (молча: всё уже существует)
Без -p пришлось бы делать:
$ mkdir ~/projects
$ mkdir ~/projects/airflow
$ mkdir ~/projects/airflow/dags
$ mkdir ~/projects/airflow/dags/etl
В скриптах всегда используйте -p. Это idempotent — можно запускать N раз, состояние одно.
С правами при создании:
$ mkdir -m 0700 ~/.ssh
# Создаст с правами 0700 (только владелец может)
$ mkdir -m 0755 -p /var/data/raw/2026
# Стандартные права для общедоступных папок
Подробнее про права (0700, 0755 и так далее) — в модуле 6.
touch: пустые файлы и mtime
touch имеет два применения:
- Создать пустой файл (если не существует).
- Обновить modification time существующего файла на текущее.
# Создать пустой файл
$ touch newfile.txt
$ ls -la newfile.txt
-rw-r--r-- 1 user user 0 May 13 14:00 newfile.txt
# Размер 0, mtime = сейчас
# Обновить mtime уже существующего
$ ls -l existing.txt
-rw-r--r-- 1 user user 1024 May 10 10:00 existing.txt
$ touch existing.txt
$ ls -l existing.txt
-rw-r--r-- 1 user user 1024 May 13 14:00 existing.txt
# Размер тот же, mtime теперь сейчас
Опции touch:
# Установить конкретное время
$ touch -t 202605131200 file.txt # 2026-05-13 12:00
$ touch -d "2026-01-01 00:00" file.txt
$ touch -d "yesterday" file.txt
$ touch -d "2 hours ago" file.txt
# Не создавать новый, только обновить (если существует)
$ touch -c file.txt
# Установить только atime / только mtime
$ touch -a file.txt # только access time
$ touch -m file.txt # только modification time
В DE-практике touch используется:
- Создать marker-файлы:
touch /var/lock/etl.lock— для логики «уже запущен». - Обновить mtime для cache invalidation: некоторые инструменты пересчитывают, если mtime изменился.
- Создать пустые placeholder-файлы.
# Marker-файл для уведомления о завершении ETL
$ touch /var/data/2026-05-13/_SUCCESS
# Многие big data tools используют такой паттерн
mktemp: безопасные временные файлы
В скриптах часто нужны временные файлы. Простое решение «использовать /tmp/myfile.txt» имеет проблемы:
- Race condition: два скрипта могут создать одно имя одновременно.
- Безопасность: предсказуемое имя позволяет attacks (symlink attack).
- Чистка: легко забыть удалить.
Правильное решение — mktemp:
$ mktemp
/tmp/tmp.XJZ9aB2c4q
# Создал файл с уникальным именем, вернул путь
# С префиксом и шаблоном
$ mktemp /tmp/etl-XXXXXX.csv
/tmp/etl-aZ9bX1.csv
# XXXXXX заменяется на 6 случайных символов
# Создать директорию вместо файла
$ mktemp -d
/tmp/tmp.XJZ9aB2c4q
В скриптах паттерн такой:
#!/usr/bin/env bash
set -euo pipefail
TMPDIR=$(mktemp -d /tmp/myapp.XXXXXX)
trap "rm -rf $TMPDIR" EXIT # автоудаление при выходе
# Работаем в TMPDIR
curl https://api.example.com/data > "$TMPDIR/raw.json"
jq '.data[]' "$TMPDIR/raw.json" > "$TMPDIR/processed.json"
mv "$TMPDIR/processed.json" /var/data/result.json
# При exit (любом — успех, ошибка, Ctrl-C) trap чистит
Подробнее про trap и cleanup-паттерны — в модуле 18.
Никогда не используйте предсказуемые имена в /tmp. /tmp/my-script-output.txt — это уязвимость. Атакующий может заранее создать symlink /tmp/my-script-output.txt -> /etc/passwd, и ваш скрипт перезапишет /etc/passwd. Всегда mktemp.
Куда mktemp кладёт файлы
По умолчанию mktemp использует:
- Переменную
$TMPDIR, если установлена. /tmp, если$TMPDIRне установлена.
$ export TMPDIR=~/my-temp
$ mkdir -p ~/my-temp
$ mktemp
/home/user/my-temp/tmp.aB9X1c2d3e
Это полезно, когда:
- Скрипт обрабатывает большие файлы, и
/tmpслишком маленький (tmpfs в RAM, ~7GB). - Хочется хранить tmp на отдельном диске.
# Явный путь для большого временного файла
$ TMP_BIG=$(mktemp /data/scratch/etl-XXXXXX.csv)
Команды для типичных задач
Создание daily-папок в data lake:
$ today=$(date +%Y-%m-%d)
$ mkdir -p /var/data/raw/"$today"/
$ mkdir -p /var/data/processed/"$today"/
$ mkdir -p /var/data/archived/"$today"/
Подготовка структуры нового проекта:
$ mkdir -p new-project/{src,tests,docs,data,scripts}
$ touch new-project/{README.md,.gitignore,requirements.txt}
$ ls new-project
data/ docs/ README.md requirements.txt scripts/ src/ tests/ .gitignore
Заметьте brace expansion {src,tests,docs} — bash раскрывает в несколько аргументов. Это работает с mkdir, touch, cp и любой командой.
Создание временной копии в pipeline:
$ TMP=$(mktemp -d)
$ cp -r /var/data/important "$TMP/working-copy"
$ # делаем что-то с копией
$ rm -rf "$TMP"
Brace expansion: создание массивами
Bash brace expansion — это мощный синтаксис для создания нескольких имён одной командой:
# Несколько папок
$ mkdir -p project/{src,tests,docs}
# Создаёт project/src, project/tests, project/docs
# Нумерованные
$ mkdir batch-{01..10}
$ ls
batch-01/ batch-02/ ... batch-10/
# Декартово произведение
$ mkdir {dev,staging,prod}-{api,db,cache}
$ ls
dev-api/ dev-cache/ dev-db/ staging-api/ staging-cache/ ...
# Touch с разными расширениями
$ touch report.{csv,json,yaml,md}
$ ls
report.csv report.json report.md report.yaml
# Числовая последовательность
$ touch day-{2026-05-{01..31}}.csv
# day-2026-05-01.csv ... day-2026-05-31.csv
Это типично для DE: создание daily-партиций, серий тестовых файлов, структуры окружений.
Создание файлов через перенаправление
Альтернатива touch — записать пустоту в файл через >:
$ : > newfile.txt
# Или
$ > newfile.txt
$ echo -n > newfile.txt
Все три создают пустой файл (или очищают существующий). Подробнее про перенаправления — в модуле 9.
Для создания файла с содержимым:
# Heredoc — многострочный текст
$ cat > config.yaml <<'EOF'
database:
host: localhost
port: 5432
EOF
$ cat config.yaml
database:
host: localhost
port: 5432
Heredoc (<<'EOF') — это шаблон создания файла в скриптах. Подробнее в модуле 9.
Попробуй сам
$ mkdir -p ~/linux-sandbox/lesson-create
$ cd ~/linux-sandbox/lesson-create
# Базовое создание
$ mkdir simple-dir
$ touch simple-file.txt
# Brace expansion — структура нового DE-проекта
$ mkdir -p new-etl/{src/{api,db,utils},tests/{unit,integration},docs,scripts}
$ tree new-etl
new-etl
├── docs
├── scripts
├── src
│ ├── api
│ ├── db
│ └── utils
└── tests
├── integration
└── unit
# Daily-партиции
$ mkdir -p data/raw/2026-05-{01..31}
$ ls data/raw | head -5
2026-05-01 2026-05-02 2026-05-03 2026-05-04 2026-05-05
# mktemp
$ TMP=$(mktemp -d)
$ echo "$TMP"
/tmp/tmp.aB9X1c2d3e
$ echo "test data" > "$TMP/data.txt"
$ ls "$TMP"
data.txt
# Удалить после использования
$ rm -rf "$TMP"
Heredoc для создания конфига:
$ cat > config.yaml <<'EOF'
service:
name: etl-pipeline
version: 1.0.0
schedule:
cron: "0 */6 * * *"
EOF
$ cat config.yaml
service:
name: etl-pipeline
version: 1.0.0
schedule:
cron: "0 */6 * * *"