Використання unset vs. встановлення змінної до порожньої


108

В даний час я пишу рамку тестування bash, де в тестовій функції можуть використовуватися як стандартні баш-тести ( [[), так і попередньо визначені відповідники. Матчі є обгортками до '[[', і крім повернення коду повернення, встановіть якесь змістовне повідомлення, в якому йдеться про те, що очікувалося.

Приклад:

string_equals() {
    if [[ ! $1 = $2 ]]; then
            error_message="Expected '$1' to be '$2'."

            return 1
    fi
}

Отже, коли використовується Matcher, і він виходить з ладу, лише тоді встановлюється повідомлення про помилку.

Тепер, у якийсь момент пізніше, я перевіряю, чи вдалися тести. Якщо це вдалося, я роздруковую очікування зеленим кольором, якщо воно не вдалося червоним кольором.

Крім того, може бути набір повідомлень про помилку, тому я перевіряю, чи існує повідомлення, надрукуйте його та скасуйте його (оскільки наступний тест може не встановити error_message):

if [[ $error_message ]]; then
    printf '%s\n' "$error_message"

    unset -v error_message
fi

Тепер моє запитання полягає в тому, якщо краще змінити змінну або просто встановити її на "", як

error_message=''

Який з них кращий? Чи насправді це має значення? Чи, можливо, у мене повинен бути додатковий прапор із зазначенням, що повідомлення було встановлено?


1
Якщо ви ніколи не порівнюєте error_messageні з чим іншим, я б сказав, що це не має значення. Однак я думаю, що ти хочеш [[ $error_message ]], інакше ти перевіряєш, що існує буквальний рядок "error_message".
чепнер

@chepner Так, був друкарський помилок. Виправлено це.
helpermethod

Відповіді:


143

Переважно ви не бачите різниці, якщо не використовуєте set -u :

/home/user1> var=""
/home/user1> echo $var

/home/user1> set -u
/home/user1> echo $var

/home/user1> unset var
/home/user1> echo $var
-bash: var: unbound variable

Тож справді, це залежить від того, як ви збираєтеся перевірити змінну.

Я додам, що мій кращий спосіб тестування, якщо він встановлений:

[[ -n $var ]]  # True if the length of $var is non-zero

або

[[ -z $var ]]  # True if zero length

43
var=не "не встановлено". Це просто порожня рядок без котирування. Крім того set -u, різні форми розширення параметрів bash також можуть розрізняти значення unset та null: ${foo:bar}розширюється на "bar", коли fooне встановлено, але "" - коли foonull, а ${foo:-bar}розширюється на "bar", якщо foo не встановлено або null.
чепнер

1
[[ -n $var ]]false, якщо varвстановлено порожній рядок.
чепнер

1
якщо ви використовуєте "оголосити -p" для перевірки змінної "існування", то var = покаже "заявити - var =" "", ви повинні використовувати unset, щоб позбутися від неї, звичайно, якщо її змінна для читання, то ви не можете отримати позбутися цього, звичайно. Крім того, якщо ви вар = щось усередині функції, вам не доведеться турбуватися про позбавлення від неї, якщо ви використовуєте "локальний var = значення", будьте обережні, оскільки "оголосити var = значення" також є локальним. У разі оголошення ви повинні явно встановити його глобальним, використовуючи "оголосити -g var = значення", без декларування вам потрібно явно встановити його як місцеве, використовуючи "локальний".
osirisgothra

@osirisgothra: хороший момент щодо локальних змінних. Звичайно, найкраще оголосити (або локалізувати) всі змінні у функції, щоб вона була інкапсульована.
cdarke

3
@chepner має бути ${foo-bar}замість ${foo:bar}. тест для себе:unset a; echo ">${a:-foo}-${a:foo}-${a-foo}<"
Liviu Chircu

17

Як було сказано, використання масиву unset відрізняється і від масивів

$ foo=(4 5 6)

$ foo[2]=

$ echo ${#foo[*]}
3

$ unset foo[2]

$ echo ${#foo[*]}
2

2

Отже, скасувавши індекс 2 масиву, ви по суті видалите цей елемент у масиві та зменшите розмір масиву (?).

Я зробив власний тест ..

foo=(5 6 8)
echo ${#foo[*]}
unset foo
echo ${#foo[*]}

Що призводить до ..

3
0

Тому просто для уточнення того, що невстановлення всього масиву насправді видалить його повністю.


0

На основі коментарів, наведених вище, ось простий тест:

isunset() { [[ "${!1}" != 'x' ]] && [[ "${!1-x}" == 'x' ]] && echo 1; }
isset()   { [ -z "$(isunset "$1")" ] && echo 1; }

Приклад:

$ unset foo; [[ $(isunset foo) ]] && echo "It's unset" || echo "It's set"
It's unset
$ foo=     ; [[ $(isunset foo) ]] && echo "It's unset" || echo "It's set"
It's set
$ foo=bar  ; [[ $(isunset foo) ]] && echo "It's unset" || echo "It's set"
It's set
Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.