这不是我在实际应用中所做的全部,但归结为:
我有一个函数返回带有空格的东西。我希望能够调用该函数并将内容解释为单个参数,并且我希望以最干净/最短的方式执行此操作。
例如:
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
,但可能是bash
或zsh
?这听起来很糟糕,但因为这会被输入到一个交互式会话中,所以也许某种方式可以挂钩到shell并在执行之前修改命令行?
答案 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 noglob
或set -f
停用路径名扩展。通过合理的应用程序,如果他们知道自己正在做什么,这对高级脚本编写者来说实际上是一种很好的做法。
当然,如果禁用了单词拆分,则您无法再执行for x in $something; do
。但这无关紧要,因为除非禁用路径名扩展,否则这种形式不值得称道。但是,您可以使用IFS=<separators> read -rd '' -a array <<< "$something"; for x in "${array[@]}"; do
作为更好的选择。
禁用路径名扩展后,您仍然可以使用compgen
(同时适用extglob
和dotglob
):
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