Cómo crear una secuencia con ceros a la izquierda usando la expansión de llaves

46

Cuando uso lo siguiente, obtengo un resultado como se esperaba:

$ echo {8..10}
8 9 10

¿Cómo puedo usar esta expansión de llaves de una manera fácil para obtener el siguiente resultado?

$ echo {8..10}
08 09 10

Ahora sé que esto se puede obtener usando seq(no lo intenté), pero eso no es lo que estoy buscando.

La información útil puede ser que estoy restringido a esta versión bash. (Si tiene una zshsolución, pero no tiene bashsolución, compártala también)

$ bash -version
GNU bash, version 3.2.51(1)-release (x86_64-suse-linux-gnu)
Bernhard
fuente
Alguna pista para hacer esto en bash 3 que encontré aquí: mywiki.wooledge.org/BashFAQ/018 Sin embargo, el enfoque descrito allí no es conveniente.
Bernhard
stackoverflow.com/questions/8789729/zero-padding-in-bash
Ciro Santilli 新疆 改造 中心 法轮功 六四 事件

Respuestas:

70

Prefije el primer número con a 0para forzar que cada término tenga el mismo ancho.

$ echo {08..10}
08 09 10

Desde la sección de la página de manual de bash sobre Expansión de Brace:

Los enteros suministrados pueden tener el prefijo 0 para forzar que cada término tenga el mismo ancho. Cuando x o y comienza con un cero, el shell intenta forzar todos los términos generados para que contengan la misma cantidad de dígitos, rellenando con ceros cuando sea necesario.

También tenga en cuenta que puede usar seqla -wopción para igualar el ancho rellenando con ceros a la izquierda:

$ seq -w 8 10
08
09
10

$ seq -s " " -w 8 10
08 09 10

Si desea más control, incluso puede especificar un formato de estilo printf:

$ seq -s " " -f %02g 8 10
08 09 10
dogbane
fuente
8
echo {08..10}Sin embargo, después de enterarse de la solución, solo se presenta para bash versión 4 y superior.
Bernhard
Eso me incomoda un poco que bash haga eso. Para un grupo de utilidades (por ejemplo perl), un cero inicial indica un número octal. Supongo que no es frecuente que desee una secuencia de números octales ...
kurtm
55
Debe tenerse en cuenta que también puede prefijar los números al dar entonces a seqcon el -winterruptor de la siguiente manera: seq -w 003produce los números 001, 002 y 003.
slm
@kurtm no te preocupes por los ceros a la izquierda. Eso podría doler cuando algo intenta analizar un número. Lo que esto es realmente útil es generar una secuencia de nombre de archivo foo_00001.someextensiondonde casi todos los contextos de ordenación proporcionen una ordenación sensata.
Stéphane Gourichon
9

si usas printf

printf "%.2d " {8..10} 

esto forzará a ser 2 caracteres y agregará un 0. inicial. En caso de que necesite 3 dígitos, puede cambiar a "% .3d".

BitsOfNix
fuente
Gracias por tu respuesta. Soy consciente de la printfsolución, pero en realidad no está facilitando esto. Espero que haya algún truco oculto que haga el trabajo :)
Bernhard
Esta es la única respuesta que parece lo suficientemente versátil como para manejar cualquier circunstancia para el origen del número para rellenar. Estoy usando un contador mientras recorro los archivos. Esta solución printf cero rellena perfectamente mientras que todos los demás parecen centrarse en generar números con relleno de cero en lugar de números existentes con relleno de cero.
mightypile el
7

Use un rango que comience con un dígito constante y elimine ese dígito:

echo \ {108..110} | sed 's/ 1//g'

o sin usar un comando externo:

a=({108..110}); echo "${a[@]#1}"

Para usar en un bucle for:

for x in {108..110}; do
  x=${x#1}
  
done

aunque para este caso un ciclo while sería más claro y funciona en cualquier shell POSIX:

x=8
while [ $x -le 10 ]; do
  n=$((100+x)); n=${n#1}
  
  x=$((x+1))
done
Gilles 'SO- deja de ser malvado'
fuente
Acepté esta respuesta sobre las otras respuestas, porque satisface la solicitud de Bash 3.x. Especialmente porque necesitaba el forbucle de todos modos.
Bernhard el
6

Tengo la misma versión bash del póster original ( GNU bash, version 3.2.51(1)-release) y {08..12}no funciona para mí, pero lo siguiente sí:

for i in 0{8..9} {10..12}; do echo $i; done
08
09
10
11
12

Es un poco más tedioso, pero funciona en la versión OP de bash (y versiones posteriores, supongo).

Gregory Dulin
fuente
No pensé en esta solución (aunque en mi caso en realidad también quiero numerar 0001 1000, pero su principio funciona, por supuesto.
Bernhard
1

Como referencia, creo que el ancho fijo automático solo ocurre con la última versión de bash:

$ bash -version
GNU bash, version 3.2.25(1)-release (x86_64-redhat-linux-gnu)
Copyright (C) 2005 Free Software Foundation, Inc.

$ echo test{00..05}
test0 test1 test2 test3 test4 test5
Benjamin Goodacre
fuente
-3
for i in $(seq -s " " -f %0${zeros}g $ini $fin); do ....;done

los ceros, ini y fin son vars, así que es fácil, solo escribes ceros que digas en 'ceros' para que ini fin sin problemas;)

miniminiyo
fuente