Тестовые операторы файлов в Linux — проверка с помощью -e, -s, -d, -h, -r, -O

Введение
Тестовые операторы файлов в оболочке Bash и POSIX-совместимых shell используются для принятия решений в скриптах: существует ли файл, пуст ли он, является ли он директорией или символической ссылкой, доступен ли он для чтения и принадлежит ли текущему пользователю. Правильное использование операторов делает скрипты надежными и безопасными.
Кратко о терминах:
- Тестовый оператор — выражение вида [ -e path ] или [[ -e path ]], возвращающее успешный код выхода (0) при выполнении условия.
- Символическая ссылка — файл, содержащий путь на другой файл.
Важно: в большинстве реализаций -h и -L эквивалентны (проверяют символическую ссылку). Некоторые встроенные реализации могут незначительно отличаться, поэтому тестируйте в вашей среде.
Какие операторы мы рассмотрим
- -e — файл существует
- -s — файл существует и не пустой
- -d — путь — директория
- -h — путь — символическая ссылка (альтернатива: -L)
- -r — файл читаем текущим пользователем (euid)
- -O — файл принадлежит текущему пользователю (euid)
Общая методика: как организовать проверку в скрипте
Мини-методология:
- Валидация входных параметров (проверить, что переменная с путём непуста).
- Использовать кавычки вокруг переменных: “$file”.
- Использовать явные условия с понятным сообщением об ошибке.
- Логировать причины отказа (exit code ≠ 0) и при необходимости выдавать рекомендации.
Простой шаблон:
#!/usr/bin/env bash
file="$1"
if [ -z "$file" ]; then
echo "Укажите путь к файлу" >&2
exit 2
fi
if [ -e "$file" ]; then
echo "$file найден"
else
echo "$file не найден" >&2
exit 1
fiПодробные примеры и объяснения
1) Проверка существования: -e
Назначение: убедиться, что путь существует (файл, директория или ссылка).
Пример:
file="Test.txt"
if [ -e "$file" ]; then
echo "True: $file существует"
else
echo "False: $file не найден"
fiЗапуск:
$ touch Test.txt
$ bash FileTestOperators.sh
Заметки:
- -e не различает тип: директория, обычный файл или ссылка — лишь проверяет существование.
- Для POSIX-строгих скриптов используйте single-bracket [ … ] или команду test.
2) Проверка непустоты: -s
Назначение: файл существует и имеет размер > 0 байт.
Пример:
file="Test.txt"
if [ -s "$file" ]; then
echo "True: $file не пустой"
else
echo "False: $file пустой или не существует"
fiЕсли файл пуст — оператор вернёт False. Добавление текста в файл изменит результат на True.

Дополнительная проверка содержимого:
cat Test.txt
file Test.txt3) Проверка директории: -d
Назначение: проверить, что путь указывает на директорию.
Пример:
file="Test.txt"
if [ -d "$file" ]; then
echo "True: $file — директория"
else
echo "False: $file не является директорией"
fiЕсли путь — обычный файл, результат будет False.

4) Проверка символической ссылки: -h (или -L)
Назначение: проверить, является ли путь символической ссылкой.
Создание примера:
touch SymbolicFile.sh
ln -s SymbolicFile.sh NewSymbolicFile.sh
file="NewSymbolicFile.sh"
if [ -h "$file" ]; then
echo "True: $file — символическая ссылка"
else
echo "False: $file не ссылка"
fiКоманда ls -l покажет стрелку к целевому файлу.




