Bash脚本 - 以空格作为单个参数的字符串

时间:2014-07-26 04:50:00

标签: bash shell sh zsh

这不是我在实际应用中所做的全部,但归结为:

我有一个函数返回带有空格的东西。我希望能够调用该函数并将内容解释为单个参数,并且我希望以最干净/最短的方式执行此操作。

例如:

sp() {
    echo "hello world"
}
echo `sp`         # two arguments to echo, BAD
echo $(sp)        # two arguments to echo, BAD
echo "$(sp)"      # one argument to echo, GOOD, but this takes a lot of characters

有没有更短/更清洁的方式来实现我想做的事情?我正在寻找更容易打字的东西(4个额外的字符很多)。也许某些功能不属于sh,但可能是bashzsh?这听起来很糟糕,但因为这会被输入到一个交互式会话中,所以也许某种方式可以挂钩到shell并在执行之前修改命令行?

3 个答案:

答案 0 :(得分:3)

zsh会做你想要的开箱即用 - 在zsh中,foo $bar默认将$bar的扩展视为单个参数,而不是字符串拆分和glob - 扩展,除非它是双引号。

也就是说,这样做会违反POSIX sh标准,你应该警惕学习坏习惯:我个人使用zsh,直到我发现在尝试为其他shell编写脚本时它让我变得草率。

答案 1 :(得分:2)

  

我希望能够调用该函数并将内容解释为单个参数,并且我希望以最干净/最短的方式执行此操作。

最简洁和最简短的方法是将参数括在引号中以防止word splitting和可能的pathname expansion (now named filename expansion in 4.3)但是如果您只计划在Zsh或Bash上运行脚本,则会有解决方法。

在Bash中,您只需使用IFS=禁用分词即可。您还可以使用shopt -s -o noglobset -f停用路径名扩展。通过合理的应用程序,如果他们知道自己正在做什么,这对高级脚本编写者来说实际上是一种很好的做法。

当然,如果禁用了单词拆分,则您无法再执行for x in $something; do。但这无关紧要,因为除非禁用路径名扩展,否则这种形式不值得称道。但是,您可以使用IFS=<separators> read -rd '' -a array <<< "$something"; for x in "${array[@]}"; do作为更好的选择。

禁用路径名扩展后,您仍然可以使用compgen(同时适用extglobdotglob):

readarray -t files < <(compgen -G '*')

或者

IFS='\n' read -rd ''  -a files < <(compgen -G '*')

但保守党人会说,对于带有换行符的文件名来说,这并不完美。所以你可以使用生成器函数:

function generate {
    local RESTORE=$(shopt -p -o noglob) IFS=
    shopt -u -o noglob
    __=($1)
    eval "$RESTORE"
}

generate '*'

for file in "${__[@]}"; do
    :
done

如果您不经常进行路径名扩展,这很好。

还有最后一件事:"$*""${var[*]}"将不再以空格作为分隔符展开。因此,在拥有自定义分隔符时,使用eval

可以轻松地将数组合并到字符串中
IFS=' ' eval 'merged="${var[*]}"'

所有这些都可以通过在脚本开头插入规则来安全地完成。

[ -n "$BASH_VERSION" ] || exit  ## You may use a block instead and insert a message if you like.
[[ BASH_VERSINFO -ge 4 ]] || exit  ## If you need `readarray` or other 4.0+ stuffs.
IFS=
shopt -s -o noglob

通过它,您现在可以安全地使用do_something $x

现在观看这些想法如何在以后构建在线wiki;)

就像我说的,这是针对高级用户的。那些非常关心晋升并谴责可能误导新手的人可能不会想要这个。正如明确指出的那样,如果你有相反的方法或感知,请远离这个。无需用“明显”的评论来抨击。

答案 2 :(得分:1)

由于这是交互式使用,也许您可​​以使用辅助功能为您进行报价。类似的东西:

$ func() { for arg; do echo "arg: $arg"; done; }
$ q() { cmd=$1; shift; $cmd "$*"; }
$ sp() { echo hello world; }
$ f="$(sp)"
$ echo $f
hello world
$ func $f
arg: hello
arg: world
$ q func $f
arg: hello world
$ q func `sp`
arg: hello world