将变量拆分为 sh 中的命令选项参数

将变量拆分为 sh 中的命令选项参数

谁能告诉我在脚本调用中将变量转换为重复参数的最有效方法?我不知道如何正确地描述它,但这些例子不言而喻。至少我希望他们这样做:)

示例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[@]}"

相关内容