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

时间:2017-12-29 13:10:15

标签: 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

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

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

我无法找到在功能定义中使用或不使用function关键字之间存在任何差异的地方。在这种情况下,为什么这是解决方案? (我在zsh和bash中尝试过)

2 个答案:

答案 0 :(得分:6)

来自Bash Reference Manual

  

在读取命令时扩展别名,而不是在执行命令时扩展别名。

因此,{p> 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

此代码段显示别名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
} 

Bash Reference Manual更详细地解释了别名的行为,并建议如下:

  

为了安全起见,请始终将别名定义放在单独的行上,并执行此操作   不要在复合命令中使用别名。

答案 1 :(得分:0)

手册页(man bash)声明“保留字功能是可选的。”:

Shell函数定义        shell函数是一个被称为简单命令的对象,它使用一组新的位置参数执行复合命令。 Shell函数声明如下:

   name () compound-command [redirection]
   function name [()] compound-command [redirection]
          This  defines a function named name.  **The reserved word function is optional.**  If the function reserved word is supplied, the parentheses are optional.