有没有办法设置 bash 以便它执行任何带有扩展名的文件.sh
,例如mycommand.sh
,只需键入mycommand
,就像在 Windows 中mycommand.bat
只需键入mycommand
?即可执行一样。
我已经使用chmod +x
并将包含的目录放在mycommand.sh
中PATH
,因此无需说明这些内容。
一种显而易见的方法是重命名mycommand.sh
为mycommand
。我不想这样做。一些第三方产品(例如 Kafka 和一些数据库系统)提供的 shell 脚本都有扩展名.sh
,我不想重命名不属于我的东西。
我特别想问的是是否可以制作.sh
某种“已知”的可执行扩展,类似于 Windows 的PATHEXT
环境变量。
答案1
Bash 为您提供了一种定义自己的“未找到命令”处理程序的方法:
如果名称既不是 shell 函数也不是内置函数,并且不包含斜杠,Bash 会在 的每个元素中搜索
$PATH
包含该名称的可执行文件的目录。[…] 如果搜索不成功,shell 会搜索名为 的已定义 shell 函数command_not_found_handle
。如果该函数存在,则会在单独的执行环境中调用它,并使用原始命令和原始命令的参数作为其参数,并且该函数的退出状态将成为该子 shell 的退出状态。如果该函数未定义,shell 会打印错误消息并返回退出状态127
。
(来源)
这是一个可以解决您的问题的基本处理程序:
command_not_found_handle () {
unset -f command_not_found_handle
cmmnd="$1".sh
shift
exec "$cmmnd" "$@"
}
定义此函数后,如果您尝试运行mycommand
但未找到命令,则 shell 将尝试使用应该获取的mycommand.sh
所有命令行参数。mycommand
笔记:
- 其他 shell 可能提供类似的功能。
unset
如果找不到新命令,则阻止处理程序再次触发自身。- 您可能已经定义了一些处理程序。例如,在 Debian 中,软件包
command-not-found
依赖于其处理程序。如果您只是定义自己的处理程序,您将失去它。要保留旧功能,您需要模仿(或恢复)旧处理程序并在未找到新命令后运行其代码(但要确保它有效地工作,就像它得到了原始命令一样,即mycommand
,不是mycommand.sh
)。旧处理程序可能看起来像这是我的另一个答案。
答案2
这是一个老问题,但它在我遇到这个问题时帮助了我,并且从那时起我对所选答案进行了改进,我认为值得分享。我的实现适用于所有可执行文件类型,而不仅仅是 .sh,并且当找不到命令时它不会弄乱错误消息:
command_not_found_handle() {
unset -f command_not_found_handle
found=false
# Iterate over possible autocompletions.
while IFS='' read -r cmmnd; do
# If the only thing that was autocompleted was the extension, execute it,
# but outside the loop because STDIN is redirected inside here.
if [[ "$cmmnd" == "$1".* ]]; then
found=true
break
fi
done < <(compgen -c -- "$1") # Generate possible autocompletions for the command.
$found && exec -- "$cmmnd" "${@:2}"
echo "bash: '$1': command not found" >&2
return 127
}