Инициализация переменных Bash - требуется, рекомендуется или определяется по мере продвижения

9

Есть ли преимущество / недостаток инициализации значения переменной bash в скрипте, либо перед основным кодом, либо перед локальными переменными в функции перед присвоением ей фактического значения?

Мне нужно сделать что-то вроде этого:

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

init "Mark"

Есть ли риск того, что переменные будут инициализированы значениями мусора (если они не инициализированы) и это отрицательно скажется на значениях переменных?

Кир
источник
2
Откуда у вас эта идея?
6
@DoritoStyle Хорошо, если кто-то используется для языков более низкого уровня, таких как C, то это совершенно правильная вещь, о которой нужно беспокоиться.
Кусалананда
@ Kusalananda Разве C не эквивалентен этому коду name = ""; name = argv[1];? И разве это не так бессмысленно?
Джозеф Сибл-Восстановить Монику
1
@ JosephSible-ReinstateMonica Да. Код C, который вы разместили, не имеет смысла. Однако в C, в отличие от оболочки, неинициализированные переменные не имеют определенного четко определенного значения. Это означает, что инициализация переменных в таких языках, как C, имеет смысл при многих обстоятельствах. Делать так в оболочке не нужно. Как вы указали, инициализация переменной в C только для немедленной установки ее в другое значение не имеет смысла.
Кусалананда

Ответы:

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
Хотя нет значения для установки переменной на пустое значение, а затем немедленно устанавливать ее, как буквально делает OP, есть значение для установки пустого значения (или unsetting) перед запуском какого- forлибо whileцикла или цикла, чтобы установить его на вычисляемый значение, если есть вероятность того, что цикл фактически не запустится из-за невыполнения условия; и переменная могла быть установлена ​​в другое значение в среде, унаследованной сценарием. Но, возможно, лучше поместить все в a main()и определить переменные как local.
Монти Хардер
Вы также можете обнаружить неустановленные переменные, используя операторы расширения параметров, пропустив :, например,${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"
}

В этом примере это не имеет большого значения, но если вы имеете дело с большими и более сложными функциями, это может стать более болезненным.

wjandrea
источник
1
Вопрос не в том, чтобы объединить объявление и инициализацию. Речь шла о том, чтобы инициализировать с пустым значением, прежде чем назначить реальное значение.
Бармар
@ Barmar О, я только что посмотрел "инициализация". Я думал, что это было синонимом «декларация» ...
wjandrea