Arrays 是否将多个数组作为参数传递给Bash脚本?
我已经看过了,但只看到脚本中传递的一个数组的答案 我想将多个数组传递给bash脚本,该脚本将它们作为单独的变量分配,如下所示:Arrays 是否将多个数组作为参数传递给Bash脚本?,arrays,bash,shell,command-line,Arrays,Bash,Shell,Command Line,我已经看过了,但只看到脚本中传递的一个数组的答案 我想将多个数组传递给bash脚本,该脚本将它们作为单独的变量分配,如下所示: ./myScript.sh ${array1[@]} ${array2[@]} ${array3[@]} 这样:var1=array1和var2=array2和var3=array3 我尝试了多个选项,但执行variableName=(“$@”)将所有数组合并到每个变量中。我希望在bash脚本中有一个表示每个数组的变量。shell将一个参数向量(即一个简单的字符串C数
./myScript.sh ${array1[@]} ${array2[@]} ${array3[@]}
这样:var1=array1
和var2=array2
和var3=array3
我尝试了多个选项,但执行
variableName=(“$@”)
将所有数组合并到每个变量中。我希望在bash脚本中有一个表示每个数组的变量。shell将一个参数向量(即一个简单的字符串C数组)传递给正在运行的程序。这是操作系统级别的限制:在参数列表中的两个程序(任何两个程序,用任何语言编写!)之间,不存在传递结构化数据的方法,除非在该C字符串数组成员的内容中对该结构进行编码
./myScript \
<( (( ${#array1[@]} )) && printf '%s\0' "${array1[@]}") \
<( (( ${#array2[@]} )) && printf '%s\0' "${array2[@]}") \
<( (( ${#array3[@]} )) && printf '%s\0' "${array3[@]}")
方法:长度前缀
如果效率是一个目标(无论是在解析的易用性和从代码中使用的空间量>ARGYMAX 命令行和环境存储的限制),一种考虑的方法是用一个描述其长度的参数对每个数组进行预处理。
但是,通过提供长度参数,可以指示该参数列表的哪些部分应该是给定数组的一部分:./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世界(尤其是的用户)中的一种常见做法是允许将参数传递多次以修改给定数组。在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
然后解析它的代码可能如下所示:
./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=(一二三)array2=(aye-bee)array3=(“hello-world”)
,则调用约定为:
./myScript --array1=one --array1=two --array1=three \
--array2=aye --array2=bee \
--array3="hello world"
方法:NUL分隔流 另一种方法是为每个数组传递一个文件名,从中可以读取以NUL分隔的数组内容列表。这种方法的一个主要优点是数组内容的大小不计入操作系统强制执行的命令行长度限制
ARG_MAX
。此外,对于可用的操作系统,下面的命令不会创建真正的磁盘文件,而是创建/dev/fd
-样式的链接,指向通过写入每个数组内容的子shell写入的FIFO
./myScript \
<( (( ${#array1[@]} )) && printf '%s\0' "${array1[@]}") \
<( (( ${#array2[@]} )) && printf '%s\0' "${array2[@]}") \
<( (( ${#array3[@]} )) && printf '%s\0' "${array3[@]}")
…或者,要支持较旧的bash版本,请执行以下操作:
#!/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"
#/usr/bin/env bash
声明-a阵列1阵列2阵列3
而IFS=read-r-d“”项;do array1+=(“$entry”);完成基于此问题的答案,您可以尝试以下方法
将数组定义为外壳上的变量:
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[@]"
这样称呼它:
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[@]"
请注意,脚本需要源代码(.or source),以便在当前shell环境中执行,而不是作为子shell执行。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简化了他的解决方案,这可能是一个比我更好、更清晰的解决方案。下面是一个代码示例,它演示了如何将两个数组传递给一个函数。除了提供一个完整的代码示例之外,没有什么比前面的答案更多的了
这是在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
工作完成:-)数组是否包含任意数据,或者是否存在您知道不在数据中的字符?例如,如果您的数组不包含逗号之类的内容,我可以在几分钟内找到一个解决方案Bash变量非常简单,您不能有这样的嵌套结构。@Barmar您可以使用一些技巧在命令行中传递的参数是字符串。如果您想强制一个结构,您需要自己序列化它。(例如,传入JSON)(…另一方面--我倾向于建议不要使用.sh
扩展名。可执行脚本定义命令,而命令通常没有扩展名:不运行ls.elf
或systriage.py
;如果用其他语言重写命令而不更新所有调用方,扩展名可能会产生误导s、 此外,暗示POSIX sh合规性的扩展可能导致人们调用需要ksh或bash扩展才能正确运行的脚本,而解释器不提供相同的功能).Eh?基本shell变量可以导出到环境中,从而可用于子流程,但数组不能。这将如何工作?这种方法对函数有效,但我非常确定@CharlesDuffy是正确的。Charles您是正确的。但是,正如anubhava在回答中的链接问题中所解释的,诀窍在于寻源(.或来源)脚本,以便脚本在当前shell环境中执行,而不是在子shell中执行。因此,在需要源代码才能工作的内容中使用shebang有点误导。@CharlesDuffy是的,您再次是正确的。为了清晰起见,我将编辑答案并将其删除。在第二种情况下,我认为您需要“${1#*=”
或类似内容。这是一个放在旧bash工具箱中的保管器,在将数组作为参数传递时将其组合在一起。做得好。