2012-09-21 74 views
1

在解釋我的bash問題之前,讓我給你一些上下文:在bash中克隆一個變量?

我正在寫一些腳本,使用我當前使用的bash「框架」。該框架的一個特點是啓動一組有用的環境變量,以便在我們的集羣基礎架構上運行作業。

這些變量取決於由$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有線連接...

+2

嘗試將shebang行更改爲'#!/ bin/bash -xv'來查看bash是如何解釋代碼的。 – choroba

+0

永遠不需要兩次導出變量,並且在這個腳本中沒有明顯需要導出它們一次。 –

+0

@WilliamPursell:這就是爲什麼我把我的問題的一些背景!我做了這些事情是因爲我在當前工作中使用了瘋狂的框架。我問了這個問題,以理解這種行爲不是爲了解決我在工作中遇到的問題。即使這個劇本是愚蠢的,我也從中學到了一些東西。感謝chepner的回答和choroba的建議,這使我完全明白答案。 –

回答

3

數組不是通過bash中的值或引用傳遞的。相反,數組擴展的值是按值傳遞的。當你寫

assign $my_date1 

assigndate變量爲空,因爲$my_date1擴展爲一個空字符串,被稱爲函數之前字拆分後消失。因此,$1未設置。

date,是一個全局變量,因爲它不是本地申報,設置正確使用YY等,然後第二呼叫assign重置

此外,請注意,您的函數的第一行不會使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