Estou lendo o código-fonte do wrapper Maven escrito para o shell Bourne . Me deparei com estas linhas:
if [ -z "$JAVA_HOME" ]; then
javaExecutable="$(which javac)"
if [ -n "$javaExecutable" ] && ! [ "$(expr "$javaExecutable" : '\([^ ]*\)')" = "no" ]; then
# snip
expr
quando usado com arg1
and arg2
e a :
corresponde arg1
ao regex arg2
. Normalmente, o resultado seria a quantidade de caracteres correspondentes, por exemplo:
$ expr foobar : foo
3
Porém, ao usar parênteses de captura ( \(
e \)
), ele retorna o conteúdo dos primeiros parênteses de captura:
$ expr foobar : '\(foo\)'
foo
Até agora tudo bem.
Se eu avaliar a expressão da fonte citada acima em minha máquina, obtenho:
$ javaExecutable=$(which javac)
$ expr "$javaExecutable" : '\([^ ]*\)'
/usr/bin/javac
Para um executável inexistente:
$ nonExistingExecutable=$(which sjdkfjkdsjfs)
$ expr "$nonExistingExecutable" : '\([^ ]*\)'
O que significa que para um executável inexistente a saída é uma string vazia com nova linha.
O que está me intrigando na fonte é como a saída de which javac
( arg1
to expr
) retorna a string no
?
Existe alguma versão which
que, em vez de não retornar nada, retorne no
quando nenhum executável for encontrado?
Caso contrário, esta afirmação sempre será avaliada como verdadeira e isso seria estranho.
Classicamente,
which
era um script csh e imprimia uma mensagem de erro comono foo in /usr/bin:/bin
e retornava um status de sucesso. (Pelo menos uma versão comum, pode ter havido outras que se comportaram de maneira diferente.) Exemplo do FreeBSD 1.0 (sim, é antigo):(Essa implementação clássica também é famosa por carregar o
.cshrc
, o que poderia alterar oPATH
, o que faria com que a saída estivesse errada.)Os sistemas modernos geralmente têm uma implementação diferente de
which
, escrita em C ou em sh, e seguem padrões modernos para lidar com condições de erro: nenhuma saída para stdout e um status de saída diferente de zero.Tecnicamente, isso verifica se a primeira palavra (ou melhor, a primeira sequência de caracteres sem espaço) na saída. E há
which
implementações que não ficam em silêncio:zsh
'swhich foo
escrevefoo not found
para stdoutwhich foo
escrevewhich: no foo in (<contents of $PATH>)
para stderrNão sei qual variante específica imprime a saída começando com
no
, mas o GNUwhich
pode ser inspirado por ela ou ser a inspiração para ela.