AskOverflow.Dev

AskOverflow.Dev Logo AskOverflow.Dev Logo

AskOverflow.Dev Navigation

  • Início
  • system&network
  • Ubuntu
  • Unix
  • DBA
  • Computer
  • Coding
  • LangChain

Mobile menu

Close
  • Início
  • system&network
    • Recentes
    • Highest score
    • tags
  • Ubuntu
    • Recentes
    • Highest score
    • tags
  • Unix
    • Recentes
    • tags
  • DBA
    • Recentes
    • tags
  • Computer
    • Recentes
    • tags
  • Coding
    • Recentes
    • tags
Início / computer / Perguntas / 1653224
Accepted
Hashim Aziz
Hashim Aziz
Asked: 2021-06-03 06:29:12 +0800 CST2021-06-03 06:29:12 +0800 CST 2021-06-03 06:29:12 +0800 CST

Como reescrever uma parede de instruções if-elif

  • 772

Para cigs.sh - o script completo pode ser encontrado aqui - escrevi a seguinte lógica feia (mas funcionando perfeitamente) para imprimir e formatar a saída do script, em parte apenas para descobrir todos os casos extremos, mas também porque não vi nenhum outra alternativa.

...

if [[ $W -le 0 && $D -le 0 && $H -eq 1 ]]; then string="$H hour"
elif [[ $W -le 0 && $D -le 0 && $H -gt 1 ]]; then string="$H hours"
elif [[ $W -le 0 && $D -eq 1 && $H -le 0 ]]; then string="$D day" 
elif [[ $W -le 0 && $D -eq 1 && $H -eq 1 ]]; then string="$D day and $H hour"
elif [[ $W -le 0 && $D -eq 1 && $H -gt 1 ]]; then string="$D day and $H hours"   
elif [[ $W -le 0 && $D -gt 1 && $H -le 0 ]]; then string="$D days"
elif [[ $W -le 0 && $D -gt 1 && $H -eq 1 ]]; then string="$D days and $H hour"
elif [[ $W -le 0 && $D -gt 1 && $H -gt 1 ]]; then string="$D days and $H hours"
elif [[ $W -eq 1 && $D -le 0 && $H -le 0 ]]; then string="$W week"
elif [[ $W -eq 1 && $D -le 0 && $H -eq 1 ]]; then string="$W week and $H hour"
elif [[ $W -eq 1 && $D -le 0 && $H -gt 1 ]]; then string="$W week and $H hours"
elif [[ $W -eq 1 && $D -eq 1 && $H -le 0 ]]; then string="$W week and $D day"
elif [[ $W -eq 1 && $D -gt 1 && $H -le 0 ]]; then string="$W week and $D days"
elif [[ $W -eq 1 && $D -eq 1 && $H -eq 1 ]]; then string="$W week, $D day and $H hour"
elif [[ $W -eq 1 && $D -eq 1 && $H -gt 1 ]]; then string="$W week, $D day and $H hours"
elif [[ $W -eq 1 && $D -gt 1 && $H -eq 1 ]]; then string="$W week, $D days and $H hour"
elif [[ $W -eq 1 && $D -gt 1 && $H -gt 1 ]]; then string="$W week, $D days and $H hours"
elif [[ $W -gt 1 && $D -le 0 && $H -le 0 ]]; then string="$W weeks"
elif [[ $W -gt 1 && $D -le 0 && $H -eq 1 ]]; then string="$W weeks and $H hour"
elif [[ $W -gt 1 && $D -le 0 && $H -gt 1 ]]; then string="$W weeks and $H hours"
elif [[ $W -gt 1 && $D -eq 1 && $H -le 0 ]]; then string="$W weeks and $D day"
elif [[ $W -gt 1 && $D -gt 1 && $H -le 0 ]]; then string="$W weeks and $D days"
elif [[ $W -gt 1 && $D -eq 1 && $H -eq 1 ]]; then string="$W weeks, $D day and $H hour"
elif [[ $W -gt 1 && $D -eq 1 && $H -gt 1 ]]; then string="$W weeks, $D day and $H hours"
elif [[ $W -gt 1 && $D -gt 1 && $H -eq 1 ]]; then string="$W weeks, $D days and $H hour"
elif [[ $W -gt 1 && $D -gt 1 && $H -gt 1 ]]; then string="$W weeks, $D days and $H hours"
fi

