Verificando se um comando é embutido no ksh

5

Como posso verificar se um comando é um comando interno para ksh ?

Em tcsh você pode usar where ; em zsh e bash você pode usar type -a ; e em algumas versões modernas de ksh você pode usar whence -av .

O que eu quero fazer é escrever uma função isbuiltin que funcione em qualquer versão de ksh (incluindo ksh88 e qualquer outra versão "antiga" de ksh ) que se comporte assim:

  1. Aceite vários argumentos e verifique se cada um deles está integrado
  2. Retornar 0 (sucesso) se todos os comandos fornecidos estiverem incorporados
  3. No primeiro comando não interno, interrompa a verificação, retorne 1 (falha) e imprima uma mensagem para stderr.

Já tenho funções de trabalho como esta para zsh e bash usando os comandos mencionados acima.

Aqui está o que eu tenho para 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
}

Esta função funciona para o ksh93. No entanto, parece que a versão do whence do ksh88 não suporta a opção -a , que é a opção para mostrar todas as ocorrências. Sem a capacidade de exibir todas as ocorrências, só posso usar whence -v , o que faz dizer se um comando é interno, mas somente se não houver também um alias ou função de mesmo nome .

Pergunta: há mais alguma coisa que eu possa usar no lugar de whence -av em ksh88 ?

Solução

Usando a resposta aceita (abrindo um subshell), aqui está minha solução atualizada. Coloque o seguinte em .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
}

Eu testei isso com o ksh88 no Solaris, AIX e HP-UX. Ele funciona em todos os casos que testei. Eu também testei isso com as versões modernas do ksh no FreeBSD, Ubuntu, Fedora e Debian.

    
por Sildoreth 05.05.2015 / 20:58

2 respostas

5

Se sua preocupação for sobre aliases, faça:

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

( $(...) cria um ambiente de subshell, então unalias só está em vigor lá).

Se você também está preocupado com as funções, também execute command unset -f -- "$cmd" antes de type .

    
por 05.05.2015 / 22:33
0

Eu temo que você tenha perdido seu tempo implementando isso; ksh93 suporta o comando builtin . Por exemplo. com 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"


Note também que o comando builtin é embutido, portanto, o teste que você tem em seu código para excluir este código específico parece estar incorreto.

    
por 05.05.2015 / 21:58