Como encolher a expressão -eq do teste com mais de um valor var em / bin / sh

5
#!/bin/sh
if [ $num -eq 9 -o $num -eq 75 -o $num -eq 200 ]; then
    echo "do this"
elif [ $num -eq 40 -o $num -eq 53 -o $num -eq 63]; then
    echo "do something for this"
else
    echo "for other do this"
fi

Existe outra maneira de reduzir a expressão na instrução if ? Talvez algo como

[ $num -eq (9,75,200) ]

BTW, eu não tenho utilitários GNU neste SO.

    
por Ragnar Lodbrog 06.03.2016 / 08:20

5 respostas

7

Às vezes, uma construção diferente pode ficar mais legível:

case $num in
9|75|200) echo "do this" ;;
40|53|63) echo "do something for this" ;;
*)        echo "for other do this" ;;
esac
    
por 06.03.2016 / 09:26
3

cuidadoso, o posix não define teste com mais de 4 argumentos, então sua construção de teste é indefinida . veja a 6ª armadilha do bash

Então você precisaria, se usar teste, para ser mais detalhado:

if [ "$arg" = 9 ] || [ "$arg" = 75 ] || [ "$arg" = 200 ]

ou use caso em vez

case "$arg" in
     9|75|200)  do something ; ;
     40|53|63)  do that ;;
      *)  else ... ;;
 esac
    
por 06.03.2016 / 19:57
3

Parece um trabalho para uma função:

test_num() {
  n=$1; shift
  for arg do
    [ "$arg" -eq "$n" ] && return 0
  done
} 2>/dev/null

if test_num "$num" 9 75 200; then
  echo "do this"
elif test_num "$num" 40 53 63; then
  echo "do something for this"
else
  echo "for other do this"
fi
    
por 06.03.2016 / 17:06
1

Se você estiver usando bash ou ksh ou zsh (e talvez alguns outros, não me lembro agora), você pode usar [[ ... ]] em vez de [ ... ] , o que permite que você faça a expressão regular corresponde em sh.

por exemplo,

if [[ "$num" =~ ^(9|75|200)$ ]] ; then
    echo "do this"
elif [[ "$num" =~ ^(40|53|63)$ ]] ; then
    echo "do something for this"
else
    echo "for other do this"
fi

OBSERVAÇÃO: como você deseja uma correspondência exata nos números específicos, é importante que o regex esteja ancorado nas duas extremidades com ^ e $ , caso contrário, eles corresponderão a outros números que os contêm (por exemplo, '99' ou '7500' ou '163')

    
por 06.03.2016 / 08:40
0

Uma solução POSIX alternativa:

if     printf '%s' "$num" | grep -xE '(9|75|200)' >/dev/null; then
       echo "do this"
elif   printf '%s' "$num" | grep -xE '(40|53|63)' >/dev/null; then
       echo "do something for this"
else
       echo "for other do this" 
fi

Isso é muito lento ~ 50 vezes mais lento que a opção case .

Este é um menor e acredito que um script mais simples, apenas duas vezes o tempo da opção de caso:

#!/bin/sh

num="$1"    a='9 75 200'    b='40 53 63'

tnum() {
    for    arg
    do     [ "$arg" = "$num" ] && return 0
    done   return 1
}

if     tnum $a; then
            echo "do this"
elif   tnum $b; then
            echo "do something for this"
else
            echo "for other do this"
fi

CAVEAT: Nenhum teste [ "$arg" = "$num" ] funcionará em todos os casos, isso falha em 00 = 0 , por exemplo.
E um teste numérico [ "$arg" -eq "$num" ] não corresponderá aos valores vazios [ "" -eq "" ] .

Você pode escolher o que funciona melhor no seu caso.

    
por 06.03.2016 / 16:04