Passar algumas indicações sobre a lógica de ramificação para script

4

Eu tenho um script que quero ramificar com base em um argumento.
Basicamente, esse argumento é como um booleano. Mas eu não quero que o usuário apenas digite qualquer lixo no comando shell run e interprete-o como verdadeiro.
Ou eu não desejaria que algumas sequências de caracteres precisassem levar em conta problemas de diferenciação de maiúsculas etc.
O que eu gostaria como resultado final é:

some_script.sh arg1 arg2 arg3 --remove   

Para que:

PARAM1="$1"  
PARAM2="$2"  
PARAM3="$3"   
REMOVE=?--> what here   

if [ $REMOVE ]; then  
# remove some files  
fi   
    
por Jim 11.10.2017 / 10:41

2 respostas

4

Você pode apenas verificar se a string --remove está nos parâmetros posicionais do seu script. versão bash usando o operador de correspondência regex =~ :

#!/bin/bash

if [[ $@ =~ --remove ]]; then
   echo "removing files"
fi

exit

versão POSIX:

#!/bin/sh

for arg in "$@"; do
   if [ "$arg" = "--remove" ]; then
      echo "removing files"
   fi
done

exit
    
por 07.11.2017 / 18:27
2

Enquanto $1 e amigos trabalham razoavelmente bem para scripts com um conjunto fixo de argumentos, eles não funcionam muito bem para scripts com argumentos dinâmicos. Para isso, você quer usar um loop e uma estrutura de caso:

REMOVE=
for arg in "$@"; do
    case "$arg" in
        --remove)
            REMOVE=1
            ;;
        *)
            if [ ! -z "$REMOVE" ]; then
                # whatever you need to do to remove
            else
                # whatever you need to do if you do not want to remove
            fi
            ;;
    esac
done

Isso funciona bem se você documentar que --remove só se aplica aos argumentos que vêm depois dele; Isso permitiria que você tivesse uma linha de comando mista, em que a remoção se aplica a alguns argumentos, mas não a outros:

script.sh arg1 arg2 --remove arg3

no exemplo acima, --remove se aplica a arg3, mas não a arg1 ou arg2. Você também pode adicionar suporte para uma opção de linha de comando --noremove à sua estrutura de casos:

case "$arg" in
    --noremove)
        REMOVE=
        ;;
    --remove)
        # ... rest of the case remains as is from before
esac

que permitiria algo assim:

script.sh --remove arg1 --noremove arg2 --remove arg3

nesse exemplo, a opção --remove se aplica a arg1 e arg3, mas não a arg2.

Finalmente, se você quiser que seu --remove se aplique a qualquer argumento, independentemente de onde ele aparecer na linha de comando, a maneira mais fácil de seguir é provavelmente usar getopt(1) :

# reorder the command line so that option arguments come first
# and non-option arguments come second, separated by "--"
PARSED=$(getopt -o '' --long remove -n scriptname.sh -- "$@")
# overwrite $@ with the contents of the newly created $PARSED
# Note the quotes; they are essential
eval set -- "$PARSED"

REMOVE=

while true; do
    case "$1" in
        --remove)
            REMOVE=1
            shift
            ;;
        --)
            shift; break;
    esac
done

for arg in "$@"; do
    if [ ! -z "$REMOVE" ]; then
        # whatever you need to do to remove
    else
        # the other thing
    fi
done

O argumento -o para getopt tem opções curtas, para que você possa usar -r em vez de --remove , se preferir. O Getopt também tem algumas opções extras para quando você deseja que as opções tenham (opcionalmente) argumentos, etc, e permite a saída de uso básico gratuitamente, quando os usuários fornecem opções que não são reconhecidas pelo seu script. Há um exemplo que vem com o GNU getopt que mostra todas as possibilidades; no Debian (e derivados) você pode encontrá-lo como /usr/share/doc/util-linux/getopt-parse.bash

    
por 13.11.2017 / 17:02