gpt4 book ai didi

arrays - 将多个数组作为参数传递给 Bash 脚本?

转载 作者:行者123 更新时间:2023-11-29 08:59:48 27 4
gpt4 key购买 nike

我看过了,但只看到脚本中传递的一个数组的答案。

我想将多个数组传递给 bash 脚本,该脚本将它们分配为单独的变量,如下所示:

./myScript.sh ${array1[@]} ${array2[@]} ${array3[@]}

使得:var1=array1var2=array2var3=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 library 的用户)的一种常见做法是允许多次传递参数以修改给定数组。在 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=(一二三)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 样式的链接到 FIFO,子 shell 写入每个数组的内容.

./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"

...或者,支持旧的 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"

关于arrays - 将多个数组作为参数传递给 Bash 脚本?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/43686878/

27 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com