1

私の bash の問題を説明する前に、いくつかのコンテキストを説明させてください。

現在の仕事で使用している bash の「フレームワーク」を使用して、いくつかのスクリプトを作成しています。フレームワークの機能の 1 つは、クラスター インフラストラクチャでジョブを実行するのに役立つ一連の環境変数を初期化することです。

$YYこれらの変数は、によって指定された日付に依存し、環境変数でも$mmあり$ddます (はい、これは配線されています)。フレームワークを使用するには、まず日付を定義してから、関数を呼び出して他の変数を初期化します。これは、特定の日のみの変数を必要とするスクリプトを作成する場合にうまく機能します。今日、私は 2 日間の変数を必要とするものを書いています。これを書いていると、奇妙な問題に直面します。問題をよりよく理解するために、それをシミュレートする次のコードを書きました。

#!/bin/bash

function assign(){
    date=$1
    date[1]=$YY
    date[2]=$mm
    date[3]=$dd
}

function display() {
    date=$1
    echo "${date[1]}/${date[2]}/${date[3]}"
}

export YY=2012
export mm=09
export dd=20
declare -a my_date1=()
assign $my_date1

export YY=2012
export mm=08
export dd=20
declare -a my_date2=()
assign $my_date2

display $my_date1
display $my_date2

予想される出力は次のとおりです。

2012/09/20
2012/08/20

しかし、出力は次のとおりです。

2012/08/20
2012/08/20

最初は、割り当て関数が配列を値ではなく , への参照で埋めていると思い$YYまし$mm$dd。しかし、次のコードを試してみましたが、結果は変わりません。

date[1]=$(echo $YY)
date[2]=$(echo $mm)
date[3]=$(echo $dd)

誰かが私に何を追加するか説明できますか? たぶん何かが配線されていdate=$1ます...

4

1 に答える 1

3

配列は、bash では値または参照によって渡されません。むしろ、配列の展開の値が値渡しされます。あなたが書くとき

assign $my_date1

空の文字列に展開され、関数が呼び出される前に単語分割後に消えるため、date内部の変数assignは nullです。$my_date1その結果、$1設定が解除されます。

しかし、ローカルとして宣言されていないためグローバル変数である は、et aldateを使用して正しく設定され、2 回目の呼び出しでリセットされます。YYassign

dateまた、関数の最初の行は引数への参照を作成しないことに注意してください。それは実際には、グローバルdate配列になるものの 0 番目の要素を の展開に設定するだけです$1


そうは言っても、declare組み込みの間接パラメーター展開を使用してそれを偽装する方法を紹介します。

function assign () {
    ref=$1
    # Without the -g, we'd declare function-local parameters. The argument is a
    # string to evaluate as a variable assignment. If $ref=my_date1, then we do
    # 'my_date1[1]=$YY', 'my_date1[2]=$mm', etc.
    declare -g "$ref[1]=$YY"
    declare -g "$ref[2]=$mm"
    declare -g "$ref[3]=$dd"
}

function display () {
    ref=$1
    # If $ref=my_date1, then idx
    # iterates over my_date[1], my_date[2], my_date[3].
    # E.g. ${!idx} in the first iteration is ${my_date[1]}.
    arr=()
    for idx in $ref[{1,2,3}]; do
        arr+=( ${!idx} )
    done
    local IFS="/"
    echo "${arr[*]}"
}

export YY=2012 mm=09 dd=20
assign my_date1    # The *name* of the array; no need to predeclare

export YY=2012 mm=08 dd=20
assign my_date2    # The *name* of the array; no need to predeclare

# Again, just the *names* of the arrays
display my_date1
display my_date2
于 2012-09-21T19:22:34.873 に答える