Bash 将字符串解析为一个参数而不是两个

问题描述

我有一个 bash 脚本和该 bash 脚本处理的 -e 标志。我想决定是否需要动态使用这个 -e 标志。代码如下所示:

if [...] then;
export EXPIRATION_FLAG="-e 1m";
else
export EXPIRATION_FLAG=""
fi
./my_script.sh $EXPIRATION_FLAG

问题是 bash 将这个字符串解析为一个参数而不是 2 个单独的参数。因此,如果回声 $1 我得到“-e 1m”,如果回声 $2 我得到“”,而不是 $1“-e”和 $2“1m”

脚本本身:

#!/bin/bash

set -x

echo $1
echo $2

while getopts e: OPT
do
    case $OPT in
        e) expirationPeriod=$OPTARG ;;
        *) printUsage ;;
    esac
done
shift `expr $OPTIND - 1`

if [ -n "$expirationPeriod" ] ; then
  echo $expirationPeriod
fi

任何想法如何解决

解决方法

./my_script.sh $EXPIRATION_FLAG

在 POSIX-y shell 中,这不带引号,应该调用 word splitting 并且 ./my_script.sh 应该得到两个参数。

$ foo() { printf "<%s> <%s>\n" "$1" "$2"; }
$ flags='-e 1m'
$ foo $flags
<-e> <1m>

当然,如果您引用它,或者您的 IFS 不包含空格,则不会发生这种情况:

$ foo "$flags"
<-e 1m> <>
$ IFS=
$ foo $flags
<-e 1m> <>

检查您是否在调用 shell 中更改了全局 IFS。请注意,某些 shell 从环境中继承 IFS(Bash 没有,但以防万一您实际使用了例如 Dash)。

默认情况下,Zsh 也不会拆分,您必须要求它这样做:

% foo() { printf "<%s> <%s>\n" "$1" "$2"; }
% flags='-e 1m'
% foo $flags
<-e 1m> <>
% foo $=flags
<-e> <1m>

在任何情况下,您都应该使用数组来存储这样的多个参数,而不是依赖分词,参见例如 How can we run a command stored in a variable? 在 unix.SE 上。