colour1='\033[0;31m'
colour2='\033[0;32m'
if (($elapsed < threshold))
then echo -e "${colour1}It's been $string since you last bought a $item."
else
echo -e "${colour2}It's been $string since you last bought a $item."
fi

Talvez eu esteja apenas sendo burro, mas por mais embaraçoso que seja o código acima, não consigo ver uma maneira melhor de reescrevê-lo. Existe um, e em caso afirmativo, o que é?

bash automation
  • 4 4 respostas
  • 142 Views

4 respostas

  • Voted
  1. meuh
    2021-06-03T09:33:55+08:002021-06-03T09:33:55+08:00

    Uma abordagem alternativa é começar com a versão longa e detalhada e reduzi-la usando padrões correspondentes para remover plurais, etc. Eu não sei se é mais radável, então pode ser mais difícil de manter.

    string=" $W weeks, $D days and $H hours" # leading space to simplify matching
    string=${string/ 1 weeks/1 week}
    string=${string/ 1 days/ 1 day}
    string=${string/ 1 hours/ 1 hour}
    string=${string# 0 weeks,}
    string=${string/ 0 days/}
    string=${string%and 0 hours}
    string=${string/, and/ and}
    string=${string# }
    string=${string% }
    string=${string%,}
    string=${string#and }
    [[ $string =~ and ]] || string=${string/,/ and}
    

    Isso usa a sintaxe de expansão de parâmetro do bash, onde ${parameter/pattern/replacement}tenta corresponder ao padrão glob e, se encontrado, o substitui. Isso é usado para "corrigir" os "erros" como "1 semana" para torná-lo "1 semana". Para evitar também a correspondência 21 weeks, a string inicial tem um espaço extra no início, para que o espaço possa estar no padrão para garantir que apenas "1" seja correspondido.

    A sintaxe ${parameter#pattern}exclui a correspondência se encontrada no início do parâmetro. Isso é usado para excluir "0 semanas".

    A sintaxe ${parameter%pattern}exclui a correspondência se encontrada no final do parâmetro. Isso é usado para excluir "e 0 horas". As outras correções excluem um espaço se for deixado no início ou no final, ou uma vírgula se for deixado no final, ou um "e" e espaço se for deixado no início.

    A linha final substitui a vírgula por " e" se não houver "e" na string. Isso corresponde a, digamos, mudar "2 semanas, 3 dias" para "2 semanas e 3 dias", onde já removemos o "e 0 horas".

    • 3
  2. Gordon Davisson
    2021-06-04T00:47:29+08:002021-06-04T00:47:29+08:00

    Se você estiver executando o script no bash, que tal isso (com base no comentário de Jeff Zeitlin):

    # Start with an empty list of units
    units=()
    
    # Add the non-zero units to the list
    if (( W == 1 )); then units+=("1 week")
    elif (( W > 1 )); then units+=("$W weeks")
    fi
    
    if (( D == 1 )); then units+=("1 day")
    elif (( D > 1 )); then units+=("$D days")
    fi
    
    if (( H == 1 )); then units+=("1 hour")
    elif (( H > 1 )); then units+=("$H hours")
    fi
    
    # Based on the number of non-zero units, add separators appropriately
    case ${#units[@]} in
            3) string="${units[0]}, ${units[1]} and ${units[2]}" ;;
            2) string="${units[0]} and ${units[1]}" ;;
            1) string="${units[0]}" ;;
            0) string="less than an hour" ;;
    esac
    

    Aviso: isso praticamente requer bash. zsh também tem arrays, mas numera as entradas de forma diferente (começando em 1 em vez de 0), então a seção final falharia estranhamente em zsh.

    • 3
  3. Best Answer
    meuh
    2021-06-04T04:42:22+08:002021-06-04T04:42:22+08:00

    Nos dias anteriores ao bash ter [[ ]]expressões, as instruções case eram muito usadas para correspondência de padrões. A lista de if's pode ser convertida em uma instrução de caso único (o +sinal é apenas um separador arbitrário):

    case $W+$D+$H in
    0+0+0 ) string="" ;;
    0+0+1 ) string="$H hour" ;;
    0+1+0 ) string="$D day"  ;;
    0+1+1 ) string="$D day and $H hour" ;;
    1+0+0 ) string="$W week" ;;
    1+0+1 ) string="$W week and $H hour" ;;
    1+1+0 ) string="$W week and $D day" ;;
    1+1+1 ) string="$W week, $D day and $H hour" ;;
    
    0+0+* ) string="$H hours" ;;
    0+*+0 ) string="$D days"  ;;
    *+0+0 ) string="$W weeks" ;;
    0+1+* ) string="$D day and $H hours" ;;
    0+*+1 ) string="$D days and $H hour" ;;
    *+0+1 ) string="$W weeks and $H hour" ;;
    *+1+0 ) string="$W weeks and $D day" ;;
    1+0+* ) string="$W week and $H hours" ;;
    1+*+0 ) string="$W week and $D days" ;;
    1+1+* ) string="$W week, $D day and $H hours" ;;
    1+*+1 ) string="$W week, $D days and $H hour" ;;
    *+1+1 ) string="$W weeks, $D day and $H hour" ;;
    
    0+*+* ) string="$D days and $H hours" ;;
    1+*+* ) string="$W week, $D days and $H hours" ;;
    *+0+* ) string="$W weeks and $H hours" ;;
    *+*+0 ) string="$W weeks and $D days"  ;;
    *+1+* ) string="$W weeks, $D day and $H hours" ;;
    *+*+1 ) string="$W weeks, $D days and $H hour" ;;
    *+*+* ) string="$W weeks, $D days and $H hours" ;;
    esac
    

    Isso ainda é difícil de digerir, mas se separarmos as palavras no plural com variáveis ​​contendo an sou não, a casedeclaração é muito mais simples:

    ws=s; [ $W = 1 ] && ws=
    ds=s; [ $D = 1 ] && ds=
    hs=s; [ $H = 1 ] && hs=
    case $W+$D+$H in
    0+0+0 ) string="" ;;
    0+0+* ) string="$H hour$hs" ;;
    0+*+0 ) string="$D day$ds"  ;;
    0+*+* ) string="$D day$ds and $H hour$hs" ;;
    *+0+0 ) string="$W week$ws" ;;
    *+0+* ) string="$W week$ws and $H hour$hs" ;;
    *+*+0 ) string="$W week$ws and $D day$ds" ;;
    *+*+* ) string="$W week$ws, $D day$ds and $H hour$hs" ;;
    esac
    
    • 3
  4. Yorik
    2021-06-03T08:15:04+08:002021-06-03T08:15:04+08:00

    Bash suporta funções , então talvez tente uma função. Esbocei (em pseudocódigo) uma possível tática a ser tomada.

    O "s" é fácil de manusear porque só deve ser singular se o valor for um. A vírgula e o "e" são decisões baseadas em contagem, portanto, uma função retorna uma string vazia ou "apropriadamente pluralizada", e a próxima função é usada para incrementar um contador com base na natureza vazia da string.

    O contador é então usado para manipular duas strings separadoras e, em seguida, a coisa toda é montada às cegas.

    Pseudo-código:

    function foo ($int, $singular, $suffix, $ignoreZero) {
        $rval = "";
        if ( $ignoreZero && $int == 0 )  { return $rval; }
        if ( $int == 1 ) { $rval = $int + " " + $singular; }
        else { $rval = $int + " " + $singular + $suffix; }
        return $rval;
    }
    function bar($int, $str) {
       $rval = $int;
       if ( $str !="" ) { $rval = $int + 1; }
       return $rval;
    }
    
    $count = 0
    
    $strW = foo($W, "week", "s", true);
    $count = bar($count, $strW);
    
    $strD = foo($D, "day", "s", true);
    $count = bar($count, $strD);
    
    $strH = foo($H, "hour", "s", true);
    $count = bar($count, $strH);
    
    $sep1 = "";
    $sep2 = " and ";
    
    if ($count == 3) { $sep1=", ";}
    if ($count < 2) { $sep2=""; }
    
    $emit = $strW + $sep1 + $strD + $sep2 + $strH
    
    • 0

