从 shell 脚本中捕获“找不到命令”

Phi*_*rly 7 shell-script command-not-found

我有一个 shell 脚本

echo "Type your command"
read command
echo "You typed $command"
$command
Run Code Online (Sandbox Code Playgroud)

所以它运行一个命令很简单。我的问题是如果输入是错误的,假设lw终端说,command not found那么我如何将这些信息检索到我的 shell 脚本并打印到终端Try again wrong command。我是否必须将命令的输出重定向到某个文件并读取或是否有任何类型的陷阱信号传递给我的脚本。这是您关于如何以最有效的方式执行此操作的建议。

Sté*_*las 8

当未找到命令时,退出状态为 127。您可以使用它来确定未找到命令:

until
  printf "Enter a command: "
  read command
  "$command"
  [ "$?" -ne 127 ]
do
  echo Try again
done
Run Code Online (Sandbox Code Playgroud)

虽然命令通常不会返回 127 退出状态(因为它会与 shell 使用的标准特殊值冲突),但在某些情况下,命令可能真正返回 127 退出状态:最后一个命令的脚本找不到。

bash并且zsh有一个特殊的command_not_found_handler函数(在bash's 中有一个拼写错误,因为它在command_not_found_handle那里被调用),当没有找到命令时,它会在定义时执行。但它是在子shell上下文中执行的,也可能在执行函数时未找到的命令上执行。

您可能会想使用typeor预先检查命令是否存在command -v,但请注意:

"$commands"
Run Code Online (Sandbox Code Playgroud)

被解析为一个简单的命令,别名不会被扩展,而typeorcommand也会为别名和 shell 关键字返回 true。

例如, with command=for,type -- "$command"将返回 true,但"$command"(最有可能)返回命令未找到错误。

which 可能会因为许多其他原因而失败。

理想情况下,如果命令作为函数、shell 内置命令或外部命令存在,则您希望返回 true 的内容。

hash至少会满足这些标准ashbash(不是yash也不kshzsh)。因此,这将适用于bashash

while
  printf "Enter a command: "
  read command
do
  if hash -- "$command" 2> /dev/null; then
    "$command"
    break
  fi
  echo Try again
done
Run Code Online (Sandbox Code Playgroud)

一个问题是hash对于目录(对于包含 a 的目录的路径)也返回 true /。而如果您尝试执行它,虽然它不会返回命令未找到错误,但它会返回一个Is a directoryPermission Denied错误。如果你想覆盖它,你可以这样做:

while
  printf "Enter a command: "
  read command
do
  if hash -- "$command" 2> /dev/null &&
     { [ "${command#*/}" != "$command" ] || [ ! -d "$command" ];}
  then
    "$command"
    break
  fi
  echo Try again
done
Run Code Online (Sandbox Code Playgroud)