Verifique se algum dos parâmetros de um script bash corresponde a uma sequência

67

Estou tentando escrever um script em que quero verificar se algum dos parâmetros passados ​​para um script bash corresponde a uma seqüência de caracteres. A maneira como eu o configurei agora é

if [ "$3" != "-disCopperBld" -a "$4" != "-disCopperBld" -a "$5" != "-disCopperBld" -a "$6" != "-disCopperBld"]

mas pode haver um grande número de parâmetros, então eu queria saber se existe uma maneira melhor de fazer isso?

obrigado

EDIT: Tentei esse pedaço de código e chamei o script com a opção -disableVenusBld, mas ele ainda imprime "Iniciando a compilação". Estou fazendo algo errado? Desde já, obrigado!

while [ $# -ne 0 ]
do
    arg="$1"
    case "$arg" in
        -disableVenusBld)
            disableVenusBld=true
            ;;
        -disableCopperBld)
            disableCopperBld=true
            ;;
        -disableTest)
            disableTest=true
            ;;
        -disableUpdate)
            disableUpdate=true
            ;;
        *)
            nothing="true"
            ;;
    esac
    shift
done

if [ "$disableVenusBld" != true ]; then
    echo "Starting build"
fi
iman453
fonte
Obrigado pelas respostas pessoal, agradeço que você tenha tempo para me ajudar. Tentei um pedaço de código, mas não consigo descobrir o que está errado. Alguma ideia? (I colou o código em uma edição do meu post original)
iman453
Hmm: funciona para mim. Adicionei #! /bin/sh -ao topo o que você incluiu lá, tornei o script executável e depois ./t.shimprimi "Iniciando a compilação", mas ./t.sh -disableVenusBldnão imprime nada.
Norman Gray

Respostas:

59

Parece que você está manipulando opções em um script de shell. Aqui está o idioma para isso:

#! /bin/sh -

# idiomatic parameter and option handling in sh
while test $# -gt 0
do
    case "$1" in
        --opt1) echo "option 1"
            ;;
        --opt2) echo "option 2"
            ;;
        --*) echo "bad option $1"
            ;;
        *) echo "argument $1"
            ;;
    esac
    shift
done

exit 0

(Existem algumas convenções para recuar o ;;e algumas conchas permitem que você dê as opções como (--opt1), para ajudar na correspondência entre chaves, mas essa é a idéia básica)

Norman Gray
fonte
3
Uma shiftdeclaração é usada quando o número de argumentos para um comando não é conhecido antecipadamente, por exemplo, quando os usuários podem fornecer quantos argumentos quiserem. Nesses casos, os argumentos são processados ​​em um whileloop com uma condição de teste de $#. Essa condição é verdadeira desde que o número de argumentos seja maior que zero. A $1variável e a shiftinstrução processam cada argumento. O número de argumentos é reduzido cada vez que shifté executado e, eventualmente, se torna zero, após o qual o whileloop sai. fonte
Serge Stroobandt
Aqui está um exemplo semelhante com echo $1 | sedprocessamento de valor de argumento adicional .
Serge Stroobandt
26

Isso funcionou para mim. Faz exatamente o que você pediu e nada mais (sem processamento de opções). Se isso é bom ou ruim, é um exercício para o pôster :)

if [[ "$*" == *YOURSTRING* ]]
then
    echo "YES"
else
    echo "NO"
fi

Isso tira proveito do manuseio especial $* e dos suportes de super teste [[… do bash ]].

Rich Homolka
fonte
2
IMHO esta tinha que ser a resposta mais correta, uma vez que a pergunta requer apenas a verificação da presença de um parâmetro. No entanto, editei a alteração $*para $@, uma vez que a sequência a ser testada pode ter espaços e adicionar um link à documentação do bash sobre isso.
H7r
9
Você queria usar o operador = ~? Caso contrário, não vejo por que isso deve funcionar e, de fato, não funciona quando tento o script exato.
Seppo Enarvi
3
Não está funcionando. bash -c 'echo args=$*; [[ "$@" == "bar" ]] && echo YES || echo NO' -- foo bar
Tobia
2
Isso compara toda a lista de argumentos com your string. Eu acho que você precisa fazer o que é sugerido por esta resposta . ou seja: bash -c 'echo args=$*; for i in "$@" ; do [[ $i == "bar" ]] && echo "Is set!" && break ; done' -- bar foofuncionaria.
starfry
2
Essa resposta está errada nos últimos quatro anos porque a edição do h7r a quebrou. A resposta original (que eu restaurei agora) funciona, desde que "sua string" não contenha caracteres glob e com alguns falsos positivos. Por exemplo, se o comando for create a new certificatee "sua string" for cat, isso reportará uma correspondência porque certificate contém cat .
Scott
8

Que tal pesquisar (com caracteres curinga) todo o espaço de parâmetros:

if [[ $@ == *'-disableVenusBld'* ]]
then

Edit: Ok, ok, então essa não era uma resposta popular. Que tal este, é perfeito !:

if [[ "${@#-disableVenusBld}" = "$@" ]]
then
    echo "Did not find disableVenusBld"
else
    echo "Found disableVenusBld"
fi

Edit2: Ok, ok, talvez isso não seja perfeito ... Acho que funcionará apenas se -param estiver no início da lista e também corresponderá a -paramXZY ou -paramABC. Ainda acho que o problema original pode ser resolvido muito bem com a manipulação de strings do bash, mas ainda não o resolvi aqui ... -Pode?

Rico
fonte
Sua segunda sugestão - comparar a substituição de filtragem com a substituição completa - funciona razoavelmente bem e tem a vantagem de não interromper a lista de argumentos.
Donal Fellows
Você poderia explicar o que a segunda sugestão (especialmente ${@#) faz?
velop
11
@velop Claro! Então você sabe que $@é uma variável especial que contém todos os argumentos da linha de comando? Bem, eu apenas usei a manipulação de string Bash nessa variável para remover a substring "-disableVenusBld" e depois comparo-a ao original $@. Então, se $@iguais -foo -bar, então ${@#-disableVenusBld}ainda seria -foo -bar, então eu posso ver que a bandeira que eu estou procurando não está presente. No entanto, se $@iguais, -foo -disableVenusBld -barentão ${@#-disableVenusBld}seria o -foo -barque não é igual $@, me dizendo que a bandeira que estou procurando está presente! Legal eh!
Rich
@velop Saiba mais sobre a manipulação de string Bash aqui: tldp.org/LDP/abs/html/string-manipulation.html
Rich
@ Rich bastante arrumado ^^, thx pela explicação.
velop
4
disCopperBld=
for x; do
  if [ "$x" = "-disCopperBld" ]; then disCopperBld=1; break; fi
done
if [ -n "$disCopperBld" ]; then
  ...
fi

Se você precisar testar apenas os parâmetros iniciados em $3, faça a pesquisa em uma função:

## Usage: search_trailing_parameters NEEDLE NUM "$@"
## Search NEEDLE amongst the parameters, skipping $1 through ${$NUM}.
search_trailing_parameters () {
  needle=$1
  shift $(($2 + 2))
  for x; do
    if [ "$x" = "$needle" ]; then return 0; fi
  done
  return 1
}
if search_trailing_parameters -disCopperBld 2 "$@"; then
  ...
fi

Mas eu me pergunto por que você está tentando fazer isso em primeiro lugar, não é uma necessidade comum. Geralmente, você processa as opções em ordem, como na resposta de Dennis à sua pergunta anterior .

Gilles 'SO- parar de ser mau'
fonte