Como ativar e desativar o modo verboso usando uma instrução case no UNIX

2

Estou tentando criar um arquivo de script de shell que use getopts. O objetivo do programa é remover os arquivos que estão no projeto e colocá-los na pasta de reciclagem do diretório excluído. Eu já consegui concluir isso com sucesso.

Também consegui usar o comando getopt -i (interativo) para passar para uma instrução case e, em seguida, disparar uma pergunta para o usuário perguntando se ele tem certeza de que gostaria de remover um arquivo.

Isso foi feito criando uma variável "ision" e definindo-a como true quando a instrução case for ativada. Eu inseri meu código abaixo. Eu tentei algumas vezes e tudo parece estar bem, mas eu gostaria de adicionar a atividade detalhada / modo. Existe alguém que possa me ajudar?

#!/bin/bash

while getopts ":i:v" option ;
do
case "$option" in
i) echo "interactive mode set"
ision=true;
break;;
v) echo "verbose mode"
vison=true;
break;;
esac
done
echo "this is the proof we need"

echo $@

shift $(($OPTIND-2))

echo $@

echo "this is working too"

if [ ! -e ~/deleted ]
then
mkdir ~/deleted
fi

echo "the echo file was made or just created"

if [ $# -eq 0 ]
then
echo "safe_rm missing operand"
exit
fi

echo "all workking on the western front"

for i in $@
do

if [ "$ision" == "true" ]
then
echo "do you want to remobve the file"
echo "variable test $i"
echo "yes or no"
read -p "Enter " answer
if [ "$answer" == "no" ]
then
continue;
fi
fi

if [ ! -f $i ]
then
echo "no such file or directory"
exit
fi
        if [ $i == safe_rm ]
        then

        echo "cant remove safe_rm"
        continue
        fi

        if [ $i == safe_rm_restore ]
        then
        continue
        echo "cant remove safe_rm_restore"

        fi

inode=$(ls -i $i | cut -c -6 )
echo "the inode is $inode "
pathname=$(dirname $i)
if [ $pathname == "." ]
then
pathname=$(pwd)
echo $pathname
fi
basename=$(basename $i)
path=$basename"_"$inode":"$pathname"/"$basename

echo $path

if [ ! -f .restoreinfo ]
then
touch .restoreinfo
fi


echo $path >> .restoreinfo
mv $i ~/deleted/

done
    
por Rob 10.06.2014 / 19:09

3 respostas

1

Vou me concentrar na linha de comando analisando aqui:

# defaults:
ision=0
vison=0

while getopts "iv" option; do
    case "$option" in
        i)
            echo "interactive mode set"
            ision=1 ;;
        v)
            echo "verbose mode"
            vison=1 ;;
        *)
            exit 1 ;;
    esac
done
shift $(( OPTIND - 1 ))

(( vison )) && echo 'This is a verbose message'

if (( ision )); then
   # interactive code
fi

É muito mais fácil operar com ision e vison se eles forem inteiros. Então você pode apenas testar seu valor com (( vison )) , como mostrado acima.

Você também obteve a string de opção de comando getopts wrong. Tanto quanto eu posso dizer, nenhuma opção leva um argumento, o que significa que não deve haver nenhum dois pontos na string. Se uma opção receber um argumento, os dois pontos deverão vir depois, como em v: .

Não use break quando estiver analisando a linha de comando, isso interromperá a análise. Em vez disso, basta definir os sinalizadores e fazer o que você precisa fazer e deixar o loop continuar. Eu estou supondo que você pode ter alguma familiaridade com C onde um faz precisa break de uma instrução case (em switch ). Não é o mesmo aqui.

Não faça a saída durante a análise da linha de comando, exceto como um auxílio de depuração. Muitos utilitários têm sinalizadores que se anulam, por ex. -v para o modo detalhado seguido por -q para o modo "silencioso" e ter a saída do código "entrando no modo detalhado" seguido de "entrar no modo silencioso" é apenas barulhento.

A propósito, para fazer algo assim (lidar com opções mutuamente exclusivas), você poderia ter

case "$option" in
    q)
        quiet=1
        verbose=0 ;;
    v)
        verbose=1
        quiet=0   ;;

    # etc.

