繁体   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