Ошибка при использовании пустых переменных оболочки

22

Иногда я использую, $PROJECT_HOME/*чтобы удалить все файлы в проекте. Когда переменная окружения PROJECT_HOMEне установлена ​​(потому что я сделал, suа у нового пользователя не установлена ​​эта переменная окружения), он начинает удалять все файлы из корневой папки. Это апокалипсис.

Как я могу настроить, bashчтобы выдавать ошибку, когда я использую неопределенную переменную среды в оболочке?

Сообщество
источник
5
set -uбудет делать то, что вы хотите.
Cuonglm
Вы можете сделать это как ответ?
2
Конечно, вы бы не инициализировали свои переменные для пустых строк. [ -z "$VAR" ]работает с неинициализированным VARтоже. Инициализация была просто для того, чтобы показать нежелательное поведение. Моя точка зрения заключается в том, что если ваши переменные когда-либо инициализируются пустыми строками, и вы rm -r "$PROJECT_HOME"/*ошибочно полагаетесь на них set -u, вы получите «апокалиптическое» поведение. IHMO, лучше быть в безопасности, чем сожалеть о защите всего содержимого вашего компьютера. set -uне безопасно
PSkocik
3
"Это очень долго"? Вам не следует искать удобный способ вручную выполнять опасные операции. Вместо этого вы должны создать функцию, псевдоним или скрипт, чтобы делать то, что вы хотите; в этом случае создание псевдонима из предложенной команды @ PSkocik будет и безопасным, и удобным.
Кайл Стрэнд,
1
Что делать, если пользователь устанавливает PROJECT_HOME=/etc? Просто проверка на пустое значение недостаточно для предотвращения катаклизма. Вы не должны использовать переменные от ненадежных пользователей при запуске от имени пользователя root.
Бармар

Ответы:

27

В оболочке POSIX вы можете использовать set -u :

#!/bin/sh

set -u
: "${UNSET_VAR}"

или используя расширение параметра :

: "${UNSET_VAR?Unset variable}"

В вашем случае вы должны использовать :?вместо того, ?чтобы также потерпеть неудачу на множественных, но пустых переменных:

rm -rf -- "${PROJECT_HOME:?PROJECT_HOME empty or unset}"/*
cuonglm
источник
17
[ -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"/* 

Полное удаление вашего проекта из дома и воссоздание его может быть другой вариант (если вы хотите избавиться и от dotfiles):

#no apocalyptic threats in this scenario
rm -r "$PROJECT_HOME"
mkdir "$_" 
PSkocik
источник
1
-z is ok, but since $PROJECT_HOME is supposed to be a directory, maybe -d would be better. [[ -d $PROJECT_HOME ]] && rm -r "$PROJECT_HOME".
kojiro
2
Если для PROJECT_HOME задано некаталог, это некатастрофическая ошибка, возможно, из-за опечатки. -dПроверка будет скрыть эту ошибку. Я думаю, что было бы лучше, если бы он продолжал rmи rmжаловался на это вслух.
PSkocik
2
Если установлен PROJECT_HOME, но имя не является каталогом, то [[ -d $PROJECT_HOME ]] && rm -r "$PROJECT_HOME"ничего не будет делать, молча. Но [[ -z $PROJECT_HOME ]] || rm -r "$PROJECT_HOME"молча удалит «$ PROJECT_HOME», даже если это файл, который не является каталогом. Получение сообщения об ошибке никогда не является проблемой:if [[ -d $PROJECT_HOME ]]; then rm -r "$PROJECT_HOME"; else printf '%s is not a directory\n' "$PROJECT_HOME" >&2; fi
Кодзиро
1
Теперь «случайно» установили PROJECT_HOME="/."...
Хаген фон Айцен
1
@HagenvonEitzen Если для PROJECT_HOME задано значение root, процедура, которая очищает PROJECT_HOME, очистит root. Это ожидаемое и совершенно разумное поведение. И вам даже не нужна эта последняя точка.
PSkocik
0

Еще один способ сделать это:

rm -r "${somevar:-/tmp/or_this_if_somevar_is_empty}"/*

Существует множество подстановок переменных, одна из которых выше, когда "somevar" пусто (и в этом случае он пытается удалить /tmp/or_this_if_somevar_is_empty/*)

Оливье Дюлак
источник
1
Или: rm -fr ${ENV_VAR:?suitably caustic message here}/*, но он все еще может быть стоит проверить , что значение не отображает в корневой каталог, отметив , что есть много способов , чтобы ниспровергать простых тестов: //, /.., /usr/who/../.., ...
Джонатан Леффлера
Да. Если вы собираетесь использовать расширение параметров, вы также можете использовать тот, который на самом деле выдает ошибку
Digital Trauma