web-dev-qa-db-ja.com

関数内でのグローバル変数の宣言

私がやりたいことは以下の通りです。関数内で、変数に値を割り当てる必要があります。その名前は別の変数から取得されます。言い換えると:

func() {  
  #  
  # Here happens something that ultimately makes $arg="var_name"
  # 
  declare -g ${arg}=5
}

func

echo ${var_name}; # Prints out "5"

上記のコードスニペットは、bash 4.2で適切に機能します。ただし、4.2より前のbashでは、declare-gオプションがありません。 Googleで見つけたものはすべて、関数内でグローバル変数を定義するには、var=value構文を使用する必要があると述べていますが、残念ながらvar自体は別の変数に依存しています。 ${arg}=5も機能しません。 (-bash: var_name=5: command not foundと表示されています。

興味深いことに、このすべての理由は、この関数が実際にスクリプトパラメータからグローバル変数を作成するためです。つまり、script --arg1=valを実行すると、arg1という名前の変数が自動的に作成され、値はvalになります。大量の定型コードを節約します。

21
Leonid99

Var = valueを文字列として作成し、bash組み込みコマンドevalを使用して評価できます。

3
minopret

関数内のdeclareが期待どおりに機能しません。関数で宣言された読み取り専用のグローバル変数が必要でした。私はこれを関数の中で試しましたが、うまくいきませんでした:

declare -r MY_VAR=1

しかし、これはうまくいきませんでした。 readonlyコマンドを使用した場合:

func() {
    readonly MY_VAR=1
}
func
echo $MY_VAR
MY_VAR=2

これにより1が出力され、2番目の割り当てに対してエラー「MY_VAR:readonly variable」が発生します。

15
kipibenkipod

これはShellとタグ付けされているため、declareは限られたシェルのセットでのみ有効なキーワードであり、-gをサポートするかどうかは問題ではないことに注意することが重要です。一般的なBourne Shellでこの種のことを行うには、evalを使用するだけです。

eval ${arg}=5
7
William Pursell

-vスイッチが組み込まれたprintfが必要だと思います。

func() {
    printf -v "$var" '5'
}
var=var_name
func
echo "$var_name"

5を出力します。

6
gniourf_gniourf

"eval"(または任意の直接割り当て)を使用すると、特殊文字(または値の注入などの問題)が頭痛の種になる可能性があります。

「読む」だけで大成功

$ function assign_global() {
>   local arg="$1"
>   IFS="" read -d "" $arg <<<"$2"
>}
$ assign_global MYVAR 23
echo $MYVAR
23
$ assign_global MYVAR "\"'"
"'
4
Beorn Harris

もう少しハックしたくないものがあれば、declare -gの代わりにexportを使用してみてください。現在は環境変数であるという利点があります。

func() {  
#  
# Here happens something that ultimately makes $arg="var_name"
# 
export ${arg}=5
}

func

echo ${var_name}; # Prints out "5"

残念ながら、これはまだ配列では機能しません。

3
Zach

関数定義内で配列変数を宣言するためのBashでは、次の例のように、localコマンドをevalコマンドと組み合わせて使用​​できます。

#!/bin/bash
function test
{
    local -g $1
    local array=( AA BB 'C C' DD)
    eval ${1}='("${array[@]}")'
}
test VAR
echo VAR=${VAR[@]:1:2}

出力は次のようになります。

$./test.sh
VAR=BB C C

GNU bash、バージョン4.4.18

2
tomy

Evalは配列変数で動作します... evalステートメント内でローカル配列変数を単一引用符で囲む必要がありました。

以下は、ファイル(1番目の引数)を1行ずつ読み込み、それをget_fileの2番目の引数に渡された変数名にコピーします。

get_file () {
  declare -a Array=();
  while read line; do
    Array=("${Array[@]}" "($line)")
  done < ${1}
  eval ${2}='("${Array[@]}")'
  unset Array
}

declare -a my_array=();
get_file /etc/myfile.conf my_array
echo ${#my_array[@]}
0
ASG

たぶん、次の関数を使用して、bash(<4.2)でグローバル変数を動的に割り当てることができます。 2つ以上の引数が渡された場合、値は配列型になります。例えば

_set2globals variable_name arg1 [arg2] [arg3] [...]

ソース:

# dynamically set $variable_name($1)=$values($2...) to globals scope
function _set2globals()
{
    if (( $# < 2 )); then
        printf "$FUNCNAME: expect at least 2 argument, but %d you given.\n" $# >&2
        exit 1
    fi
    local ___pattern_='^[_a-zA-Z][_0-9a-zA-Z]*$'
    if [[ ! $1 =~ $___pattern_ ]]; then
        printf "$FUNCNAME: invalid variable name: %s.\n" "$1" >&2
        exit 1
    fi
    local __variable__name__=$1
    shift
    local ___v_
    local ___values_=()
    while (($# > 0)); do
        ___v_=\'${1//"'"/"'\''"}\'
        ___values_=("${___values_[@]}" "$___v_") # Push to array
        shift
    done

    eval $__variable__name__=\("${___values_[@]}"\)
}
0
Ekeyme Mo