Примечание: -h и -L эквивалентны в большинстве реализаций test. Если хотите проверить файл, на который указывает ссылка, используйте проверку самого целевого пути.
5) Проверка на читаемость: -r
Назначение: проверить, может ли текущий процесс прочитать файл (основываясь на effective UID/GID и ACL).
Пример:
file="Test.txt"
if [ -r "$file" ]; then
echo "True: $file читаем"
else
echo "False: $file нечитаем или не существует"
fi
Важно: для записи и выполнения используйте -w и -x соответственно.
6) Проверка владельца: -O
Назначение: убедиться, что файл принадлежит текущему пользователю (effective UID).
Пример:
file="Test.txt"
if [ -O "$file" ]; then
echo "True: $file принадлежит текущему пользователю"
else
echo "False: $file принадлежит другому пользователю"
fi
Замечание: -O сравнивает владельца с effective UID процесса. Если скрипт запускается sudo, результат может отличаться.
Частые ошибки и когда проверки дают неожиданный результат
- Забытые кавычки: [ -e $file ] при пути с пробелами разобьёт аргумент.
- Различие real vs effective ID: операции с sudo могут менять результат -O, -r, -w.
- -e вернёт True и для симлинка, даже если цель удалена (если сама ссылка существует).
- Проверка прав через тест не учитывает SELinux/прочие расширенные политики.
Важно: тестовые операторы оценивают состояние на момент выполнения. Между проверкой и использованием файла возможна гонка (TOCTOU). Для критичных операций используйте атомарные системные вызовы.
Чек-лист для разработчика/администратора
- Проверить входной параметр и экранировать его.
- Использовать кавычки вокруг переменных.
- Логировать причину отказа и код выхода.
- При необходимости использовать mkdir -p или touch с проверкой ошибок.
- Для операций с правами понимать влияние sudo/euid.
Быстрая шпаргалка (cheat sheet)
- [ -e FILE ] — существует (файл/директория/ссылка)
- [ -s FILE ] — существует и размер > 0
- [ -d FILE ] — это директория
- [ -h FILE ] — это символическая ссылка (синоним: -L)
- [ -r FILE ] — читаемо текущим пользователем
- [ -w FILE ] — доступно для записи
- [ -x FILE ] — исполняемо
- [ -O FILE ] — владелец — текущий пользователь
Роль-ориентированные контрольные пункты
Для разработчика:
- Добавить проверки наличия файла перед чтением.
- Обрабатывать ошибочные коды и выводить понятные сообщения.
Для системного администратора:
- Проверять владельца и права перед запуском автоматизированных задач.
- Учитывать влияние sudo и cron (разные euid/egid).
Для DevOps/CI:
- Использовать тесты в pipeline перед деплоем (наличие конфигов, отсутствие пустых файлов, корректные права).
Сценарий инцидента: файл конфигурации отсутствует
Runbook (быстрые шаги):
- Проверить существование: [ -e /etc/myapp/conf.json ]
- Если отсутствует — проверить историю изменений (git, backup).
- Восстановить из резервной копии или создать шаблон конфигурации.
- Проверить права доступа: владельцем должен быть сервисный пользователь; права 640/600 в зависимости от требований.
- Перезапустить сервис и проверить логи.
Критерии приёмки:
- Файл существует и не пустой
- Владелец и права соответствуют политике
- Сервис успешно стартует
Тест-кейсы для валидации скриптов
- Путь пустой -> скрипт возвращает код 2 и понятное сообщение.
- Файл не существует -> код 1 и сообщение об отсутствии.
- Файл существует и пуст -> -s даёт False, -e даёт True.
- Файл — символическая ссылка -> -h True, -e True.
- Файл принадлежит другому пользователю -> -O False.
- Запуск через sudo -> поведение -O может измениться.
Руководство по безопасности и приватности
- Никогда не логируйте содержимое конфиденциальных файлов.
- При автоматическом создании файлов задавайте минимально необходимые права (умолчание 600/640).
- Учтите SELinux/AppArmor: тестовые операторы не отражают дополнительных политик безопасности.
Примеры продвинутых шаблонов
Атомарная обработка с временной блокировкой (примитивный подход для избежания гонок):
file="/var/lib/myapp/state"
lockdir="${file}.lock"
if mkdir "$lockdir" 2>/dev/null; then
trap 'rmdir "$lockdir"' EXIT
# безопасно читать/писать файл
if [ -e "$file" ]; then
# работа с файлом
:
fi
else
echo "Не удалось получить блокировку, другой процесс работает" >&2
exit 3
fiМероприятие для выбора действия (decision tree)
flowchart TD
A[Есть путь?] -->|нет| B[Ошибка: укажите путь]
A -->|да| C{Существует?}
C -->|нет| D[Создать/восстановить]
C -->|да| E{Это директория?}
E -->|да| F[Операции с директориями]
E -->|нет| G{Симлинк?}
G -->|да| H[Проверить цель ссылки]
G -->|нет| I{Пустой?}
I -->|да| J[Содержимое отсутствует — заполнить/ошибка]
I -->|нет| K[Проверки прав и владельца]
K -->|OK| L[Продолжить]
K -->|не OK| M[Исправить права/владельца]Короткая галерея крайних случаев
- Файл существует, но цель симлинка удалена: -e вернёт True для ссылки, но доступ к содержимому приведёт к ошибке.
- Файл читаем, но SELinux запрещает доступ — тест -r вернёт True, а реальный доступ может быть заблокирован.
- Скрипт запускается cron’ом от другого пользователя — права и владельцы влияют на поведение.
1‑строчный глоссарий
- test/[] — встроенный тест в shell; возвращает код выхода 0 при истинности.
- euid — effective UID процесса, влияет на проверку -r/-w/-O.
- TOCTOU — time-of-check to time-of-use, гонка между проверкой и использованием.
Заключение
Тестовые операторы файлов — базовый и мощный инструмент для написания надёжных shell-скриптов. Простые проверки (-e, -s, -d, -h, -r, -O) позволяют избегать ошибок и защищают от типичных проблем: отсутствия файлов, неправильных прав и неожиданного типа объекта. Соблюдайте практики безопасности, используйте кавычки и логирование, и ваши сценарии будут предсказуемо работать в разных средах.
Важно: всегда тестируйте скрипты в целевой среде, особенно если используются sudo, cron или контейнеры.
Похожие материалы
Несколько аккаунтов Skype: Multi Skype Launcher
Журнал для работы: повысить продуктивность
Персональные звуки уведомлений на Android
Скачивание шоу Hulu для офлайн‑просмотра
Microsoft Start: персонализированная новостная лента