Alternativa portátil do shell POSIX para o seq do GNU (1)?

6

Eu notei que você não pode realmente contar com seq(1) estando disponível em qualquer coisa, exceto nos sistemas GNU. O que é uma reimplementação simples de seq(1) posso trazer comigo escrito em shell POSIX (não bash)?

EDIT: Note que eu pretendo usá-lo em pelo menos vários BSD's, Solaris e Mac OS X.

    
por Elizafox 25.07.2016 / 19:23

3 respostas

5

De acordo com o grupo aberto o POSIX awk suporta BEGIN , portanto, isso pode ser feito em awk :

awk -v MYEND=6 'BEGIN { for(i=1;i<=MYEND;i++) print i }'

Onde -v MYEND=6 representaria a atribuição como no primeiro argumento para seq . Em outras palavras, isso também funciona:

END=6
for i in 'awk -v MYEND=$END 'BEGIN { for(i=1;i<=MYEND;i++) print i }''; do
    echo $i
done

Ou mesmo com três variáveis (início, incremento e fim):

S=2
I=2
E=12
for i in 'awk -v MYS=$S -v MYI=$I -v MYE=$E 'BEGIN { for(i=MYS;i<=MYE;i+=MYI) print i }''; do
    echo $i
done

Nota extra do Solaris : no Solaris /usr/bin/awk é não compatível com POSIX, você precisa usar nawk ou /usr/xpg4/bin/awk no Solaris.

No Solaris, você provavelmente desejará definir /usr/xpg4/bin antecipadamente no PATH se estiver executando um script compatível com POSIX.

Resposta de referência:

por 25.07.2016 / 19:36
6

Uma alternativa para awk é bc :

seq() (first=$1 incr=$2 last=$3
  echo "for (i = $first; i <= $last; i+=$incr) i" | bc -l
)

Uma vantagem é que você não está limitado pelo tamanho / resolução dos duplos do seu processador:

$ seq '(2^200)' '(2^100)' '(2^200+2^102)'
1606938044258990275541962092341162602522202993782792835301376
1606938044258990275541962092342430253122431223184289538506752
1606938044258990275541962092343697903722659452585786241712128
1606938044258990275541962092344965554322887681987282944917504
1606938044258990275541962092346233204923115911388779648122880

Mas cuidado com a quebra de linha quando os números ficarem muito grandes:

$ seq '(2^500)' '(2^100)' '(2^500+2^101)'
32733906078961418700131896968275991522166420460430647894832913680961\
33796404674554883270092325904157150886684127560071009217256545885393\
053328527589376
32733906078961418700131896968275991522166420460430647894832913680961\
33796404674554883270092325904157150886684127560071010484907146113622\
454825230794752
32733906078961418700131896968275991522166420460430647894832913680961\
33796404674554883270092325904157150886684127560071011752557746341851\
856321934000128
    
por 28.07.2016 / 15:39
2

Acabei escrevendo um em ksh há um tempo atrás; não é tão à prova de balas quanto poderia ser, porque eu escrevi para mim, mas deve ser um bom começo. Não tenho certeza se ele funcionaria com o shell Bourne puro, já que seu Q está marcado atualmente, por causa da sintaxe $ (()).

#!/usr/bin/ksh

start=1
end=1
step=1

case $# in
        0)
                echo Usage: $0 '[Start [Step]] End'
                exit 0
                ;;
        1)
                end=$1
                ;;
        2)
                start=$1
                end=$2
                ;;
        3)
                start=$1
                step=$2
                end=$3
                ;;
esac

# quick & dirty validations
if [ $step -eq 0 ]
then
  exit 1
fi

if [ $step -gt 0 ]
then
  if [ $start -gt $end ]
  then
    exit 2
  fi
else
  if [ $start -lt $end ]
  then
    exit 3
  fi
fi

i=$start
if [ $step -gt 0 ]
then
  while [ $i -le $end ]
  do
    printf "%d\n" $i
    i=$(( i + step ))
  done
else
  while [ $i -ge $end ]
  do
    printf "%d\n" $i
    i=$(( i + step ))
  done
fi
    
por 25.07.2016 / 19:27