简体   繁体   中英

shell function definition with and without keyword

It took me forever to find out that the reason the following piece of shell script doesn't work:

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

is that the function definition, in this case, requires the function keyword, function z() {...} . Without it I get:

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

I couldn't find anywhere that says there is any difference between using or not using the function keyword in a function definition. Why is that the solution in this case? (I tried in zsh and in bash)

From Bash Reference Manual :

Aliases are expanded when a command is read, not when it is executed.

z is therefore expanded when the if statement is read, not when it is executed. So even if you unalias , the aliases are already expanded in your if statement (namely z() ... is expanded).

Adding function helps because aliases are expanded only when they are used as the first word. If you add function to your function declaration, nothing gets expanded.


Check this code that demonstrates the behavior of aliases inside a compound command:

#!/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

This snippet shows that the alias foo really gets expanded before execution. As a result, there is a function called bar declared, not 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 explains the behavior of aliases in further detail and recommends the following:

To be safe, always put alias definitions on a separate line, and do not use alias in compound commands.

Man page (man bash) states "The reserved word function is optional.":

Shell Function Definitions A shell function is an object that is called like a simple command and executes a compound command with a new set of positional parameters. Shell functions are declared as follows:

   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.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM