按原样将参数传递给函数

按原样将参数传递给函数

浏览过这篇文章:完全按原样将参数传递给函数

但设置略有不同:

我有 3 个 bash 函数 foo、bar、baz。它们的设置如下:

foo() {
  bar $1
}

bar() {
  var1=$1
  var2=$2
  echo "$var1" test "$var2"
}
export ENV_VAR_1="1"
export ENV_VAR_2="2 3"

foo "${ENV_VAR_1} ${ENV_VAR_2}"

我期望输出是:

1 test 2 3

但输出是:

1 test 2

我明白为什么会这样。 bar 执行如下:

bar 1 2 3

我的问题是:如何让它执行

bar 1 "2 3"

我尝试过的方法:

foo () {bar "$1"} 
# Out: 1 2 3 test. Makes sense since "1 2 3" is interpreted as a single argument.

答案1

这提供了一个字符串作为参数foo

foo "${ENV_VAR_1} ${ENV_VAR_2}"

因为$1不在引号中,所以 shell 执行分词,因此,这为 提供了三个参数bar

bar $1

分词是对S1.不考虑这些字符的原始来源。

更简单的例子

让我们定义x为:

$ x="${ENV_VAR_1} ${ENV_VAR_2}"

现在,让我们打印"$x"

$ printf "%s\n" "$x"
1 2 3

正如您所看到的,"$x"被解释为一个参数。相比之下,请考虑:

$ printf "%s\n" $x
1
2
3

在上面,分词是在$x创建三个参数时执行的。

Shell 字符串没有历史的概念。字符串在被分配之前x没有2 3作为一个字符串的一部分的记录。x字符串x仅由1、 空格、2、 空格组成,3并且分词对空格进行操作。

替代方案:选择您自己的 IFS

这会产生您想要的输出:

$ foo() ( IFS=@;  bar $1; )
$ foo "${ENV_VAR_1}@${ENV_VAR_2}"
1 test 2 3

在 中foo,我们设置IFS@。因此,所有后续的单词分割都是使用@单词分隔符来执行的。因此,在调用 时foo,我们将 a 放在@需要分词的任何位置。

答案2

您向函数传递一个参数foo,即 5 个字符的字符串1 2 3。三个数字之间用空格分隔。foo没有理由以不同的方式对待这些空间。

在组合${ENV_VAR_1}${ENV_VAR_2}内部单个字符串中,您丢失了信息。恢复丢失的信息需要魔法,而计算机无法做到这一点。要保留1 2和之间的分离3,您需要更改foo调用方式。传递两个单独的参数。

foo "${ENV_VAR_1}" "${ENV_VAR_2}"

那么你需要做的就是修复引用在呼叫中bar。要么传递两个参数:

foo () {
  bar "$1" "$2"
}

或传递整个参数列表:

foo () {
  bar "$@"
}

相关内容