Ініціалізація змінних Bash - це потрібно, рекомендується чи визначати під час руху


9

Чи є якась перевага / недолік ініціалізації значення bash змінної в скрипті перед основним кодом або локальними змінними у функції перед призначенням її фактичного значення?

Чи потрібно мені робити щось подібне:

init()
{
    name=""
    name=$1
}

init "Mark"

Чи є ризик ініціалізації змінних зі значеннями сміття (якщо вони не ініціалізовані) та негативних наслідків значень змінних?


2
Звідки ви взяли цю ідею?

6
@DoritoStyle Ну, якщо один використовується для мов нижчого рівня, таких як C, то це цілком дійсна річ, про яку слід турбуватися.
Kusalananda

@Kusalananda Чи не еквівалент С цього коду name = ""; name = argv[1];? І чи не так це безглуздо?
Джозеф Сибл-Відновити Моніку

1
@ JosephSible-ReinstateMonica Так. Код С, який ви опублікували, є безглуздим. Однак у C, на відміну від оболонки, неініціалізовані змінні не мають особливого чітко визначеного значення. Це означає, що ініціалізація змінних у таких мовах, як C, має сенс за багатьох обставин. Робити це в оболонці не потрібно. Як ви вказуєте, ініціалізувати змінну в C лише для негайного встановлення її іншого значення - безглуздо.
Kusalananda

Відповіді:


22

Немає користі, якщо призначити порожній рядок змінній, а потім негайно призначити їй інший рядок змінної. Присвоєння значення змінній оболонки повністю замінить її попереднє значення.

Наскільки мені відомо, жодна рекомендація не говорить про те, що слід явно ініціалізувати змінні в порожні рядки. Фактично, це може замаскувати помилки за певних обставин (помилки, які в іншому випадку були б очевидні при запуску set -u, див. Нижче).

Змінна, що не використовується, яка не використовується з моменту запуску скрипту або явно знімається, виконуючи unsetкоманду на ній, не матиме значення. Значення такої змінної буде нічого. Якщо використовується як "$myvariable", ви отримаєте еквівалент "", і ви ніколи не отримаєте "дані про сміття".

Якщо параметр оболонки nounsetвстановлений з або, set -o nounsetабо set -uпосилання на незбуту змінну призведе до помилки (і неінтерактивна оболонка припиниться):

$ set -u
$ echo "$myvariable"
/bin/sh: myvariable: parameter not set

або, у bash:

$ set -u
$ echo "$myvariable"
bash: myvariable: unbound variable

Змінні оболонки будуть ініціалізовані середовищем, якщо ім'я змінної відповідає існуючій змінній оточення.

Якщо ви очікуєте, що ви використовуєте змінну, яка може бути ініціалізована середовищем таким чином (і якщо вона небажана), ви можете явно скасувати її перед основною частиною сценарію:

unset myvariable    # unset so that it doesn't inherit a value from the environment

який також видалить його як змінну середовища, або, ви можете просто проігнорувати його початкове значення та просто перезаписати його з призначенням (що також призведе до зміни значення змінної середовища).

Ви ніколи не зіткнетеся з неініціалізованим сміттям у змінній оболонки (якщо, як зазначалося, цей сміття вже існував у змінній середовища з однойменною назвою).


3
Хоча немає значення встановити змінну на порожнє значення, а потім негайно встановити її так, як ОП буквально робить, є значення у встановленні порожнього значення (або unsetting) перед запуском якогось forабо whileциклу, щоб встановити його на обчислене значення, якщо є ймовірність, що цикл насправді не запуститься через невиконання умови; і змінна, можливо, була встановлена ​​на якесь інше значення в середовищі, яке сценарій успадкував. Але, можливо, краще поставити все в a main()і визначити змінні як local.
Monty Harder

Ви також можете виявити незмінені змінні за допомогою операторів розширення параметрів, опустивши :, наприклад,${myvariable-defaultvalue}
Barmar

3

Правка : На жаль, декларація відрізняється від ініціалізації. Я все одно залишу це тут, щоб початківці кодери, як я, могли навчитися на своїй помилці.


Перевага оголошення локальних змінних у функції полягає в тому, що ви можете легко скопіювати код.

Наприклад, скажіть, у мене є функція:

foo(){
    local name
    name="$1"
    echo "$name"
}

Якщо я хочу перетворити його на сценарій, я просто ігнорую localзаяву і копіюю все інше:

#!/bin/bash
name="$1"
echo "$name"

Якщо декларація та призначення були в одному рядку, я повинен був би вручну відредагувати localчастину, перш ніж я міг перетворити її в сценарій:

foo(){
    local name="$1"
    echo "$name"
}

У цьому прикладі це не велика справа, але якщо ви маєте справу з більшими, складнішими функціями, це може набути більш болісних відчуттів.


1
Питання полягало не в поєднанні декларації та ініціалізації. Йшлося про те, чи ініціалізувати з порожнім значенням перед призначенням реального значення.
Бармар

@Barmar О, я просто шукав "ініціалізацію". Я думав, що це синонім "декларації" ...
wjandrea
Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.