传递包含空格和通配符的参数时出现问题

传递包含空格和通配符的参数时出现问题

如果参数可能包含通配符和/或空格(如果这些参数是可选的),那么我在传递参数时遇到问题。由于这听起来相当抽象,让我们举一个小例子:以下 shell 脚本some_command.sh需要 2 或 3 个参数。第一个参数应该是命令行开关,第二个参数是可选的,如果存在,则必须是 形式的命令行开关--NAME=VALUE,最后一个参数是必需的,可以是任何内容:

#!/bin/bash
# This is file some_command.sh
# Synopsis:
# some_command.sh --switch1=val1 [--switch2=val2] arg
echo "switch1: $1"
shift
if [[ "$1" == --*=* ]]
then
  echo "switch2 ($1) detected"
  shift
fi
echo argument is ${1:?argument missing}

假设我some_command.sh通过其他脚本调用,caller.sh如下所示:

#!/bin/bash
# This is file caller.sh
if [[ ${1:-x} == x ]]
then
  switch="--abc=long argument"
else
  switch=""
fi
some_command.sh "--exclude=*~" "$switch" arg

请注意引用。引号--exclude是必要的,因为通配符表达式不能被 shell 扩展,引号也是"$switch"必要的,因为$switch可能包含带有空格的文本,并且参数不能在空格上被分解。

目的是,如果我们执行caller.sh x,这应该会导致

some_command.sh "--exclude=*~" "--abc=long argument"  arg

如果我们执行,比如说,,caller.sh y这应该变成

some_command.sh "--exclude=*~" arg

caller.sh在这里提供的,确实不是工作正常,因为在后一种情况下,它将执行

some_command.sh "--exclude*~" "" arg

这是不正确的。

我尝试在命令前加上前缀eval.虽然这可以解决 的问题$switch,但它也会删除 周围的引号"--exclude",并且通配符将由 shell 进行评估。

我想我可以继续使用eval, 并使用额外的引用级别, ie "\"--exclude*~\"",但这是一个糟糕的解决方案。我想知道是否有人有更干净的方法来做到这一点。

如果您想知道我为什么会提出这个问题:我在编写调用脚本时偶然发现了这个问题zip,因为这些脚本应该能够处理文件名中的空格。

顺便说一句,如上所述,问题发生在bash和 上zsh。我还对聪明的解决方案感兴趣,这些解决方案仅适用于其中一种 shell。

答案1

使用数组,因为它可以扩展到可变数量的参数:

#! /bin/bash -
# This is file caller.bash
switch=()
if [[ ${1-x} == x ]]
then
  switch=("--abc=long argument")
fi
some_command.sh "--exclude=*~" "${switch[@]}" arg

或者你可以使用${var+...}语法:

#! /bin/sh -
# This is file caller.sh
unset switch
if [ "${1-x}" = x ]
then
  switch="--abc=long argument"
fi
some_command.sh "--exclude=*~" ${switch+"$switch"} arg

请注意,使用 zsh,您可以执行以下操作:

#! /bin/zsh -
switch=
if [ "${1-x}" = x ]
then
  switch="--abc=long argument"
fi
some_command.sh "--exclude=*~" $switch arg

zsh不做分割+全局在参数扩展时,但它确实空去除这就是你想要的。

相关内容