Executa a expansão de parâmetros antes da expansão de chaves? [duplicado]

0

O manual do Bash diz que a expansão do contraventamento é realizada antes de qualquer outra expansão.

Estou escrevendo um script que aceita dois argumentos:

#! /bin/bash

for b in {$1..$2}; do echo $b; done

Eu corro como:

$ ./myscript 0002 0010
{0002..0010}

A saída não é o que eu espero. Espero realizar a expansão de parâmetros antes da expansão de chaves. A saída esperada do meu exemplo é 0002 0003 0004 0005 0006 0007 0008 0009 0010 , não 2 3 4 5 6 7 8 9 10 . Com o que você substituiria {$1..$2} ?

Espero que a solução funcione mesmo quando $1 e $2 forem sequências não apenas compostas de dígitos, mas também feitas de letras e dígitos.

Observe que os valores $1 e $2 só podem ser fornecidos como argumentos para o script. Eu acho que está claro desde o começo, mas aponte se não.

    
por Tim 22.04.2016 / 05:31

3 respostas

0

Expansão de Brace não é definida por POSIX, então talvez você possa abandoná-la ao todo:

seq $*

Ou:

j=$1
while [ $j -le $2 ]
do
  echo $j
  j=$((j+1))
done

Ou:

echo $* | awk '{for (j = $1; j <= $2; j++) print j}'
    
por 22.04.2016 / 05:42
0
#! /bin/bash

seq -w $1 $2

Isso pode ser o que você encontra!

    
por 22.04.2016 / 09:51
0

Para fazer o que você pede: realize a expansão de parâmetros antes da expansão de chaves.

Precisamos atrasar a expansão de chaves, o que é feito facilmente citando-lhe \{...\} e chamando eval:

$ set -- 5 10
$ eval printf \'%s \' \{$1..$2\}
5 6 7 8 9 10

Isso funcionaria bem, desde que não haja comandos dentro de $1 ou $2 .
Esse é um risco de segurança dessa solução. Uma maneira de atenuar o problema é garantir que as variáveis contenham apenas números:

#!/bin/bash

a=${1//[^0-9]/}          ### select only numbers from first parameter.
b=${2//[^0-9]/}          ### select only numbers from second parameter.

c=$(eval printf \'%s \' \{$a..$b\})

for i in $c; do echo "$i"; done

O código acima está faltando algumas citações que esta versão corrige:

#!/bin/bash
a=${1//[^0-9]/}          ### select only numbers from first parameter.
b=${2//[^0-9]/}          ### select only numbers from second parameter.
c=( $(eval printf \'%s \' \{$a..$b\}) )

for i in "${c[@]}"; do echo "$i"; done

### Or just
# printf '%s\n' "${c[@]}"

Mas, para imprimir uma lista de números, um loop aritmético for parece uma solução melhor:

#!/bin/bash

a=${1//[^0-9]/}          ### select only numbers from first parameter.
b=${2//[^0-9]/}          ### select only numbers from second parameter.

for (( i=$a; i<=$b; i++)); do
    printf '%0*d\n' 5 "$i"
done    

Use como:

$ script.sh 5 15
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
    
por 22.04.2016 / 06:16