如果参数可能包含通配符和/或空格(如果这些参数是可选的),那么我在传递参数时遇到问题。由于这听起来相当抽象,让我们举一个小例子:以下 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
不做分割+全局在参数扩展时,但它确实空去除这就是你想要的。