- Вопрос или проблема
- Ответ или решение
- 1. Использование set -u
- 2. Расширение параметров
- 3. Проверка переменной перед выполнением команды
- Примеры использования
- Ситуация 1: Удаление неудачно
- Ситуация 2: Безопасная проверка
- 4. Полное удаление и создание директории
- 5. Альтернатива с использованием замены переменных
- Заключение
Вопрос или проблема
Иногда я использую $PROJECT_HOME/*
, чтобы удалить все файлы в проекте. Когда переменная окружения PROJECT_HOME
не установлена (потому что я сделал su
, и у нового пользователя эта переменная окружения не настроена), начинает удаляться все файлы из корневой папки. Это апокалиптично.
Как я могу настроить bash
, чтобы он выдавал ошибку, когда я использую неопределённую переменную окружения в оболочке?
В оболочке POSIX вы можете использовать set -u:
#!/bin/sh
set -u
: "${UNSET_VAR}"
или с использованием Расширения параметров:
: "${UNSET_VAR?Неопределенная переменная}"
В вашем случае вы должны использовать :?
вместо ?
, чтобы также выдавать ошибку для установленных, но пустых переменных:
rm -rf -- "${PROJECT_HOME:?PROJECT_HOME пустая или не установлена}"/*
[ -z "$PROJECT_HOME" ] || rm -r "$PROJECT_HOME"/*
Это также поймает случай, когда PROJECT_HOME
установлена, но ничего не содержит.
Пример:
1) Это удалит практически все, что вы можете удалить в своей системе (за исключением скрытых файлов в /
(обычно их нет)):
set -u
PROJECT_HOME=
rm -r "$PROJECT_HOME"/*
2) Это ничего не сделает:
PROJECT_HOME=
[ -z "$PROJECT_HOME" ] || rm -r "$PROJECT_HOME"/*
Полное удаление вашего домашнего каталога проекта и его воссоздание может быть другим вариантом (если вы хотите избавиться от скрытых файлов тоже):
#в этом сценарии нет апокалиптических угроз
rm -r "$PROJECT_HOME"
mkdir "$_"
Другой способ сделать это:
rm -r "${somevar:-/tmp/or_this_if_somevar_is_empty}"/*
Существует много замен переменных, приведённый выше случай, когда “somevar” пустой (в этом случае он пытается удалить /tmp/or_this_if_somevar_is_empty/*
).
Для справки, в ksh93 (оболочка, которую bash обычно пытается имитировать, хотя она ещё не скопировала типы, составные переменные или дисциплины), вы можете определить тип переменной, для которой попытка расширить её, когда она пуста, вызывает фатальную ошибку:
#! /bin/ksh93 -
progname=$0
typeset -T must_be_non_empty_upon_expansion=(
function get {
if [[ -z $_ ]]; then
print -ru2 -- "$progname: строка ${.sh.lineno}: ${.sh.name}: параметр пуст"
exit 1
fi
}
)
must_be_non_empty_upon_expansion foo bar
foo=non-empty
print -r "Хорошо: $foo"
bar=
print -r "Не хорошо: $bar"
$ ./that-script
Хорошо: non-empty
./that-script: строка 15: bar: параметр пуст
Ответ или решение
Использование пустых переменных окружения в скриптах Bash может привести к нежелательным последствиям, как, например, удаление файлов из корневой директории. Для предотвращения таких ситуаций, мы можем настроить оболочку так, чтобы она выдавала ошибку при использовании неустановленных или пустых переменных. В этой статье мы рассмотрим несколько методов, которые помогут вам избежать подобных апокалиптических сценариев.
1. Использование set -u
Вы можете использовать команду set -u
, которая заставляет оболочку выдавать ошибку при попытке обратиться к неустановленным переменным. Например:
#!/bin/sh
set -u
: "${UNSET_VAR}" # Это приведет к ошибке, если UNSET_VAR не установлена.
Таким образом, если вы попытаетесь обратиться к переменной, которую не установили, оболочка выдаст ошибку и не продолжит выполнение скрипта.
2. Расширение параметров
Вы можете использовать конструкцию с расширением параметров для генерации ошибки, если переменная не установлена или пуста. Это делается следующим образом:
rm -rf -- "${PROJECT_HOME:?PROJECT_HOME пустой или не установлен}"/*
В этом примере, если переменная PROJECT_HOME
не установлена или пуста, будет выдано сообщение об ошибке PROJECT_HOME пустой или не установлен
, и команда rm
не выполнится.
3. Проверка переменной перед выполнением команды
Вы также можете использовать конструкцию проверки, чтобы избежать выполнения команды в случае, если переменная пуста:
[ -z "$PROJECT_HOME" ] || rm -r "$PROJECT_HOME"/*
С помощью этого выражения, если PROJECT_HOME
не установлена или пуста, команда rm
не выполнится, что предотвратит случайное удаление файлов.
Примеры использования
Теперь рассмотрим несколько примеров:
Ситуация 1: Удаление неудачно
set -u
PROJECT_HOME=
rm -r "$PROJECT_HOME"/*
# Это приведет к удалению файлов из корневого каталога.
Ситуация 2: Безопасная проверка
PROJECT_HOME=
[ -z "$PROJECT_HOME" ] || rm -r "$PROJECT_HOME"/*
# Это просто ничего не сделает, если PROJECT_HOME пуст.
4. Полное удаление и создание директории
Если вам необходимо полностью удалить PROJECT_HOME
, и вы хотите избавиться от скрытых файлов, можно использовать следующее:
rm -r "$PROJECT_HOME"
mkdir "$PROJECT_HOME"
# Это без угроз апокалипсиса.
5. Альтернатива с использованием замены переменных
Также можно использовать замену переменных для задания альтернативного значения, когда переменная пуста:
rm -r "${somevar:-/tmp/or_this_if_somevar_is_empty}"/*
# Если somevar пуста, то произойдет удаление из альтернативного пути.
Заключение
Соблюдение осторожности при обращении к переменным окружения может предотвратить серьезные ошибки в ваших скриптах. Используйте set -u
, проверяйте наличие переменных, и всегда следите за тем, какие команды вы выполняете с потенциально опасными переменными. Эти простые, но эффективные методы позволят вам избежать нежелательных и разрушительных действий в вашем окружении.