Присвоение значения переменной в BASH

Вчера столкнулся с неожиданным (мной) поведением при присвоении значений переменным в BASH скрипте. Вот набросал пример, который воспроизводит проблему:

    #!/bin/bash
    
    function sep {
            echo '------------------'
    }
    #блок 1
    var1=`echo 1 ; echo 2 ; echo 3`
    echo '1. var1=`echo 1 ; echo 2 ; echo 3`'
    sep
    echo '${var1}'
    echo "${var1}"
    sep
    echo '${var1[*]}'
    echo "${var1[*]}"
    sep
    echo '${var1[@]}'
    echo "${var1[@]}"
    sep

    #блок 2    
    var1=()
    var1+=( "A" )
    var1+=( "B" )
    var1+=( "C" )
    echo '2. var1=() ....'
    sep
    echo '${var1}'
    echo "${var1}"
    sep
    echo '${var1[*]}'
    echo "${var1[*]}"
    sep
    echo '${var1[@]}'
    echo "${var1[@]}"
    sep
    
    #блок 3
    var1=`echo 1 ; echo 2 ; echo 3`
    echo '3. var1=`echo 1 ; echo 2 ; echo 3`'
    sep
    echo '${var1}'
    echo "${var1}"
    sep
    echo '${var1[*]}'
    echo "${var1[*]}"
    sep
    echo '${var1[@]}'
    echo "${var1[@]}"
    sep
    
    
    exit 0

Я ожидал что результат в третьем блоке будет как и в первом, но был удивлен - он отличается от первого и второго - вылезает хвост. Вот выхлоп

1. var1=`echo 1 ; echo 2 ; echo 3`
------------------
${var1}
1
2
3
------------------
${var1[*]}
1
2
3
------------------
${var1[@]}
1
2
3
------------------
2. var1=() ....
------------------
${var1}
A
------------------
${var1[*]}
A B C
------------------
${var1[@]}
A B C
------------------
3. var1=`echo 1 ; echo 2 ; echo 3`
------------------
${var1}
1
2
3
------------------
${var1[*]}
1
2
3 B C
------------------
${var1[@]}
1
2
3 B C
------------------

Я был уверен что второй var1=echo 1 ; echo 2 ; echo 3 перезапишет старое значение переменной полностью, а оказалось что нет. Не смог сформулировать запрос к гуглу чтоб найти описание такого поведения. Как правильно присваивать значение чтоб оно "затирало" предыдущее?


Ответы (1 шт):

Автор решения: Alexey Ten

У переменных в bash есть атрибуты. Они описаны в help declare (ну или в справке) и их можно посмотреть командой declare -p ПЕРЕМЕННАЯ.

Когда вы написали var1=() вы неявно задали переменной атрибут -a (array).

$ var1=()
$ declare -p var1
declare -a var1=()

Дальнейшая попытка написать var1=строка на самом деле изменяет первый элемент массива, что вы и наблюдаете в своём эксперименте.

Сделать переменную не массивом можно только полностью её удалив.

# попробуем убрать атрибут `array`
$ declare +a var1
bash: declare: var1: cannot destroy array variables in this way
# удаляем переменную
$ unset var1
# создаём заново
$ var1=string
$ declare -p var1
declare -- var1="string"
# теперь у неё нет никаких атрибутов

UPD: Документация https://www.gnu.org/software/bash/manual/html_node/Arrays.html

→ Ссылка