Получение неправильного значения переданного аргумента для функции в скрипте bash

#bash #shell #for-loop

#bash #оболочка #for-цикл

Вопрос:

Я пишу скрипт bash, приведенный ниже (пожалуйста, игнорируйте имена переменных с заглавными буквами, это всего лишь мой тестовый файл):

 #!/bin/bash

create_nodes_directories(){
HOSTS=(192.168.110.165 192.168.110.166 192.168.110.167)
accounts=('accountnum11' 'accountnum12' 'accountnum13')
for i in "${!HOSTS[@]}"; do
        read -r curhost _ < <(hostname -I)
        printf 'Enter the key pair for the %s noden' "${accounts[i]}"
        printf "Enter public keyn"
        read -r EOS_PUB_KEY
        printf "Enter private keyn"
        read -r EOS_PRIV_KEY
        PRODUCER=${accounts[i]}

        args=()
        args =("$curhost")

        for j in "${!HOSTS[@]}"; do
                if [[ "$i" != "$j" ]]; then
                        args =("${HOSTS[$j]}")
                else
                        continue;

                fi
        done
        #echo 'Array before test:'"${args[*]}"
        create_genesis_start_file "$EOS_PUB_KEY" "$EOS_PRIV_KEY" "${HOSTS[$i]}" "$PRODUCER" args
        create_start_file "$EOS_PUB_KEY" "$EOS_PRIV_KEY" "${HOSTS[$i]}" "$PRODUCER" args
done
}
            
create_genesis_start_file(){
        EOS_PUB_KEY=$1
        EOS_PRIV_KEY=$2
        CURRENTHOST=$3
        PRODUCER=$4
        peerags="$5[@]"
        peers=("${!peerags}")

        echo 'Genesis Currenthost is:'"$CURRENTHOST"
        #echo "${peers[*]}"
        VAR=""
        length=${#peers[@]}
        last=$((length - 1))

        for i in "${!peers[@]}" ; do

                if [[ "$i" == "$last" ]]; then
                        VAR ="--p2p-peer-address ${peers[$i]}:8888 \"
                else
                        VAR =$"--p2p-peer-address ${peers[$i]}:8888 \"$'nt'
                fi
        done
}

create_start_file(){
        EOS_PUB_KEY=$1
        EOS_PRIV_KEY=$2
        CURRENTHOST=$3
        PRODUCER=$4
        peerags="$5[@]"
        peers=("${!peerags}")

        echo 'Start file Currenthost is:'"$CURRENTHOST"
        #echo "${peers[*]}"
}

create_nodes_directories
  

Для каждой итерации первого цикла for я показываю третий аргумент $CURRENTHOST , который передается функциям create_genesis_start_file и create_start_file .
Для первой итерации вывод:

 Genesis Currenthost is:192.168.110.165
Start file Currenthost is:192.168.110.167
  

Вторая итерация:

 Genesis Currenthost is:192.168.110.166
Start file Currenthost is:192.168.110.167
  

Третья итерация,

 Genesis Currenthost is:192.168.110.167
Start file Currenthost is:192.168.110.167
  

Genesis Currenthost соответствует ожиданиям и Start file Currenthost должно быть таким же с ним. Я не понимаю, почему Start file Currenthost всегда устанавливается как 192.168.110.167 .
Если я удалю приведенный ниже код, create_genesis_start_file он будет работать нормально:

 VAR=""
            length=${#peers[@]}
            last=$((length - 1))
    
            for i in "${!peers[@]}" ; do
    
                    if [[ "$i" == "$last" ]]; then
                            VAR ="--p2p-peer-address ${peers[$i]}:8888 \"
                    else
                            VAR =$"--p2p-peer-address ${peers[$i]}:8888 \"$'nt'
                    fi
            done
  

Я не понимаю точной проблемы, почему изменяется значение переменной? Пожалуйста, помогите.

Комментарии:

1. Вы используете переменную i как в основном for i in "${!HOSTS[@]}" цикле, так и в create_genesis_start_file функции, и функция частично изменяет значение в цикле. Чтобы избежать конфликта, либо используйте разные имена переменных в двух местах, либо объявите их local в функции (или оба).

2. о да, моя ошибка! Спасибо. Проблема решена.

Ответ №1:

Для "$5[@]" меня это выглядит странно. Вы не можете использовать скаляр $5 , как если бы это был массив.

Кажется, вы хотите передать весь массив в качестве параметра. Поскольку у bash нет собственного способа сделать это, я предлагаю, чтобы на вызывающей стороне вы передавали "${args[@]}" в качестве параметра, а внутри вашей функции вы выполняли

 shift 4
peers=( "$@" )
  

Другая возможность, которая, однако, нарушает идею инкапсуляции, заключается в том, чтобы использовать treet peers как глобальную переменную, доступную для всех функций. При таком подходе вы бы на стороне вызывающей стороны собирали информацию, уже находящуюся в переменной peers , вместо args .

Из стиля программирования глобальные переменные (пересекающие границы функций) обычно не нравятся по уважительным причинам, но, по моему личному мнению, если вы просто выполняете простые сценарии оболочки, я бы счел это приемлемым решением.