在Bash中,这个用连字符风格命名的函数如何实现无限调用?
我可以在 bash 中像下面这样运行这段代码
#: can works well:
#: (start a new bash)
foo_a () { echo a ; }
foo-a () { foo_a ; }
echo will out a:
foo_a
运行起来效果很好。
这些也同样有效:
#: can works well:
#: (start a new bash)
foo_a () { echo a ; }
foo-a () { foo_a ; }
alias foo-a=foo_a
echo will out a:
foo_a
#: can works well:
#: (start a new bash)
foo_a () { echo a ; }
alias foo-a=foo_a
function foo-a () { foo_a ; }
echo will out a:
foo_a
因此我们可以知道,foo-a () { foo_a ; } 和 function foo-a () { foo_a ; } 都可以在Bash中定义一个名为 foo-a 的函数。
但这些并不能正确工作:
#: will broke the terminal window or always in blocking:
#: (start a new bash)
foo_a () { echo a ; }
alias foo-a=foo_a
foo-a () { foo_a ; }
echo boom here:
foo_a
#: will broke the terminal window or always in blocking:
#: (start a new bash)
foo_a () { echo a ; }
alias foo-a=foo_a
foo-a () { foo_a ; }
function foo-a () { foo_a ; }
echo boom here:
foo_a
#: will broke the terminal window or always in blocking:
#: (start a new bash)
foo_a () ( echo a )
alias foo-a=foo_a
foo-a () { foo_a ; }
echo boom here:
foo_a
#: will spawn too much bash sub-process to fill your memory:
#: (start a new bash)
foo_a () { echo a ; }
alias foo-a=foo_a
foo-a () ( foo_a )
echo spawn here:
foo_a
只需在 foo-a 之前添加 function,
#: can works well:
#: (start a new bash)
foo_a () { echo a ; }
alias foo-a=foo_a
function foo-a () ( foo_a )
echo will out a:
foo_a
或者让 alias foo-a=foo_a 出现在 foo-a 的定义之后,也可以再次正常工作。
只有在一个 alias foo-a=foo_a 出现在 foo-a 的定义之前,且没有 function 提示时,问题才会发生:出现堆栈溢出或创建大量Bash子进程;这是否会创建子进程,取决于 foo-a 的定义。
所以,我的问题是:
- 这种现象(也就是生成大量子进程之类的情况)是一个 bug 还是一个 feature?
- 它是如何发生的?
我猜这问题/现象的关键在于 foo-a 的定义,问题在于它会在普通函数调用时陷入无限执行(原因我也不知道为什么),并且这种关系看起来像是由一个预定义的别名构成(我也不知道为什么别名会在这里产生影响)。
我用来测试的Bash版本:
GNU bash, version 5.1.4(1)-release (x86_64-pc-linux-gnu)GNU bash, version 5.2.37(1)-release (x86_64-pc-msys)
并且,我也在 brush-shell-v0.4.0 上测试过,它won't 会带来任何问题——上述提到的所有情况在 brush 中都能正常工作。
解决方案
命令中的第一个单词总是会被展开为别名。即使它处在函数定义的开头,这一点也成立。因此,当你这样做时
alias foo-a=foo_a
foo-a () { foo_a ; }
就等价于
alias foo-a=foo_a
foo_a () { foo_a ; }
因为别名会替换函数名。这显然会造成无限递归,函数无条件地调用自身。
如果把别名定义在函数之后,就不会出现同样的问题,因为函数名不会被改变。并且如果你使用 function 命令来定义函数,别名就不是第一个单词,因此不会被展开;不过,这种语法并非可移植的,这是一个 bash 的扩展。
站内所有文章版权归属LeftHeroAI导航站,无授权禁止任何主体转载、抄袭、复制内容,亦不得私自架设镜像站点。一经侵权,本站将通过法律途径追责。