if 语句中 bash 函数定义的奇怪行为,语法为 foo(){} [duplicate]

Weird behavior of bash function definitions inside if statements with the foo(){} syntax [duplicate]

提问人:ychaouche 提问时间:12/22/2022 更新时间:12/22/2022 访问量:52

问:

让我们从一个有效的代码开始

$ cat foo1
#!/bin/bash


foo() { 
    echo "I'm here";
}
foo # prints: I'm here

$ ./foo1
I'm here
$ 

目前为止,一切都好。

现在我们来介绍一个语法错误

$ cat foo2
#!/bin/bash -i

alias foo="echo I am an alias"
foo() { 
    echo "I'm here";
}
foo # isn't reached

$ ./foo2
bash: ./foo2: line 4: syntax error near unexpected token `('
bash: ./foo2: line 4: `foo() { '
$

哎呀!让我们通过取消锯齿 FOO 来修复它。

$ cat foo3
#!/bin/bash -i

alias foo="echo I am an alias"
unalias foo
foo() {
    echo "I'm here";
}
foo # prints:

$ ./foo3
I'm here
$

如果我们添加一个 if 条件会发生什么?

$ cat foo4
#!/bin/bash -i

alias foo="echo I am an alias"
if true
then
    unalias foo
    foo() {
        echo "I'm here";
    }
fi
foo # prints:

$ ./foo4
bash: ./foo4: line 7: syntax error near unexpected token `('
bash: ./foo4: line 7: `    foo() { '
$

为什么?为什么它在 if 条件下失败,但过去在没有 if 条件的情况下工作?

如果我们使用语法而不是 ?function foo{}foo(){}

$ cat foo5
#!/bin/bash -i

alias foo="echo I am an alias"
if true
then
    unalias foo
    function foo {
        echo "I'm here";
    }
fi
foo # prints:

$ ./foo5
I'm here
$

它现在有效吗?

问:为什么 foo2 和 foo4 会断裂?

bash 函数 语法错误 别名

评论

0赞 Jetchisel 12/22/2022
对别名和函数使用不同的名称?

答:

4赞 glenn jackman 12/22/2022 #1
  1. 因为别名首先发生,所以函数定义变成这样(在 bash 替换别名之后:

    echo I am an alias() { 
        echo "I'm here";
    }
    

    这显然是一个语法错误。

  2. 别名仅在命令的第一个单词上替换。当您使用关键字来定义函数时,您就避免了别名扩展的可能性。function

这可能是在非交互式 shell 中默认关闭别名的原因之一。

评论

5赞 oguz ismail 12/22/2022
..foo4 中断,因为在复合命令中使用 alias/unalias 所做的更改在完成之前不会生效; 也不起作用if alias foo='echo a'; then foo; fi
0赞 ychaouche 12/22/2022
您@glenn建议使用关键字而不是使用 parens?function
1赞 ShadowRanger 12/22/2022
@ychaouche:不能接受格伦的建议,但是的,使用关键字。如您所见,它可以保护您免受无意中的别名冲突的影响。类似于当您想要确保运行可执行文件而不显式提供硬编码路径时,如何使用(或当您不信任用户的 )作为前缀来绕过 shell 函数(并且隐式别名,因为实际命令不再作为第一个单词出现)。 还可以更轻松地查找稍后定义的函数,而不是滚动和跳跃。functioncommandcommand -pPATHfunction
3赞 glenn jackman 12/23/2022
我的建议是停止在脚本中使用别名。请改用函数。
2赞 David 12/22/2022 #2

我只是添加参考,因为公认的答案(连同第一条评论)是正确的。
从手册页:
bash

       The  rules  concerning  the  definition and use of aliases are somewhat
       confusing.  Bash always reads at least one complete line of input,  and
       all  lines that make up a compound command, before executing any of the
       commands on that line or the compound command.   Aliases  are  expanded
       when  a  command is read, not when it is executed.  Therefore, an alias
       definition appearing on the same line as another command does not  take
       effect  until  the  next line of input is read.  The commands following
       the alias definition on that line are not affected by  the  new  alias.
       This  behavior  is  also an issue when functions are executed.  Aliases
       are expanded when a function definition is read, not when the  function
       is  executed,  because a function definition is itself a command.  As a
       consequence, aliases defined in a function are not available until  af‐
       ter  that  function  is executed.  To be safe, always put alias defini‐
       tions on a separate line, and do not use alias in compound commands.

魔鬼在细节中(f#*@!n' 手册)。