relate perguntas

  • substituindo zsh por bash no usuário não root

  • Tendo problemas para definir variáveis ​​de ambiente no Terminal no macOS High Sierra

  • Existe um equivalente a cd - para cp ou mv?

  • Notificar-enviar notificações aparecendo na janela

  • como abrir um arquivo de escritório do WSL

Sidebar

Stats

  • Perguntas 205573
  • respostas 270741
  • best respostas 135370
  • utilizador 68524
  • Highest score
  • respostas
  • Marko Smith

    Como posso reduzir o consumo do processo `vmmem`?

    • 11 respostas
  • Marko Smith

    Baixar vídeo do Microsoft Stream

    • 4 respostas
  • Marko Smith

    O Google Chrome DevTools falhou ao analisar o SourceMap: chrome-extension

    • 6 respostas
  • Marko Smith

    O visualizador de fotos do Windows não pode ser executado porque não há memória suficiente?

    • 5 respostas
  • Marko Smith

    Como faço para ativar o WindowsXP agora que o suporte acabou?

    • 6 respostas
  • Marko Smith

    Área de trabalho remota congelando intermitentemente

    • 7 respostas
  • Marko Smith

    O que significa ter uma máscara de sub-rede /32?

    • 6 respostas
  • Marko Smith

    Ponteiro do mouse movendo-se nas teclas de seta pressionadas no Windows?

    • 1 respostas
  • Marko Smith

    O VirtualBox falha ao iniciar com VERR_NEM_VM_CREATE_FAILED

    • 8 respostas
  • Marko Smith

    Os aplicativos não aparecem nas configurações de privacidade da câmera e do microfone no MacBook

    • 5 respostas
  • Martin Hope
    Saaru Lindestøkke Por que os arquivos tar.xz são 15x menores ao usar a biblioteca tar do Python em comparação com o tar do macOS? 2021-03-14 09:37:48 +0800 CST
  • Martin Hope
    CiaranWelsh Como posso reduzir o consumo do processo `vmmem`? 2020-06-10 02:06:58 +0800 CST
  • Martin Hope
    Jim Pesquisa do Windows 10 não está carregando, mostrando janela em branco 2020-02-06 03:28:26 +0800 CST
  • Martin Hope
    v15 Por que uma conexão de Internet gigabit/s via cabo (coaxial) não oferece velocidades simétricas como fibra? 2020-01-25 08:53:31 +0800 CST
  • Martin Hope
    andre_ss6 Área de trabalho remota congelando intermitentemente 2019-09-11 12:56:40 +0800 CST
  • Martin Hope
    Riley Carney Por que colocar um ponto após o URL remove as informações de login? 2019-08-06 10:59:24 +0800 CST
  • Martin Hope
    zdimension Ponteiro do mouse movendo-se nas teclas de seta pressionadas no Windows? 2019-08-04 06:39:57 +0800 CST
  • Martin Hope
    jonsca Todos os meus complementos do Firefox foram desativados repentinamente, como posso reativá-los? 2019-05-04 17:58:52 +0800 CST
  • Martin Hope
    MCK É possível criar um código QR usando texto? 2019-04-02 06:32:14 +0800 CST
  • Martin Hope
    SoniEx2 Altere o nome da ramificação padrão do git init 2019-04-01 06:16:56 +0800 CST

Hot tag

windows-10 linux windows microsoft-excel networking ubuntu worksheet-function bash command-line hard-drive

Explore

  • Início
  • Perguntas
    • Recentes
    • Highest score
  • tag
  • help

Footer

AskOverflow.Dev

About Us

  • About Us
  • Contact Us

Legal Stuff

  • Privacy Policy

Language

  • Pt
  • Server
  • Unix

© 2023 AskOverflow.DEV All Rights Reserve