我已经搜索过,但只看到有关在脚本中传递一个数组的答案。
我想将多个数组传递给一个Bash脚本,并将它们分配为以下单独的变量:
./myScript.sh ${array1[@]} ${array2[@]} ${array3[@]}
如下: var1=array1
,var2=array2
,以及var3=array3
我尝试了多种选项,但使用variableName=("$@")
将所有数组合并到每个变量中。我希望在我的 Bash 脚本中有一个变量代表每个数组。
我已经搜索过,但只看到有关在脚本中传递一个数组的答案。
我想将多个数组传递给一个Bash脚本,并将它们分配为以下单独的变量:
./myScript.sh ${array1[@]} ${array2[@]} ${array3[@]}
如下: var1=array1
,var2=array2
,以及var3=array3
我尝试了多种选项,但使用variableName=("$@")
将所有数组合并到每个变量中。我希望在我的 Bash 脚本中有一个变量代表每个数组。
Shell将一个单一参数向量(换句话说,一个简单的C字符串数组)传递给正在运行的程序。这是一个操作系统级别的限制:除了通过将结构编码为此C字符串数组成员的内容之外,(使用任何语言编写的)两个程序之间没有办法在参数列表中传递结构化数据。
如果效率是目标(无论是解析易用性还是在命令行和环境存储的ARG_MAX
限制下所使用的空间量),则考虑采用一种方法是在每个数组前加上描述其长度的参数。
但是,通过提供长度参数,您可以指示该参数列表的哪些部分应该是给定数组的一部分:
./myScript \
"${#array1[@]}" "${array1[@]}" \
"${#array2[@]}" "${array2[@]}" \
"${#array3[@]}" "${array3[@]}"
然后,在脚本中,你可以使用长度参数将内容分割回数组:
#!/usr/bin/env bash
array1=( "${@:2:$1}" ); shift "$(( $1 + 1 ))"
array2=( "${@:2:$1}" ); shift "$(( $1 + 1 ))"
array3=( "${@:2:$1}" ); shift "$(( $1 + 1 ))"
declare -p array1 array2 array3
如果以./myScript 3 a b c 2 X Y 1 z
的形式运行,将会得到以下输出:
declare -a array1='([0]="a" [1]="b" [2]="c")'
declare -a array2='([0]="X" [1]="Y")'
declare -a array3='([0]="z")'
顺便提一下,在 Python 世界中(特别是使用 argparse
库的用户),一种常见做法是允许多次传递同名参数来修改给定的数组。在 shell 中,它看起来像这样:
./myScript \
"${array1[@]/#/--array1=}" \
"${array2[@]/#/--array2=}" \
"${array3[@]/#/--array3=}"
#!/usr/bin/env bash
declare -a args array1 array2 array3
while (( $# )); do
case $1 in
--array1=*) array1+=( "${1#*=}" );;
--array2=*) array2+=( "${1#*=}" );;
--array3=*) array3+=( "${1#*=}" );;
*) args+=( "$1" );;
esac
shift
done
因此,如果您的原始值为array1=( one two three ) array2=( aye bee ) array3=( "hello world" )
,则调用约定如下:
./myScript --array1=one --array1=two --array1=three \
--array2=aye --array2=bee \
--array3="hello world"
./myScript \
<( (( ${#array1[@]} )) && printf '%s\0' "${array1[@]}") \
<( (( ${#array2[@]} )) && printf '%s\0' "${array2[@]}") \
<( (( ${#array3[@]} )) && printf '%s\0' "${array3[@]}")
…并且,要读取(使用bash 4.4或更高版本,并提供mapfile -d
):
#!/usr/bin/env bash
mapfile -d '' array1 <"$1"
mapfile -d '' array2 <"$2"
mapfile -d '' array3 <"$3"
#!/usr/bin/env bash
declare -a array1 array2 array3
while IFS= read -r -d '' entry; do array1+=( "$entry" ); done <"$1"
while IFS= read -r -d '' entry; do array2+=( "$entry" ); done <"$2"
while IFS= read -r -d '' entry; do array3+=( "$entry" ); done <"$3"
"${1#*=}"
或类似的东西。 - ephemient我更喜欢使用base64对数组进行编码和解码,例如:
encode_array(){
local array=($@)
echo -n "${array[@]}" | base64
}
decode_array(){
echo -n "$@" | base64 -d
}
some_func(){
local arr1=($(decode_array $1))
local arr2=($(decode_array $2))
local arr3=($(decode_array $3))
echo arr1 has ${#arr1[@]} items, the second item is ${arr1[2]}
echo arr2 has ${#arr2[@]} items, the third item is ${arr2[3]}
echo arr3 has ${#arr3[@]} items, the here the contents ${arr3[@]}
}
a1=(ab cd ef)
a2=(gh ij kl nm)
a3=(op ql)
some_func "$(encode_array "${a1[@]}")" "$(encode_array "${a2[@]}")" "$(encode_array "${a3[@]}")"
输出结果为
arr1 has 3 items, the second item is cd
arr2 has 4 items, the third item is kl
arr3 has 2 items, the here the contents op ql
无论如何,这对于具有制表符或空格的值是行不通的。如果需要,我们需要更详细的解决方案。例如:
encode_array()
{
for item in "$@";
do
echo -n "$item" | base64
done | paste -s -d , -
}
decode_array()
{
local IFS=$'\2'
local -a arr=($(echo "$1" | tr , "\n" |
while read encoded_array_item;
do
echo "$encoded_array_item" | base64 -d;
echo "$IFS"
done))
echo "${arr[*]}";
}
test_arrays_step1()
{
local IFS=$'\2'
local -a arr1=($(decode_array $1))
local -a arr2=($(decode_array $2))
local -a arr3=($(decode_array $3))
unset IFS
echo arr1 has ${#arr1[@]} items, the second item is ${arr1[1]}
echo arr2 has ${#arr2[@]} items, the third item is ${arr2[2]}
echo arr3 has ${#arr3[@]} items, the here the contents ${arr3[@]}
}
test_arrays()
{
local a1_2="$(echo -en "c\td")";
local a1=("a b" "$a1_2" "e f");
local a2=(gh ij kl nm);
local a3=(op ql );
a1_size=${#a1[@])};
resp=$(test_arrays_step1 "$(encode_array "${a1[@]}")" "$(encode_array "${a2[@]}")" "$(encode_array "${a3[@]}")");
echo -e "$resp" | grep arr1 | grep "arr1 has $a1_size, the second item is $a1_2" || echo but it should have only $a1_size items, with the second item as $a1_2
echo "$resp"
}
这里有一个代码示例,展示了如何将2个数组传递给函数。除了提供完整的代码示例外,与之前的答案没有什么不同。
这是用bash 4.4.12
编写的,即在bash 4.3
之后,需要采用不同的编码方法。一个数组包含要着色的文本,另一个数组包含要用于每个文本元素的颜色:
function cecho_multitext () {
# usage : cecho_multitext message_array color_array
# what it does : Multiple Colored-echo.
local -n array_msgs=$1
local -n array_colors=$2
# printf '1: %q\n' "${array_msgs[@]}"
# printf '2: %q\n' "${array_colors[@]}"
local i=0
local coloredstring=""
local normalcoloredstring=""
# check array counts
# echo "msg size : "${#array_msgs[@]}
# echo "col size : "${#array_colors[@]}
[[ "${#array_msgs[@]}" -ne "${#array_colors[@]}" ]] && exit 2
# build the colored string
for msg in "${array_msgs[@]}"
do
color=${array_colors[$i]}
coloredstring="$coloredstring $color $msg "
normalcoloredstring="$normalcoloredstring $msg"
# echo -e "coloredstring ($i): $coloredstring"
i=$((i+1))
done
# DEBUG
# echo -e "colored string : $coloredstring"
# echo -e "normal color string : $normal $normalcoloredstring"
# use either echo or printf as follows :
# echo -e "$coloredstring"
printf '%b\n' "${coloredstring}"
return
}
调用函数:
#!/bin/bash
green='\E[32m'
cyan='\E[36m'
white='\E[37m'
normal=$(tput sgr0)
declare -a text=("one" "two" "three" )
declare -a color=("$white" "$green" "$cyan")
cecho_multitext text color
任务完成 :-)
Charles Duffy的回答完全有效,但我会用不同的方式来使初始化var1
,var2
和var3
在您的脚本中更简单:
./myScript.sh "${#array1[@]} ${#array2[@]} ${#array3[@]}" \
"${array1[@]}" "${array2[@]}" "${array3[@]}"
然后在myScript.sh
中
#!/bin/bash
declare -ai lens=($1);
declare -a var1=("${@:2:lens[0]}") var2=("${@:2+lens[0]:lens[1]}") var3=("${@:2+lens[0]+lens[1]:lens[2]}");
编辑:由于Charles简化了他的解决方案,它可能比我的更好、更清晰。
array1=(1 2 3)
array2=(3 4 5)
array3=(6 7 8)
有一个像这样的脚本:
arg1=("${!1}")
arg2=("${!2}")
arg3=("${!3}")
echo "arg1 array=${arg1[@]}"
echo "arg1 #elem=${#arg1[@]}"
echo "arg2 array=${arg2[@]}"
echo "arg2 #elem=${#arg2[@]}"
echo "arg3 array=${arg3[@]}"
echo "arg3 #elem=${#arg3[@]}"
并像这样调用它:
. ./test.sh "array1[@]" "array2[@]" "array3[@]"
array1=("hello world" "goodbye world")
将通过"${array1[@]}"
扩展为两个值,但通过未加引号的${array1[@]}
将扩展为四个值。 - Charles Duffy