我不是 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")
会打印:
number of arguments func2 got: 3
编辑,感谢评论指出:由于我的示例使用 echo,因此代码无论如何都会打印它得到 1 或 14 个参数,具体取决于您是否引用 func2 的参数。然而,我正在寻找一种从函数返回多个值的方法,而不会使它们被破坏,就像我提到的预期结果一样
谢谢!
答案1
要回答标题中的问题,禁用分词的方法是设置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")
(但是,您不能在列表末尾使用空字符串,因为命令替换会删除所有尾随换行符,而不管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[@]}"
(如果调用的变量_out
也存在于函数外部,则变量作用域存在一些问题。)
还要注意,如果您有未加引号的扩展(变量或命令替换),它们的结果也将受到文件名通配符的影响,因此像这样的输出12 * 34
将会变得严重混乱,除非您还使用 禁用通配符set -f
。
答案2
你原本想要的是参数扩展后禁用分词,所以不要写
mcd() {
mkdir -p "$1"
cd "$1"
}
你可以写
mcd() {
mkdir -p $1
cd $1
}
无论如何它都会起作用mcd "foo bar"
。
这是大多数用例的首选行为,这就是为什么zsh
将其设为默认行为(您可以使用SH_SPLIT_WORD
选项全局禁用它或通过编写单独禁用它${=1}
)。
我知道你要求bash
解决方案,但是“使用zsh
而不是bash
“这是我许多问题的答案,以至于我真的有zsh
一天切换到并摆脱了许多问题。因此,我很高兴将这一建议传递给其他人。恕我直言,坚持下去的理由很少bash
。