Помилка при використанні порожніх змінних оболонок


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}"/*

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"/* 

Повністю видалити проект додому та відтворити його, можливо, буде ще один варіант (якщо ви теж хочете позбутися від точкових файлів):

#no apocalyptic threats in this scenario
rm -r "$PROJECT_HOME"
mkdir "$_" 

1
-zце нормально, але оскільки $PROJECT_HOMEпередбачається, що це каталог, можливо, -dбуло б краще. [[ -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
kojiro

1
Тепер "випадково" встановили PROJECT_HOME="/."...
Хаген фон Ейтцен

1
@HagenvonEitzen Якщо для PROJECT_HOME встановлено корінь, процедура, що спорожняє PROJECT_HOME, видалить корінь. Очікувана та цілком розумна поведінка. І вам навіть не потрібна ця остання крапка.
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
Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.