Bash 在别名、函数、二进制文件中的搜索顺序
Bash search order among aliases, functions, binaries
function mycmd { echo 'function'; }
# After defining the alias, the function stops being visible, even if redefined.
alias mycmd="echo 'alias'"
# Yet if a binary is found in $PATH, it hides both.
echo "#!/usr/bin/env bash" > mycmd
echo "echo 'file'" >> mycmd
chmod +x mycmd
export PATH=$(pwd):"$PATH"
这些观察是否正确可靠?这种影子规则的预期好处是什么?
据我所知man bash
中没有任何地方说明优先级规则,但手册中的类型列表是根据优先级:
type [-aftpP] name [name ...]
With no options, indicate how each name would be interpreted if
used as a command name. If the -t option is used, type prints a
string which is one of alias, keyword, function, builtin, or
file if name is an alias, shell reserved word, function,
builtin, or disk file, respectively. […]
重要的部分是:
alias, shell reserved word, function, builtin, or disk file
否 — 关于 PATH 上 script/binary 的观察是不正确的。
当别名生效时,脚本和函数实际上都是不可见的。请参阅 Bash 手册中的 Command search and execution and Aliases。
基本上,简单命令名称(名称中没有斜线)的顺序是,从头到尾:
- 别名
- 函数
- built-ins
- 外部可执行文件(通过 PATH 找到)
你可以用你的脚本改编来演示:
#!/bin/bash
function mycmd { echo "function: $*"; }
mycmd should be the function
# After defining the alias, the function stops being visible, even if redefined.
alias mycmd="echo 'alias'"
mycmd should be the alias
# Yet if a binary is found in $PATH, it hides both.
echo "#!/usr/bin/env bash" > mycmd
echo 'echo "file: $*"' >> mycmd
chmod +x mycmd
export PATH=$(pwd):"$PATH"
mycmd should still be the alias
unalias mycmd
mycmd should be the function once more
unset -f mycmd
mycmd should finally be the file
我已经修改了脚本和函数以回显命令的任何参数(并且在这种情况下使用 $*
而不是 "$@"
是合适的,尽管肯定可以编写代码以使用 "$@"
代替)。
示例输出(脚本 so43.sh
):
$ bash so43.sh
function: should be the function
function: should be the alias
function: should still be the alias
function: should be the function once more
file: should finally be the file
$
为什么是这个函数?好问题!默认情况下,别名在脚本中不起作用。他们确实以交互方式工作。当我复制我的脚本(减去 shebang)并将其粘贴到我的终端时,我得到了这个输出(其中 Scafell-Pike JL:
是我的提示):
Scafell-Pike JL: function mycmd { echo "function: $*"; }
Scafell-Pike JL:
Scafell-Pike JL: mycmd should be the function
function: should be the function
Scafell-Pike JL:
Scafell-Pike JL: # After defining the alias, the function stops being visible, even if redefined.
Scafell-Pike JL: alias mycmd="echo 'alias'"
Scafell-Pike JL:
Scafell-Pike JL: mycmd should be the alias
alias should be the alias
Scafell-Pike JL:
Scafell-Pike JL: # Yet if a binary is found in $PATH, it hides both.
Scafell-Pike JL: echo "#!/usr/bin/env bash" > mycmd
Scafell-Pike JL: echo 'echo "file: $*"' >> mycmd
Scafell-Pike JL: chmod +x mycmd
Scafell-Pike JL: export PATH=$(pwd):"$PATH"
Scafell-Pike JL:
Scafell-Pike JL: mycmd should still be the alias
alias should still be the alias
Scafell-Pike JL:
Scafell-Pike JL: unalias mycmd
Scafell-Pike JL:
Scafell-Pike JL: mycmd should be the function once more
function: should be the function once more
Scafell-Pike JL:
Scafell-Pike JL: unset -f mycmd
Scafell-Pike JL:
Scafell-Pike JL: mycmd should finally be the file
file: should finally be the file
Scafell-Pike JL:
现在您可以看到别名在起作用了。
手册中关于别名的部分(在顶部附近引用)说:
Aliases are not expanded when the shell is not interactive, unless the expand_aliases
shell option is set using shopt
(see The Shopt Builtin).
在脚本顶部添加 shopt -s expand_aliases
并重新运行产量:
$ bash so43.sh
function: should be the function
alias should be the alias
alias should still be the alias
function: should be the function once more
file: should finally be the file
$
function mycmd { echo 'function'; }
# After defining the alias, the function stops being visible, even if redefined.
alias mycmd="echo 'alias'"
# Yet if a binary is found in $PATH, it hides both.
echo "#!/usr/bin/env bash" > mycmd
echo "echo 'file'" >> mycmd
chmod +x mycmd
export PATH=$(pwd):"$PATH"
这些观察是否正确可靠?这种影子规则的预期好处是什么?
据我所知man bash
中没有任何地方说明优先级规则,但手册中的类型列表是根据优先级:
type [-aftpP] name [name ...] With no options, indicate how each name would be interpreted if used as a command name. If the -t option is used, type prints a string which is one of alias, keyword, function, builtin, or file if name is an alias, shell reserved word, function, builtin, or disk file, respectively. […]
重要的部分是:
alias, shell reserved word, function, builtin, or disk file
否 — 关于 PATH 上 script/binary 的观察是不正确的。
当别名生效时,脚本和函数实际上都是不可见的。请参阅 Bash 手册中的 Command search and execution and Aliases。
基本上,简单命令名称(名称中没有斜线)的顺序是,从头到尾:
- 别名
- 函数
- built-ins
- 外部可执行文件(通过 PATH 找到)
你可以用你的脚本改编来演示:
#!/bin/bash
function mycmd { echo "function: $*"; }
mycmd should be the function
# After defining the alias, the function stops being visible, even if redefined.
alias mycmd="echo 'alias'"
mycmd should be the alias
# Yet if a binary is found in $PATH, it hides both.
echo "#!/usr/bin/env bash" > mycmd
echo 'echo "file: $*"' >> mycmd
chmod +x mycmd
export PATH=$(pwd):"$PATH"
mycmd should still be the alias
unalias mycmd
mycmd should be the function once more
unset -f mycmd
mycmd should finally be the file
我已经修改了脚本和函数以回显命令的任何参数(并且在这种情况下使用 $*
而不是 "$@"
是合适的,尽管肯定可以编写代码以使用 "$@"
代替)。
示例输出(脚本 so43.sh
):
$ bash so43.sh
function: should be the function
function: should be the alias
function: should still be the alias
function: should be the function once more
file: should finally be the file
$
为什么是这个函数?好问题!默认情况下,别名在脚本中不起作用。他们确实以交互方式工作。当我复制我的脚本(减去 shebang)并将其粘贴到我的终端时,我得到了这个输出(其中 Scafell-Pike JL:
是我的提示):
Scafell-Pike JL: function mycmd { echo "function: $*"; }
Scafell-Pike JL:
Scafell-Pike JL: mycmd should be the function
function: should be the function
Scafell-Pike JL:
Scafell-Pike JL: # After defining the alias, the function stops being visible, even if redefined.
Scafell-Pike JL: alias mycmd="echo 'alias'"
Scafell-Pike JL:
Scafell-Pike JL: mycmd should be the alias
alias should be the alias
Scafell-Pike JL:
Scafell-Pike JL: # Yet if a binary is found in $PATH, it hides both.
Scafell-Pike JL: echo "#!/usr/bin/env bash" > mycmd
Scafell-Pike JL: echo 'echo "file: $*"' >> mycmd
Scafell-Pike JL: chmod +x mycmd
Scafell-Pike JL: export PATH=$(pwd):"$PATH"
Scafell-Pike JL:
Scafell-Pike JL: mycmd should still be the alias
alias should still be the alias
Scafell-Pike JL:
Scafell-Pike JL: unalias mycmd
Scafell-Pike JL:
Scafell-Pike JL: mycmd should be the function once more
function: should be the function once more
Scafell-Pike JL:
Scafell-Pike JL: unset -f mycmd
Scafell-Pike JL:
Scafell-Pike JL: mycmd should finally be the file
file: should finally be the file
Scafell-Pike JL:
现在您可以看到别名在起作用了。
手册中关于别名的部分(在顶部附近引用)说:
Aliases are not expanded when the shell is not interactive, unless the
expand_aliases
shell option is set usingshopt
(see The Shopt Builtin).
在脚本顶部添加 shopt -s expand_aliases
并重新运行产量:
$ bash so43.sh
function: should be the function
alias should be the alias
alias should still be the alias
function: should be the function once more
file: should finally be the file
$