Bash: liga o stderr depois de suprimir

2

Eu fiz este script que automatiza a instalação / desinstalação do git. Na minha função para testar se o git está instalado, eu uso o comando git --version e testo o código de retorno.

Eu não gosto da saída stderr que ocorre normalmente quando estou tentando fazer uma boa saída personalizada. Embora eu tenha descoberto como suprimir o stderr apenas para essa função, não consigo reativá-lo.

Meu prompt read está ausente agora depois de chamar essa função.

function CheckGit() {
    exec 3>&2           # link file desc 3 w/ stderr
    exec 2> /dev/null

    SILENT_MODE=$1

    if [[ ! $(git --version) ]]; then
        if [ SILENT_MODE ]; then
            printf "${LT_RED} GIT IS NOT INSTALLED.\n"
        fi
        continue;
    else
        if [ SILENT_MODE ]; then
            printf "${LT_BLUE} GIT IS CURRENTLY INSTALLED.\n"
        fi
        continue;
    fi
    GIT_INSTALLED=$?
    #turn back on the stderr notifications
    exec 2>&3 3>&-      # Restore stdout and close file descriptor #3
}

while true; do
    printf "${LT_BLUE} Menu\n"
    printf " ***********************************************\n"
    printf "${LT_GREEN} a) Check git.\n"
    printf "${LT_GREEN} b) (More to be added)\n"
    printf "${LT_GREEN} c) ...\n"
    printf "${LT_GREEN} d) ...\n"
    printf "${LT_GREEN} h) ...\n"
    printf "${LT_RED} x) Exit.\n"
    printf "\n${NC}"
    read -p "Please make a selection: " eotuyx
    case $eotuyx in
        [Aa]* ) CheckGit true; continue;;
        [Bb]* ) ...; continue;;
        [Cc]* ) ...; continue;;
        [Dd]* ) ...; continue;;
        [Hh]* ) ...; continue;;
        [XxQq]* ) break;;
        * ) -e "\n${NC}" + "Please answer with a, b, c, d, x(or q).";;
    esac
done
    
por Bretonator 18.11.2018 / 00:08

2 respostas

4

Para reiterar os conselhos dados comentários :

  1. Exclua as instruções continue da função CheckGit .
    • Eles não são necessários,
    • e - o que você pode não ter percebido - eles causam, não apenas um retorno imediato (da função) para o loop principal, mas um retorno imediato para a declaração while true no topo do loop principal. Portanto, como Tomasz apontou , sua declaração exec 2>&3 3>&- não está sendo executada.

Notas gerais:

  1. if [ SILENT_MODE ] é sempre verdadeiro como mosvy apontou , porque está apenas testando se a string SILENT_MODE não é nula. Você parece querer if [ "$SILENT_MODE" ] .
  2. Mas você pode estar se enganando. if [ "$SILENT_MODE" ] é verdadeiro, mesmo se $SILENT_MODE for false - tudo o que está fazendo testando se a string não é nula, então chamando CheckGit false ainda resultará na informação sendo exibida.
  3. E, mesmo que você não esteja se enganando, você pode estar enganando a pessoa que tem que manter este roteiro na próxima semana. E sim, essa pessoa pode ser você. Sua lógica aparente é “se estiver no modo silencioso, relate informações extras”. Isso é logicamente atrasado; faria mais sentido dizer if [ "$SILENT_MODE" = false ] , ou então chame a variável VERBOSE_MODE .
  4. $? é muito efêmero. É sempre o resultado do comando mais recente. Então, se você fizer
    if  check whether git is installed ; then
        printf "GIT IS NOT INSTALLED.\n"
    else
        printf "GIT IS CURRENTLY INSTALLED.\n"
    fi
    GIT_INSTALLED=$?
    então GIT_INSTALLED obtém o status de saída do printf . Você precisa definir GIT_INSTALLED antes.
  5. Seu teste, if [[ ! $(git --version) ]]; then , testes, não "o código de retorno" (como você diz na pergunta), mas se git --version escreve alguma coisa na saída padrão. Isso pode ser o que você quer. Essa pode ser a melhor maneira de testar se o git está instalado. Mas pode ser melhor (e muitas vezes, em geral, é melhor) para verificar o status de saída do comando.
  6. Uma nota de estilo: acho as instruções if - then - else mais fáceis para entender se a parte “verdadeira” é a primeira. Seu script está dizendo
    if git is not installed
    then
        say that it's not installed
    else (i.e., if it's NOT not installed)
        say that it's installed
    fi
    Os negativos duplos são confusos.
  7. E sim; exec 2> /dev/null é útil se você quiser suprimir o erro padrão de 42 instruções em uma linha. Se você precisar afetar apenas um único comando, basta colocar 2> /dev/null (ou > /dev/null 2>&1 ) nesse comando, como mosvy sugeriu .
por 18.11.2018 / 02:43
1

Seus comandos parecem bem, mas a lógica não cobre todos os casos. Observe que quando você continue , os descritores não são revertidos.

Analise também como isso deve funcionar e como funciona:

GIT_INSTALLED=$?

$? é o código de saída do último comando executado. Use a depuração para ver isso mais de perto ( set -x ).

Além disso, como iniciante, você se beneficiaria bastante do teste estático dos seus scripts com o shellcheck.net .

    
por 18.11.2018 / 01:09