Estou procurando um processo de negação simples, mas de plataforma cruzada, que nega o valor que um processo retorna. Ele deve mapear 0 para algum valor! = 0 e qualquer valor! = 0 para 0, ou seja, o seguinte comando deve retornar "sim, caminho inexistente não existe":
ls nonexistingpath | negate && echo "yes, nonexistingpath doesn't exist."
O ! - operator é ótimo, mas infelizmente não é independente de shell.
shell
cross-platform
negate
segredo
fonte
fonte
Respostas:
Anteriormente, a resposta era apresentada com o que agora é a primeira seção como a última seção.
POSIX Shell inclui um
!
operadorPesquisando na especificação do shell para outros problemas, recentemente (setembro de 2015) notei que o shell POSIX oferece suporte a um
!
operador. Por exemplo, ele é listado como uma palavra reservada e pode aparecer no início de um pipeline - onde um comando simples é um caso especial de 'pipeline'. Ele pode, portanto, ser usado emif
instruções e /while
ouuntil
loops também - em shells compatíveis com POSIX. Consequentemente, apesar de minhas reservas, provavelmente está mais disponível do que eu percebi em 2008. Uma verificação rápida do POSIX 2004 e do SUS / POSIX 1997 mostra que!
estava presente em ambas as versões.Observe que o
!
operador deve aparecer no início do pipeline e nega o código de status de todo o pipeline (ou seja, o último comando). Aqui estão alguns exemplos.# Simple commands, pipes, and redirects work fine. $ ! some-command succeed; echo $? 1 $ ! some-command fail | some-other-command fail; echo $? 0 $ ! some-command < succeed.txt; echo $? 1 # Environment variables also work, but must come after the !. $ ! RESULT=fail some-command; echo $? 0 # A more complex example. $ if ! some-command < input.txt | grep Success > /dev/null; then echo 'Failure!'; recover-command; mv input.txt input-failed.txt; fi Failure! $ ls *.txt input-failed.txt
Resposta portátil - funciona com conchas antigas
Em um script Bourne (Korn, POSIX, Bash), eu uso:
if ...command and arguments... then : it succeeded else : it failed fi
Isso é tão portátil quanto possível. O 'comando e argumentos' pode ser um pipeline ou outra sequência composta de comandos.
Um
not
comandoO '!' operador, seja embutido em seu shell ou fornecido pelo o / s, não está universalmente disponível. No entanto, não é terrivelmente difícil de escrever - o código a seguir data de pelo menos 1991 (embora eu ache que escrevi uma versão anterior ainda mais atrás). Eu não costumo usar isso em meus scripts, porque não está disponível de forma confiável.
/* @(#)File: $RCSfile: not.c,v $ @(#)Version: $Revision: 4.2 $ @(#)Last changed: $Date: 2005/06/22 19:44:07 $ @(#)Purpose: Invert success/failure status of command @(#)Author: J Leffler @(#)Copyright: (C) JLSS 1991,1997,2005 */ #include <stdlib.h> #include <unistd.h> #include <sys/types.h> #include <sys/wait.h> #include "stderr.h" #ifndef lint static const char sccs[] = "@(#)$Id: not.c,v 4.2 2005/06/22 19:44:07 jleffler Exp $"; #endif int main(int argc, char **argv) { int pid; int corpse; int status; err_setarg0(argv[0]); if (argc <= 1) { /* Nothing to execute. Nothing executed successfully. */ /* Inverted exit condition is non-zero */ exit(1); } if ((pid = fork()) < 0) err_syserr("failed to fork\n"); if (pid == 0) { /* Child: execute command using PATH etc. */ execvp(argv[1], &argv[1]); err_syserr("failed to execute command %s\n", argv[1]); /* NOTREACHED */ } /* Parent */ while ((corpse = wait(&status)) > 0) { if (corpse == pid) { /* Status contains exit status of child. */ /* If exit status of child is zero, it succeeded, and we should exit with a non-zero status */ /* If exit status of child is non-zero, if failed and we should exit with zero status */ exit(status == 0); /* NOTREACHED */ } } /* Failed to receive notification of child's death -- assume it failed */ return (0); }
Isso retorna 'sucesso', o oposto de falha, quando falha ao executar o comando. Podemos debater se a opção 'não fazer nada com sucesso' estava correta; talvez ele deva relatar um erro quando não for solicitado a fazer nada. O código em '
"stderr.h"
' fornece recursos de relatório de erros simples - eu o uso em qualquer lugar. Código-fonte a pedido - consulte minha página de perfil para entrar em contato comigo.fonte
!
operador. Isso funcionou para mim:! MY_ENV=value my_command
ldd foo.exe | ! grep badlib
mas pode fazer! ldd foo.exe | grep badlib
se quiser que o status de saída seja 0 se badlib não for encontrado em foo.exe. Semanticamente, você deseja inverter ogrep
status, mas inverter o tubo inteiro dá o mesmo resultado.ldd foo.exe | { ! grep badlib; }
(embora seja um incômodo, especialmente o ponto e vírgula; você poderia usar um sub-shell completa com(
e)
e sem o ponto e vírgula). OTOH, o objetivo é inverter o status de saída do pipeline, e esse é o status de saída do último comando (exceto no Bash, às vezes).!
comando tem uma interação indesejável comset -e
, ou seja, faz com que o comando seja bem-sucedido com um código de saída 0 ou diferente de zero, em vez de ter sucesso apenas com um código de saída diferente de zero. Existe uma maneira concisa de torná-lo bem-sucedido apenas com um código de saída diferente de zero?No Bash, use o! operador antes do comando. Por exemplo:
! ls nonexistingpath && echo "yes, nonexistingpath doesn't exist"
fonte
Você poderia tentar:
ls nonexistingpath || echo "yes, nonexistingpath doesn't exist."
ou apenas:
fonte
!
não pode ser usado comgit bisect run
, ou pelo menos não sei como.!
nesse caso.Se, de alguma forma, você não tiver o Bash como shell (por exemplo: scripts git ou testes exec fantoches), você pode executar:
echo '! ls notexisting' | bash
-> retcode: 0
echo '! ls /' | bash
-> retcode: 1
fonte
! ls nonexistingpath && echo "yes, nonexistingpath doesn't exist."
ou
ls nonexistingpath || echo "yes, nonexistingpath doesn't exist."
fonte
$?
será diferente. O primeiro pode sair$?=1
se ononexistingpath
existir de fato. O segundo sempre sai$?=0
. Se você estiver usando isso em um Makefile e precisar contar com o valor de retorno, deve ter cuidado.Nota: às vezes você verá
!(command || other command)
.Aqui
! ls nonexistingpath && echo "yes, nonexistingpath doesn't exist."
é o suficiente.Não há necessidade de um sub-shell.
Git 2.22 (Q2 2019) ilustra essa forma melhor com:
Commit 74ec8cf , cometer 3fae7ad , cometer 0e67c32 , cometer 07353d9 , cometer 3bc2702 , cometer 8c3b9f7 , cometer 80a539a , cometer c5c39f4 (13 de março de 2019) por SZEDER Gábor (
szeder
) .Consulte commit 99e37c2 , commit 9f82b2a , commit 900721e (13 de março de 2019) de Johannes Schindelin (
dscho
) .(Incorporado por Junio C Hamano -
gitster
- no commit 579b75a , 25 de abril de 2019)fonte
Solução sem!, Sem subshell, sem if, e deve funcionar pelo menos no bash:
ls nonexistingpath; test $? -eq 2 && echo "yes, nonexistingpath doesn't exist." # alternatively without error message and handling of any error code > 0 ls nonexistingpath 2>/dev/null; test $? -gt 0 && echo "yes, nonexistingpath doesn't exist."
fonte