问题描述
我知道我可以使用\
或""
来运行“原始”命令(不是别名):
\ls
"ls"
但这不适用于功能。另外,它要求我每次都使用该语法。
是否可以在源脚本中禁用父进程(运行我的脚本的一个)的所有功能/别名?即如果终端中的用户定义了一些别名功能,我希望在脚本中将其禁用(但我当然仍然希望能够定义和使用自己的别名/功能)。
解决方法
Bash中的命令类型
Bash知道可以互为阴影的不同类型的命令。这些类型的优先级是:
- 别名
可以由用户使用alias cmd=...
来定义
- 功能
可以由用户使用cmd() { ... }
来定义
- 内置插件
是直接在bash中实现的,不能更改。help
和enable
列出所有内置插件。 -
$PATH
中的可执行文件
意思是如果您输入cmd arg1 arg2 ...
,则使用别名cmd
(如果已定义);否则,则使用函数cmd
(如果已定义);否则,请使用内置的{{ 1}}(如果它是内置的),否则使用cmd
中的目录中的第一个可执行文件cmd
(如果存在的话),否则将出现错误$PATH
。>
可以使用-bash: cmd command not found
来检查其中哪些情况适用于cmd
。
手动优先控制
Bash允许您使用引号以及内置的type -a cmd
和command
来影响选择哪种类型。
-
builtin
禁止使用别名
使用函数,内置函数,可执行文件 -
\cmd
禁止使用别名和功能
使用内置和可执行文件 -
command cmd
禁止别名,函数和可执行文件
仅使用内置 -
builtin cmd
完全禁用内置enable -n cmd
,以便仅在之后禁用
使用别名,函数和可执行文件 -
cmd
不是内置的bash,因此除了
仅使用可执行文件
示例
阴影完全正常。例如,bash具有自己的内置env cmd
,但是您的系统也具有echo
。两种实现方式可能不同。例如,我的bash 5中的/bin/echo
支持echo
,但是我的GNU coreutils 8.3中的\uXXXX
不支持。如果您使用别名和函数添加自己的实现,则这种差异的可能性变得更加明显。这是一个交互式bash会话中的示例(提示是echo
)
$
回答您的问题
不幸的是,我不知道像$ echo() { printf "function echo: %s\n" "$*"; }
$ alias echo='printf "alias echo: %s %s %s\n"'
$ type -a echo
echo is aliased to `printf "alias echo: %s %s %s\n"'
echo is a function
echo ()
{
printf "function echo: %s\n" "$*"
}
echo is a shell builtin
echo is /bin/echo
$ echo -e '\u2261'
alias echo: -e \u2261
$ \echo -e '\u2261'
function echo: -e \u2261
# use the built-in (or executable file if there was no such built-in)
$ command echo -e '\u2261'
≡
$ builtin echo -e '\u2261'
≡
# use the executable /bin/echo
$ env echo -e '\u2261'
\u2261
$ enable -n echo
# use the executable /bin/echo (`command` is needed to skip the alias and function)
$ command echo -e '\u2261'
\u2261
这样的东西来永久禁用别名和函数查找。您可以尝试一些技巧,例如备份所有别名和函数,对它们进行enable
和unset -f
,最后进行还原。但是,unalias
对于只读功能可能会失败。更好的方法是将unset
用于您确实不需要bash -c '... functions and aliases have no effect here ...'
好处的部分。对于其他部分,请在所有内容前加上source
。
请注意:发出脚本的调用者甚至可能禁用或隐藏command
,command
等,因此您永远无法确定自己是实际使用您期望的命令。即使编写builtin
或/usr/bin/env executable
也无济于事,因为函数可以使用名称和/path/to/the/executable
或可以更改文件系统。
但是,这不应该是您的问题。源于您脚本的人应该负责提供正确的环境。
编辑:此答案可能不再相关,因为您已编辑问题以阐明脚本是源程序,而不是在子shell中执行。
默认情况下会发生这种情况。证明:
$ function x() { echo 'hi'; }
$ x
hi
$ bash
# We are now in a subshell.
$ x
bash: x: command not found
功能通常是在Shell的启动文件之一中定义的:.bashrc
,.profile
或.bash_profile
。这些源中的哪一个取决于外壳是 login 外壳和/还是 interactive 外壳。调用执行外壳脚本的外壳既不是登录外壳也不是交互式外壳,在这种情况下,这些文件都不是源文件。
编辑:我应该更仔细地阅读,因为您不想获取脚本,但是希望获取脚本,以下是相反的方法:
功能
如果您一开始就获取父脚本,则可以循环浏览已定义的函数并取消设置它们。
declare -F
将列出所有已定义的函数,但格式为declare -f functioname
,因此您仅需获得名称:
IFS=$'\n'
for f in $(declare -F|cut -d ' ' -f 3); do
unset -f $f
done
别名
我不记得应该使用别名,但是如果存在别名,您可以这样做
unalias -a
全部取消设置。