Quando o usuário usa -qv , quiet será primeiro definido como 1 e verbose será definido como 0 e, em seguida, os valores serão revertidos. Não deve haver nenhum erro relatado neste caso, pois você não sabe se a linha de comando foi montada manualmente ou por um script de chamada.

Inseri uma instrução exit 1 que será executada se uma opção de linha de comando desconhecida for fornecida. Isso pode ser bom, pois significa que o usuário cometeu um erro e pode ser perigoso confiar cegamente no que está na linha de comando a partir daí.

O shift (para desativar as opções analisadas) deve ser feito como acima. Mudar $OPTIND - 2 mudaria muitas coisas da lista de argumentos.

Também aprimorei o recuo, o que facilita a leitura e, portanto, facilita a depuração e a manutenção.

Quanto ao resto do roteiro, não olhei muito de perto, mas noto muitas expansões de variáveis sem nome. Não faça isso, pois isso atrapalhará as coisas se você receber nomes de arquivos com espaços (ou outros caracteres em branco) neles.

Especialmente $@ precisa ser citado quando usado em, e. rotações. Isso impede que os argumentos de linha de comando sejam divididos em espaços em branco (o conteúdo de $IFS seja mais preciso) e evita a globalização acidental de nomes de arquivos, se os nomes contiverem caracteres de padrão globbing.

Há também um bom número de declarações continue . IMHO, estes devem ser eliminados, pois dificultam o acompanhamento do fluxo do código (especialmente quando o código não é indentado corretamente). Eles não estão errados em si mesmos, mas podem ser removidos se o código lidar adequadamente com as várias condições. Em pelo menos um caso, você tem um echo diretamente após uma instrução continue , o que significa que esse echo nunca será acionado:

    continue
    echo "cant remove safe_rm_restore"
    
por 15.09.2017 / 09:51
0

Você pode usar algumas comparações abreviadas. Esta é uma instrução if / then / else listada de forma semelhante à notação?: Em C e em vários outros idiomas. Você pode executar a comparação e usar um & & para executar um bloco se for verdade e || para executar um bloco se for falso.

$ vison=true 
$ [[ "$vison" == "true" ]] && vison=false || vison=true
$ echo $vison
false
$ [[ "$vison" == "true" ]] && vison=false || vison=true
$ echo $vison
true

A mesma coisa pode ser feita para verificar se há logs detalhados também.

[[ "$vison" == "true" ]] && echo "this is shown only in verbose mode"
    
por 10.06.2014 / 19:48
0

Existem false e true comandos que são úteis para expressar booleanos em shells. Para verbosidade, uma abordagem comum é usar um nível de log no qual cada ocorrência de -v aumenta o nível de log e -q diminui.

interactive=false
log_level=1

log() {
  local level="$1"
  if [ "$level" -ge "$log_level" ]; then
    shift
    local IFS=" "
    printf '%s\n' "$*"
  fi
}


while getopts iqv option; do
    case $option in
        i)
            log 2 "interactive mode set"
            interactive=true;;
        v)
            log 2 "increasing log level"
            log_level=$((log_level + 1));;
        q)
            log 2 "decreasing log level"
            log_level=$((log_level - 1));;
        *)
            exit 1 ;;
    esac
done
shift "$((OPTIND - 1))"

log 2 'This is a verbose message'
log 3 'This is a debug message'

if "$interactive"; then
   # interactive code
fi

# or:

ask() { # args: var default question
  if "$interactive"; then
    printf %s "$3"
    IFS= read -r "$1"
  else
    eval "$1=\"
  fi
}

yesno() { # args: default question
  local answer="$1"
  ask answer "$1" "$2"
  case $answer in
    ([yY][eE][sS] | y | Y) return 0;;
    ([nN][oO] | n | N) return 1;;
    (*) case $1 in
          ([yY][eE][sS] | y | Y) return 0;;
          ([nN][oO] | n | N) return 1;;
          (*) log >&2 -1 "Wrong default value $default"; exit 1;;
        esac;;
  esac
}

if yesno no "Are you OK with that (yes/[no])? "; then
   log 1 OK do it
   ...
fi

O código acima (não testado) é compatível com a política Debian, então funcionará com o Debian sh se ele está configurado para ser dash , lksh ou bash (também seria POSIX se não fosse local ) .

    
por 15.09.2017 / 10:33