A maneira mais direta e compreensível seria apenas um loop for
com um único if
s dentro dele, que break
s fora do loop quando encontrar uma correspondência.
Se você não quiser fazer isso, no Bash, type
aceita vários argumentos para pesquisar por:
type grealpath realpath ...
e a primeira palavra da linha de saída para uma entrada correspondente é sempre 1 o nome do comando / função / alias. Você pode capturar a saída padrão em uma matriz e indexá-la para evitar um subprocesso adicional:
words=($(type realpath grealpath foo make 2>/dev/null))
realpath_exec=${words[0]}
if ! [ "$realpath_exec" ] ...
De um certo ponto de vista, isso é elegante, mas é decididamente mais difícil de entender quando você se depara com isso.
A divisão de palavras em inicializadores de matriz depende do valor de IFS
. Se IFS
tiver sido alterado ou se algum dos seus comandos contiver um espaço, isso não funcionará.
1 Experimentalmente, este parece ser o caso em mais localidades, mesmo onde essa não é a ordem natural das palavras, e parece ser sempre uma U + 0020 ASCII espaço depois, mas o formato de saída não é mais especificado. Em algumas localizações, isso não funcionará; você precisa considerar se isso será um problema para você. Você pode usar LC_ALL=C type ...
para (mais ou menos) garantir um formato de saída adequado.
Em zsh , se você se importa apenas com executáveis, e não com funções ou aliases, você pode usar $commands
:
realpath_exec=${commands[grealpath]:-${commands[realpath]:-${commands[another]:?No compatible command found}}}
A expansão ${param:-...}
fornece o valor de param
, se não for nulo, e ...
, caso contrário; ${param:?...}
erros com ...
se param
falhar.
Isso continua bastante feio.
Se você não se importa com a ordenação entre a seleção de comandos, você pode usar uma versão mais simples com o (i) sinalizador subscrito :
realpath_exec=${commands[(i)realpath|grealpath|another]}
Para incluir funções e aliases também em qualquer um desses, você pode usar $functions
e $aliases
, mas será repetitivo.