shell函数定义有和没有关键字

Fuo*_*oco 2 bash shell zsh

我花了很长时间才发现以下shell脚本不起作用的原因:

if command -v z > /dev/null 2>&1; then
    unalias z 2> /dev/null

    z() {
        [ $# -gt 0 ] && _z "$*" && return
            cd "$(_z -l 2>&1 |
                fzf --height 40% --nth 2.. --reverse --inline-info +s --tac \
                --query "${*##-* }" |
                sed 's/^[0-9,.]* *//')"
    }
fi
Run Code Online (Sandbox Code Playgroud)

是函数定义,在这种情况下,需要函数关键字,function z() {...}.没有它,我得到:

~/.shell/functions:112: defining function based on alias `z'
~/.shell/functions:112: parse error near `()'
Run Code Online (Sandbox Code Playgroud)

我找不到任何说明function在函数定义中使用或不使用关键字之间的任何区别.在这种情况下,为什么这是解决方案?(我试过zsh和bash)

Pes*_*The 6

来自Bash参考手册:

读取命令时会扩展别名,而不会在执行时扩展别名.

z因此在if读取语句时扩展,而不是在执行时扩展.所以即使你unalias,别名已经在你的if陈述z() ...中扩展(即扩展).

添加function帮助,因为只有在将别名用作第一个单词时才会扩展别名.如果添加function到函数声明中,则不会扩展任何内容.


检查此代码,该代码演示了复合命令中别名的行为:

#!/usr/bin/env bash

shopt -s expand_aliases
alias greet='echo hello'

if true; then
    unalias greet 2> /dev/null

    #still outputs hello!
    greet  
    #not first word, outputs greet
    echo greet                                  
fi

#error!
greet
Run Code Online (Sandbox Code Playgroud)

此代码段显示别名foo在执行之前确实已展开.因此,有一个名为bar声明的函数,而不是 foo:

$ alias foo='bar'
$ foo() { echo hello; }
$ declare -f foo
$ declare -f bar
bar () 
{ 
    echo hello
}

#declaring with 'function' keyword will work as expected
$ function foo { echo hi; }
$ declare -f foo 
foo () 
{ 
    echo hi
} 
Run Code Online (Sandbox Code Playgroud)

Bash参考手册更详细地解释了别名的行为,并建议如下:

为安全起见,请始终将别名定义放在单独的行中,并且不要在复合命令中使用别名.