检查命令是否是 ksh 中的内置命令

检查命令是否是 ksh 中的内置命令

如何检查命令是否是内置命令ksh

tcsh你可以使用where;在zsh并且bash你可以使用type -a;并且在一些现代的ksh您可以使用的版本whence -av

我想要做的是编写一个isbuiltin可以在任何版本ksh(包括ksh88任何其他“旧”版本ksh)中工作的函数,其行为如下:

  1. 接受多个参数并检查每个参数是否是内置的
  2. 0如果所有给定的命令都是内置的,则返回(成功)
  3. 在第一个非内置命令处,停止检查,返回1(失败),并向 stderr 打印一条消息。

我已经有这样的工作功能zshbash使用上述命令。

这就是我的目的ksh

isbuiltin() {
  if [[ "$#" -eq 0 ]]; then
    echo "Usage: isbuiltin cmd" >&2
    return 1
  fi
  for cmd in "$@"
  do
    if [[ $cmd = "builtin" ]]; then
      #Handle the case of `builtin builtin`
      echo "$cmd is not a built-in" >&2
      return 1
    fi
    if ! whence -a "$cmd" 2> /dev/null | grep 'builtin' > /dev/null ; then
      echo "$cmd is not a built-in" >&2
      return 1
    fi
  done
}

此功能适用于 ksh93。然而,ksh88 的版本似乎whence不支持该-a选项,该选项是使其显示所有出现的选项。由于无法显示所有出现的情况,我只能使用whence -v告诉我命令是否是内置的,但前提是不存在同名的别名或函数。

问题:我可以用其他东西来代替whence -avin吗ksh88


解决方案

使用已接受的答案(打开子外壳),这是我更新的解决方案。将以下内容放入 .kshrc 中:

isbuiltin() {
  if [[ "$#" -eq 0 ]]; then
    printf "Usage: isbuiltin cmd\n" >&2
    return 1
  fi
  for cmd in "$@"
  do
    if (
         #Open a subshell so that aliases and functions can be safely removed,
         #  allowing `whence -v` to see the built-in command if there is one.
         unalias "$cmd";
         if [[ "$cmd" != '.' ]] && typeset -f | egrep "^(function *$cmd|$cmd\(\))" > /dev/null 2>&1
         then
           #Remove the function iff it exists.
           #Since `unset` is a special built-in, the subshell dies if it fails
           unset -f "$cmd";
         fi
         PATH='/no';
         #NOTE: we can't use `whence -a` because it's not supported in older versions of ksh
         whence -v "$cmd" 2>&1
       ) 2> /dev/null | grep -v 'not found' | grep 'builtin' > /dev/null 2>&1
    then
      #No-op.  Needed to support some old versions of ksh
      :
    else
      printf "$cmd is not a built-in\n" >&2
      return 1
    fi
  done
  return 0
}

我已经在 Solaris、AIX 和 HP-UX 中使用 ksh88 对此进行了测试。它适用于我测试的所有情况。我还在 FreeBSD、Ubuntu、Fedora 和 Debian 中使用现代版本的 ksh 对此进行了测试。

答案1

如果您担心的是别名,只需执行以下操作:

[[ $(unalias -- "$cmd"; type -- "$cmd") = *builtin ]]

$(...)创建一个子shell环境,因此unalias仅在那里有效)。

如果您还关心函数,也可以运行command unset -f -- "$cmd"before type

答案2

我担心你可能会浪费时间来实现这一点;ksh93支持该builtin命令。例如ksh version 93t 2008-11-04

$ builtin
...creates list of all builtins

$ builtin jobs umask
...returns with exit code 0

$ builtin jobs time umask
...returns with exit code 1 and prints "builtin: time: not found"


另请注意,该builtin命令是内置命令,因此您在代码中排除此特定内置命令的测试似乎不正确。

答案3

#! /bin/sh

path_to_your_command=$(command -v your_command)

if [ "${path_to_your_command}" = 'your_command' ]; then
  echo 'your_command is a special builtin.'
else
  if [ -n "${path_to_your_command}" ]; then
    echo "your_command is a regular builtin, located at ${path_to_your_command}."
  else
    echo "your_command is not a builtin (and/or does not exist as it cannot be found in \$PATH)."
  fi
fi

相关内容