簡體   English   中英

如何將數組參數傳遞給 Bash 腳本

[英]How to pass an array argument to the Bash script

令我驚訝的是,我搜索了 1 小時后沒有找到答案。 我想像這樣將一個數組傳遞給我的腳本:

test.sh argument1 array argument2

我不想把它放在另一個 bash 腳本中,如下所示:

array=(a b c)
for i in "${array[@]}"
do
  test.sh argument1 $i argument2
done

Bash數組不是“第一類值” - 你不能像一個“東西”那樣傳遞它們。

假設test.sh是一個bash腳本,我會這樣做

#!/bin/bash
arg1=$1; shift
array=( "$@" )
last_idx=$(( ${#array[@]} - 1 ))
arg2=${array[$last_idx]}
unset array[$last_idx]

echo "arg1=$arg1"
echo "arg2=$arg2"
echo "array contains:"
printf "%s\n" "${array[@]}"

並調用它

test.sh argument1 "${array[@]}" argument2

讓你的腳本arrArg.sh像這樣:

#!/bin/bash

arg1="$1"
arg2=("${!2}")
arg3="$3"
arg4=("${!4}")

echo "arg1=$arg1"
echo "arg2 array=${arg2[@]}"
echo "arg2 #elem=${#arg2[@]}"
echo "arg3=$arg3"
echo "arg4 array=${arg4[@]}"
echo "arg4 #elem=${#arg4[@]}"

現在在shell中設置這樣的數組:

arr=(ab 'x y' 123)
arr2=(a1 'a a' bb cc 'it is one')

並傳遞這樣的參數:

. ./arrArg.sh "foo" "arr[@]" "bar" "arr2[@]"

以上腳本將打印:

arg1=foo
arg2 array=ab x y 123
arg2 #elem=3
arg3=bar
arg4 array=a1 a a bb cc it is one
arg4 #elem=5

注意:使用腳本執行腳本可能看起來很奇怪. ./script . ./script語法。 請注意,這是用於在當前shell環境中執行腳本的命令。

問:為什么當前的shell環境為什么不是子shell?
答:因為bash不會將數組變量導出到子進程,如bash作者本人所述

使用備用分隔符將數組作為參數傳遞給腳本

實際樣本:

選擇響鈴字符:C 序列使用的 ascii 0x07\a

小准備:有一個 function 來准備變量:

mergeArray() {
    local IFS=$'\a'
    local -n src=$1 tgt=$2
    tgt=${src[*]}
}

然后腳本可能如下所示:

#!/bin/bash

arg1="$1"
IFS=$'\a' read -ra arg2 <<<"$2"
arg3="$3"

declare -p arg{1,2,3}

在實踐中:

var1=Hello var2=(foo bar baz) var3=world.
mergeArray var2 mvar2
bash script "$var1" "$mvar2" "$var3"

必須output:

declare -- arg1="Hello"
declare -a arg2=([0]="foo" [1]="bar" [2]="baz")
declare -- arg3="world."

說明

  • 通過使用local IFS=我確保IFS varialbe 不會在環境中被修改
  • local -n是綁定變量的名稱引用
  • ${src[*]}將使用$IFS的第一個字符將數組的所有元素合並為一個字符串
  • 當然,我為此使用\a ,這可以(在兩側)替換為從\1\377的任何其他單字節非 null 字符(ascii),而所選字符未在您的數組中使用。

安裝和遠程執行

function mergeArray可以安裝到您的.bashrc中以供示例或在您運行腳本之前獲取的任何文件中。

一旦完成,腳本本身甚至可以遠程定位。 然后通過相同的命令運行:

ssh user@remote /path/to/script  "$var1" "$mvar2" "$var3"

但對於更強大的遠程執行,我更喜歡:

myArray=("foo bar baz" 'alice bob charlie' 'strawberry raspberry')
mergeArray myArray mergedArray
var1="Hello world!"
ssh user@remote /bin/bash <<eoRemote
    /path/to/script  "$var1" "$mergedArray" "This seem nice, isnt't it?"
eoRemote

在我的遠程主機上,這會產生:

declare -- arg1="Hello world!"
declare -a arg2=([0]="foo bar baz" [1]="alice bob charlie" [2]="strawberry raspberry")
declare -- arg3="This seem nice, isnt't it?"

您可以將數組寫入文件,然后在腳本中獲取文件。 例如:

array.sh

array=(a b c)

test.sh

source $2
...

運行test.sh腳本:

./test.sh argument1 array.sh argument3

如果值沒有空格(即它們是 url、標識符、數字等),您可以這樣做:

ARRAY=(one two three)
test.sh argument1 "${ARRAY[*]}" argument3

這與:

test.sh argument1 "one two three" argument3

test.sh你做:

ARG1="$1"
ARRAY=($2) # Note that we don't add quotes
ARG3="$3"

如果值有空格,我會選擇glenn jackman 的答案並通過將數組作為最后一個參數傳遞來簡化它:

ARRAY=("the first" "the second" "the third")
test.sh argument1 argument2 "${ARRAY[@]}"

這與:

test.sh argument1 argument2 "the first" "the second" "the third"

test.sh做:

ARG1="$1"; shift
ARG2="$1"; shift
ARRAY=("$@")

我在這里找到的最佳解決方案

f() {
    declare -a argAry1=("${!1}")
    echo "${argAry1[@]}"
    # ...
}

arr1=(
    "a"
    "b"
)
f arr1[@] arr2[@] arg2

如果你的數組長度不是太長,你可以將數組轉換為字符串,用','連接

文件1.sh

s=${1}
arr=(`echo ${s} | tr ',' ' '`)  # then we can convert str to arr

文件2.sh

a="1,2,3,4"
sh file1.sh ${a} 

如果這是你的命令:

test.sh argument1 ${array[*]} argument2

您可以將數組讀入test.sh,如下所示:

arg1=$1
arg2=${2[*]}
arg3=$3

它會向你抱怨(“糟糕的替代”),但會起作用。

暫無
暫無

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

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