Scripting

檢查命令是否是 ksh 中的內置命令

  • May 28, 2021

如何檢查命令是否是內置命令ksh

tcsh你可以使用where; 在中zshbash您可以使用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 -avinksh88嗎?


解決方案

使用接受的答案(打開子shell),這是我更新的解決方案。將以下內容放在 .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 對此進行了測試。

如果您擔心別名,只需執行以下操作:

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

$(...)創建一個子shell環境,所以unalias只在那裡有效)。

如果你也關心函式,也可以執行command unset -f -- "$cmd"before type

我擔心您可能會浪費時間來實現它;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命令是內置命令,因此您在程式碼中排除此特定內置命令的測試似乎不正確。

引用自:https://unix.stackexchange.com/questions/200639