Bash, aviso sem argumentos e decisões de caso

110

Estou aprendendo bash.

Gostaria de fazer um script simples que, quando não são fornecidos argumentos, mostra alguma mensagem. E quando dou números como argumento, dependendo do valor, ele faz uma coisa ou outra.

Também gostaria de saber sugestões para os melhores manuais online para iniciantes em bash

obrigado

Abra o caminho
fonte

Respostas:

176
if [[ $# -eq 0 ]] ; then
    echo 'some message'
    exit 0
fi

case "$1" in
    1) echo 'you gave 1' ;;
    *) echo 'you gave something else' ;;
esac

O Advanced Bash-Scripting Guide é muito bom. Apesar do nome, trata do básico.

Thomas
fonte
RE: "saída 0". Não sei se sair do script era o que ele tinha em mente. Mas sim, é um excelente guia.
Trampas Kirk
Eu interpretei "e" como "caso contrário", assumindo que a mensagem seria algum texto de ajuda. Mas tenho certeza de que Werner é capaz de descobrir o que essa linha faz e se ele quer :)
Thomas
obrigado, claro! e por último, como posso desligar as mensagens de erro do script, para que não sejam mostradas no shell?
Abra o caminho
Você quer dizer os erros provenientes de um programa específico que está chamando? Você pode colocar > /dev/nulle / ou 2> /dev/nulldepois enviar sua saída padrão e / ou fluxos de erro padrão no esquecimento.
Thomas
4
Se você considerar que um argumento ausente é algo ruim (como o script não pode ser executado com êxito), retorne algo diferente de 0 ( exit 1). Existem outras convenções sobre códigos de retorno / saída, que você pode encontrar online rapidamente, mas o ponto importante é que não deve ser 0, o que indica sucesso.
Felix
25

Se estiver interessado apenas em resgatar se um argumento específico estiver faltando, a Substituição de Parâmetro é ótima:

#!/bin/bash
# usage-message.sh

: ${1?"Usage: $0 ARGUMENT"}
#  Script exits here if command-line parameter absent,
#+ with following error message.
#    usage-message.sh: 1: Usage: usage-message.sh ARGUMENT
Pat
fonte
11

Exemplo

 if [ -z "$*" ]; then echo "No args"; fi

Resultado

No args

Detalhes

-z é o operador unário para o comprimento da string é zero. $*são todos argumentos. As aspas são para segurança e encapsulam vários argumentos, se houver.

Use man bashe pesquise ( tecla / ) por "unário" para mais operadores como este.

Trampas Kirk
fonte
7
Um (menor) problema com isso é que ele não distingue entre passar nenhum argumento e passar uma string vazia como argumento. Isso pode ser importante em alguns contextos. Usando [$ # -eq 0] pode-se lidar com ambos os casos corretamente.
Idelic
1
Ah, as sutilezas da programação (ba) sh ... É por isso que eu odeio.
Thomas,
1
pense -zem mizzing
Ray Foss
4

Antigo, mas tenho motivos para refazer a resposta agora, graças a alguma confusão anterior:

if [[ $1 == "" ]] #Where "$1" is the positional argument you want to validate 

 then
 echo "something"
 exit 0

fi

Isso irá ecoar "Algo" se não houver nenhum argumento posicional $ 1. No entanto, não valida que $ 1 contenha informações específicas.

Ryan Smith
fonte
$#é explicitamente a contagem inteira do número de argumentos; será "0" e você ecoará "algo" mesmo que não haja argumentos, ou será algum número positivo, e você ecoará "algo" corretamente. Mas a verificação em si nunca fará nada, independentemente da entrada ou da falta de entrada que você usa - ela sempre relatará que $#contém um valor. Portanto, isso está completamente errado e nunca funcionará como afirmado.
eschwartz
Você tem certeza disso? Tenho vários scripts que funcionam conforme o esperado usando esse formato exato. Ao ler sua resposta, até testei novamente a correspondência e a falta dela. $ # não conterá um valor se não for especificado, se não houver nenhum argumento posicional para corresponder ao que # está em seu cenário. Não faz sentido porque bash assumiria um valor em um argumento posicional que não existe.
Ryan Smith
Tente echo $#como o conteúdo de um script /tmp/test.sh, em seguida, execute-o em / bin / bash, bem como / bin / sh (ou / bin / dash e quaisquer outras implementações de shell que você tenha disponível. /tmp/test.shEcoará "0" para o console, como o fará /bin/dash /tmp/test.sh. Por outro lado, /tmp/test.sh fooirá exibir "1" e /tmp/test.sh first second"2".
eschwartz
Conforme descrito man bashna seção "Parâmetros especiais", "O shell trata vários parâmetros de maneira especial. Esses parâmetros só podem ser referenciados; a atribuição a eles não é permitida." E "# Expande para o número de parâmetros posicionais em decimal." É igualmente exigido pelo POSIX conforme descrito em pubs.opengroup.org/onlinepubs/9699919799/utilities/…
eschwartz
Parece que houve um erro de comunicação! Eu quis dizer # como um espaço reservado para o argumento posicional específico (ou seja, $ 2 se você quis dizer o segundo argumento) não literal $ #. Depois de revisar o que você disse acima, você está absolutamente correto, um $ # literal sempre resolverá o número de argumentos. Desculpas pela confusão.
Ryan Smith