![将变量拆分为 sh 中的命令选项参数](https://linux22.com/image/212854/%E5%B0%86%E5%8F%98%E9%87%8F%E6%8B%86%E5%88%86%E4%B8%BA%20sh%20%E4%B8%AD%E7%9A%84%E5%91%BD%E4%BB%A4%E9%80%89%E9%A1%B9%E5%8F%82%E6%95%B0.png)
谁能告诉我在脚本调用中将变量转换为重复参数的最有效方法?我不知道如何正确地描述它,但这些例子不言而喻。至少我希望他们这样做:)
示例1:
# input
export DOMAINS="domain1.tld,domain2.tld"
# tranform to
./example-script.sh -d "domain1.tld" -d "domain2.tld"
示例2(输入为单数):
# input
export DOMAINS="domain1.tld"
# tranform to
./example-script.sh -d "domain1.tld"
[更新] 很抱歉没有在第一篇文章中添加此内容。
我应该添加的上下文:
- DOMAINS 是添加到 Docker 容器的环境变量
- 容器只有
sh
外壳,因此zsh
特定bash
选项不起作用。 - 抱歉添加了初始
bash
标签。
答案1
使用以下方法更容易zsh
:
从包含 - 分隔列表的标量变量,
:
DOMAINS="domain1.tld,domain2.tld"
s
分割,
成数组:
domains=( ${(s[,])DOMAINS} )
压缩一个opt=( -d )
数组:
opt=( -d )
./example-script.sh ${opt:^^domains}
如果除了 之外还./example-script.sh
支持,则可以跳过中间数组并使用:-ddomain1.tld
-d
domain1.tld
./example-script.sh -d$^domains
在 bash 中,您可以使用循环:
IFS=, # split on ,
set -o noglob # disable glob
domains=( $DOMAINS ) # split+glob
args=()
for domain in "${domains[@]}"; do
args+=( -d "$domain" )
done
./example-script.sh "${args[@]}"
或者您可以使用 shell 语法生成代码:
IFS=, # split on ,
set -o noglob # disable glob
domains=( $DOMAINS ) # split+glob
if [ "${#domains[@]}" -gt 0 ]; then
printf -v args ' -d %q' "${domains[@]}"
else
args=
fi
shell_code="./example-script.sh$args"
eval -- "$shell_code"
如果除了 之外还./example-script.sh
支持,您还可以这样做:-ddomain1.tld
-d
domain1.tld
IFS=, # split on ,
set -o noglob # disable glob
domains=( $DOMAINS ) # split+glob
./example-script.sh "${domains[@]/#-d}"
-d
我们在数组的每个元素前面添加$domains
。
标准sh
没有数组,read -A/-a
标准也printf
没有%q
(并且支持它作为扩展的实现并不总是生成sh
兼容的引用),但是您可以使用上面的第一个 bash 方法来"$@"
代替数组:
IFS=, # split on ,
set -o noglob # disable glob
set --
for domain in $DOMAINS; do # split+glob
set -- "$@" -d "$domain"
done
./example-script.sh "$@"
另一种选择是调用awk
进行拆分并生成sh
兼容的代码:
eval "./example-script.sh$(
LC_ALL=C awk -v q="'" '
function shquote(s) {
gsub(q, q "\\\\" q q, s)
return q s q
}
BEGIN {
n = split(ENVIRON["DOMAINS"], domains, ",")
for (i = 1; i <= n; i++)
printf " -d %s", shquote(domains[i])
}'
)"
答案2
尝试这样的事情:
domains=( "domain1.tld" "domain2.tld" )
./example-script.sh $(printf -- '-d "%s" ' "${domains[@]}")
答案3
您已经标记了,bash
因此这是该 shell 的基于数组的解决方案:
DOMAINS="domain1.tld,domain2.tld"
# Comma separated string to array
IFS=, read -r -a domains <<<"$DOMAINS"
# Array to parameter list
args=()
for domain in "${domains[@]}"; do args+=(-d "$domain"); done
然后,您可以将该"${args[@]}"
列表插入到结果命令中(包括双引号)。例如,
./example-script.sh "${args[@]}"