簡體   English   中英

如何在 shell 腳本中動態生成新的變量名?

[英]How can I generate new variable names on the fly in a shell script?

我正在嘗試在 shell 腳本中生成動態 var 名稱,以在循環中處理一組具有不同名稱的文件,如下所示:

#!/bin/bash

SAMPLE1='1-first.with.custom.name'
SAMPLE2='2-second.with.custom.name'

for (( i = 1; i <= 2; i++ ))
do
  echo SAMPLE{$i}
done

我希望輸出:

1-first.with.custom.name
2-second.with.custom.name

但我得到了:

SAMPLE{1}
SAMPLE{2}

是否可以即時生成 var 名稱?

您需要利用變量間接:

SAMPLE1='1-first.with.custom.name'
SAMPLE2='2-second.with.custom.name'

for (( i = 1; i <= 2; i++ ))
do
   var="SAMPLE$i"
   echo ${!var}
done

Bash 手冊頁,在“參數擴展”下:

“如果參數的第一個字符是感嘆號 (!),則引入了一個變量間接級別。Bash 使用由參數的其余部分形成的變量的值作為變量的名稱;然后擴展這個變量,然后值用於替換的其余部分,而不是參數本身的值。這稱為間接擴展。”

問題

您正在使用i的值,就好像它是一個數組索引。 不是,因為 SAMPLE1 和 SAMPLE2 是單獨的變量,而不是數組。

此外,在調用echo SAMPLE{$i}您只是將i的值附加到單詞“SAMPLE”之后。 您在此語句中取消引用的唯一變量是$i ,這就是您得到結果的原因。

解決問題的方法

有兩種主要方法可以解決這個問題:

  1. 通過eval內置變量間接變量擴展對內插變量進行多階段解引用。
  2. 迭代數組,或使用i作為數組的索引。

使用eval取消引用

在這種情況下,最簡單的方法是使用eval

SAMPLE1='1-first.with.custom.name'
SAMPLE2='2-second.with.custom.name'

for (( i = 1; i <= 2; i++ )); do
    eval echo \$SAMPLE${i}
done

這會將i的值附加到變量的末尾,然后重新處理結果行,擴展插入的變量名稱(例如SAMPLE1SAMPLE2 )。

使用間接變量取消引用

這個問題的公認答案是:

SAMPLE1='1-first.with.custom.name'
SAMPLE2='2-second.with.custom.name'

for (( i = 1; i <= 2; i++ ))
do
   var="SAMPLE$i"
   echo ${!var}
done

從技術上講,這是一個三步過程。 首先,它為var分配一個內插變量名,然后解引用存儲在var 中的變量名,最后擴展結果。 它看起來更簡潔一些,有些人更喜歡這種語法而不是eval ,但結果基本相同。

迭代數組

您可以通過迭代數組而不是使用變量插值來簡化循環和擴展。 例如:

SAMPLE=('1-first.with.custom.name' '2-second.with.custom.name')
for i in "${SAMPLE[@]}"; do
    echo "$i"
done

這比其他方法增加了好處。 具體來說:

  1. 您不需要指定復雜的循環測試。
  2. 您可以通過$SAMPLE[$i]語法訪問單個數組元素。
  3. 您可以使用${#SAMPLE}變量擴展來獲取元素總數。

原始示例的實際等效性

所有三種方法都適用於原始問題中給出的示例,但數組解決方案提供了最大的整體靈活性。 選擇最適合您手頭數據的一種。

據我所知, 他們的方式@johnshen64 說。 此外,您可以使用這樣的數組來解決您的問題:

SAMPLE[1]='1-first.with.custom.name'
SAMPLE[2]='2-second.with.custom.name'

for (( i = 1; i <= 2; i++ )) do
    echo ${SAMPLE[$i]}
done

請注意,您不需要使用數字作為索引SAMPLE[hello]也能正常工作

您可以使用eval ,如下所示:

SAMPLE1='1-first.with.custom.name'
SAMPLE2='2-second.with.custom.name'

for (( i = 1; i <= 2; i++ ))
do
  eval echo \$SAMPLE$i
done

不是一個獨立的答案,只是 Miquel 的答案的補充,我無法很好地發表評論。

您也可以使用循環、+= 運算符和 here 文檔來填充數組:

SAMPLE=()
while read; do SAMPLE+=("$REPLY"); done <<EOF
1-first.with.custom.name
2-second.with.custom.name
EOF

在 bash 4.0 中,它就像

readarray SAMPLE <<EOF
1-first.with.custom.name
2-second.with.custom.name
EOF

評估“回聲 $SAMPLE${i}”

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM