有什么方法可以禁用 bash 中的分词吗?

zom*_*rot 1 bash

我不是 bash 专家,但最近我一直在编写 bash 脚本,而且每次都引用我的参数真的很麻烦。有什么办法可以改变这种 shell 行为吗?我希望我的字符串即使不引用它们也不会被分割

PS - 将 IFS 设置为 null 不起作用,因为所有参数都会被破坏。我想要的是写作时:

func1() {
    echo $1 $2 $3
}

func2() {
    echo "number of arguments func2 got: $#"
} 

func2 $(func1 firstarg "second arg is a multi word string" "third arg is also a multi word string")
Run Code Online (Sandbox Code Playgroud)

会打印:

number of arguments func2 got: 3
Run Code Online (Sandbox Code Playgroud)

编辑,感谢评论指出:由于我的示例使用 echo,因此代码无论如何都会打印它得到 1 或 14 个参数,具体取决于您是否引用 func2 的参数。然而,我正在寻找一种从函数返回多个值的方法,而不会使它们被破坏,就像我提到的预期结果一样

谢谢!

ilk*_*chu 5

要回答标题中的问题,禁用分词的方法是设置IFS为空字符串。

但是您在文本中描述的内容更困难,在通过命令替换传递多个多单词字符串后保持它们不同。确实没有简单的方法可以做到这一点。

这里的根本问题是命令替换的结果(〜在其中调用的函数的标准输出的输出)只是一个字符串(字节流),并且您试图在其中容纳多个字符串。在一般情况下,这些字符串中包含任意内容,这是一个相当基本的问题。

这与将命令存储在变量中也没有太大区别,只是我们在这里进行了命令替换。


解决方法是保留一些字符用作分隔符,并将其设置IFS为该字符。使用默认值IFS,您将使用空格、制表符和换行符作为分隔符,这显然不适用于带有空格的字符串。如果IFS设置为空字符串,则不会有这样的分隔符,因此您总是只会得到一个字段。

但是您可以设置IFS为例如仅换行符(假设您的字符串不是多行):

#!/bin/bash
IFS=$'\n'
foo() {
    printf "%s\n" "$@"
}

nargs() {
    echo "number of arguments nargs got: $#"
} 

nargs $(foo firstarg "multi word string" "also a multi word string")
Run Code Online (Sandbox Code Playgroud)

(但是,您不能在列表末尾使用空字符串,因为命令替换会删除所有尾随换行符,而不管IFS.)

另一种方法是不使用函数的标准输出,而是将变量的名称传递给函数,并让函数通过 nameref 写入命名数组:

#!/bin/bash
bar() {
    declare -n _out="$1"
    shift
    _out=("$@")
}

nargs() {
    echo "number of arguments nargs got: $#"
} 

bar tmparr firstarg "multi word string" "also a multi word string"
nargs "${tmparr[@]}"
Run Code Online (Sandbox Code Playgroud)

(如果调用的变量_out也存在于函数外部,则变量作用域存在一些问题。)

另请注意,如果您有未加引号的扩展(变量或命令替换),它们的结果也将受到文件名通配的影响,因此类似的输出12 * 34将受到严重破坏,除非您也禁用set -f.