Bash: Como usar enquanto shift; do..case $ 1 in

4

Estou trabalhando em um script bash e preciso implementar "opções". Como posso fazer isso com o bash?

Meu objetivo é executar o script da seguinte maneira: /myscript.sh -d "/var/log/" -c "test"

o que eu tentei:

while shift; do
        case $1 in
                -d)
                        shift&&DIR="$1"||die
                ;;
                -c)
                        shift&&COMMAND="$1"||die
                ;;
        esac
done

echo "$DIR"
echo "$COMMAND"
teslasimus
fonte
E o que exatamente acontece quando você tenta isso?
Dennis
imprima apenas o caso -c)
teslasimus

Respostas:

5

Para expandir a resposta da @ choroba, aqui está um exemplo de como usar getopts:

# parse the flag options (and their arguments)
while getopts c:d: OPT; do
    case "$OPT" in
      d)
        DIR="$OPTARG" ;;
      c)
        COMMAND="$OPTARG" ;;
      [?])
        # got invalid option
        echo "Usage: $0 [-d directory] [-c command]" >&2
        exit 1 ;;
    esac
done

# get rid of the just-finished flag arguments
shift $(($OPTIND-1))

Note que depois de deslocar os argumentos de bandeira, quaisquer argumentos "regulares" permanecerão. Então, nesse ponto, você pode lidar com eles (por exemplo, ... for arg in "$@"; do ... ) ou se o seu script não os leva a reclamar se você receber algum ( if [ $# -gt 0 ]; then echo "Usage ... ).

Gordon Davisson
fonte
getopt é uma dependência externa. O autor original só perguntou sobre mudança, não getopt.
heroxbd
@heroxbd getopt é um comando externo, mas estou sugerindo getopts (note o "s"), que é um shell embutido.
Gordon Davisson
6

Seu erro é que você está mudando no topo do loop, jogando o primeiro argumento antes de examiná-lo. Isso é o que eu acho que você provavelmente quis dizer:

#!/bin/bash
while (( "$#" )); do
   case $1 in
      -d)
         shift&&DIR="$1"||die
         ;;
      -c)
         shift&&COMMAND="$1"||die
         ;;
   esac
   shift
done

echo "$DIR"
echo "$COMMAND"
Nicole Hamilton
fonte
morrer? bash não é Perl
glenn jackman
@glennjackman Bom comentário. Eu não entendi isso como um possível problema. (Observe que o OP explica que a queixa é que ele imprime apenas o caso -c). die provavelmente era um pseudônimo - ou pelo menos, que o que quer que fosse não importava para a questão.
Nicole Hamilton
certo, eu comentei com a pessoa errada ...
glenn jackman
2

Como a choroba já disse getopts é uma abordagem melhor.

No seu caso, você poderia usar:

getopts c:d: d || die
DIR=$OPTARG
getopts c:d: c || die
COMMAND=$OPTARG

para conseguir o que você está tentando fazer com o loop while.

A corda c:d: especifica os comutadores possíveis. O cólon significa que o comutador requer um argumento.

O problema com a sua abordagem é que você chama shift antes de analisar o primeiro argumento, descartando-o no processo.

Para corrigir isso, altere o loop while para o seguinte:

while true; do
        case $1 in
                -d)
                        shift&&DIR="$1"||die
                ;;
                -c)
                        shift&&COMMAND="$1"||die
                ;;
        esac
        shift || break
done
Dennis
fonte
1

A abordagem usual é usar getopts.

choroba
fonte