即使使用 shopt Expand_aliases,bash 别名也不会扩展

即使使用 shopt Expand_aliases,bash 别名也不会扩展

我想在构造内运行别名bash -c

bash手动的说:

当 shell 非交互式时,别名不会扩展,除非expand_aliases使用 shell 选项设置shopt

hi在这个例子中,为什么显式设置时找不到别名expand_aliases

% bash -O expand_aliases -c "alias hi='echo hello'; alias; shopt expand_aliases; hi"
alias hi='echo hello'
expand_aliases  on
bash: hi: command not found

我在跑GNU bash, version 5.0.0(1)-release (x86_64-pc-linux-gnu)

上下文:我希望能够以空闲优先级运行别名,例如包含以下内容的脚本:

#!/bin/bash
exec chrt -i 0 nice -n 19 ionice -c 3 bash -c ". ~/.config/bash/aliases; shopt -s expand_aliases; $(shell-quote "$@")"

我想避免使用,bash -i因为我不希望我的内容.bashrc被阅读。

答案1

如果您将别名设置在所使用的同一行上,这似乎不起作用。可能与在实际解析阶段之前的命令行处理早期如何扩展别名有关。在交互式 shell 上:

$ alias foo
bash: alias: foo: not found
$ alias foo='echo foo'; foo         # 2 
bash: foo: command not found
$ alias foo='echo bar'; foo         # 3
foo
$ foo
bar

请注意,所使用的别名晚了一行:在第二个命令中,它找不到刚刚设置的别名,而在第三个命令中,它使用之前设置的别名。

因此,如果我们在字符串中添加换行符,它就会起作用-c

$ bash -c $'shopt -s expand_aliases; alias foo="echo foo";\n foo'
foo

(您也可以使用bash -O expand_aliases -c ...而不是shopt在脚本中使用,但这并不是说它有助于换行。)

或者,您可以使用 shell 函数而不是别名,它们在其他方面也更好:

$ bash -c 'foo() { echo foo; }; foo'
foo

答案2

按照 ilkkachu 的建议,将我的评论转化为答案。

Bash 手册(问题中链接到)确实提供了当同一行上有别名定义和命令时如何处理别名的解释。

引用(为了清晰起见,稍微格式化):

有关别名的定义和使用的规则有些令人困惑。在执行该行或复合命令上的任何命令之前,Bash 始终读取至少一个完整的输入行以及构成复合命令的所有行。

别名在读取命令时展开,而不是在执行命令时展开。因此,与另一个命令出现在同一行的别名定义在读取下一行输入之前不会生效。该行上别名定义后面的命令不受新别名的影响。

执行函数时,此行为也是一个问题。别名在读取函数定义时展开,而不是在执行函数时展开,因为函数定义本身就是一个命令。因此,函数中定义的别名只有在执行该函数之后才可用。

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

ilkkachu 的回答为这个问题提供了多种可能的解决方案。

相关内容