¿Cómo poner a cero una secuencia de enteros en bash para que todos tengan el mismo ancho?

429

Necesito recorrer algunos valores,

for i in $(seq $first $last)
do
    does something here
done

Para $firsty $last, necesito que sea de longitud fija 5. Entonces, si la entrada es 1, necesito agregar ceros al frente para que se convierta 00001. Se repite hasta, 99999por ejemplo, pero la longitud debe ser 5.

Por ejemplo: 00002, 00042, 00212, 012312y así sucesivamente.

¿Alguna idea de cómo puedo hacer eso?

John Marston
fuente
22
Una buena respuesta podría ser: seq - w 1 99999. Opción -w mantiene constante la longitud de salida, rellenando los números más cortos con 0.
Bruno von Paris
También cambie el nombre de los archivos: stackoverflow.com/questions/55754/bash-script-to-pad-file-names
Ciro Santilli 郝海东 冠状 病 六四 事件 法轮功
Aquí se recomiendan muchas respuestas, for variable in $(something to generate the numbers); do ...pero esto es problemático cuando la lista de números es larga. Es mucho más eficiente de usar something to generate the numbers | while read -r variable; do .... Consulte también mywiki.wooledge.org/DontReadLinesWithFor, que analiza la lectura de líneas de archivos, etc., pero algunos de los argumentos también se aplican aquí.
tripleee

Respuestas:

712

En su caso específico, aunque probablemente sea más fácil usar el -findicador seqpara formatear los números a medida que genera la lista. Por ejemplo:

for i in $(seq -f "%05g" 10 15)
do
  echo $i
done

producirá el siguiente resultado:

00010
00011
00012
00013
00014
00015

En términos más generales, bashtiene printfuna función integrada para que pueda rellenar la salida con ceros de la siguiente manera:

$ i=99
$ printf "%05d\n" $i
00099

Puede usar la -vbandera para almacenar la salida en otra variable:

$ i=99
$ printf -v j "%05d" $i
$ echo $j
00099

Tenga en cuenta que printfadmite un formato ligeramente diferente al seqque necesita usar en %05dlugar de %05g.

Dave Webb
fuente
55
%05gen lugar de %05darreglarlo para mí "00026" me estaba dando "00022" . ¡Gracias!
Ed Manet
12
Gran respuesta integral. Una pequeña corrección: estrictamente hablando, seqadmite un subconjunto de caracteres de formato. que printfadmite (y que los subconjuntos incluyen g, pero no d). El comportamiento de los caracteres dy gdifiere sutilmente en que dinterpreta las 0cadenas de números prefijadas como números octales y los convierte a decimales, mientras que los gtrata como decimales. (@EdManet: por eso '00026' se convirtió en '00022' con d). Otra cosa vale la pena mencionar: seq -whace automática relleno con ceros de los números de salida en función del número más amplia generada.
mklement0
Esto me ayudó a generar la lista de caracteres hexadecimales. for (( i = 0; i <= 0xffffffff; i++ )) do printf "%08x\n" $i ; done >> hex.txtprodujo una lista hexadecimal de 8 caracteres. Gracias.
cde
seq --help: "FORMATO debe ser adecuado para imprimir un argumento de tipo 'doble'; el valor predeterminado es% .PRECf si FIRST, INCREMENT y LAST son números decimales de punto fijo con PREC de máxima precisión, y% g en caso contrario". Los posibles especificadores de conversión son efgaEFGA.
x-yuri
133

Más fácil aún puedes hacer

for i in {00001..99999}; do
  echo $i
done
Indie
fuente
16
Esto funciona en Bash versión 4.1.2 (CentOS 6) pero falla en la versión 3.2.25 (CentOS 5). ¡Estoy de acuerdo en que esta es una forma mucho más estética de hacerlo!
Mike Starov
1
Funciona, pero no da cadenas sin relleno en mi bash
user2707001
En una Mac (Bash 4.4), esto no rellena los números. ¡En CentOS y SuSE, funciona muy bien!
Stefan Lasiewski
Esto funciona bien en macOS con Bash4.4.23(1)-release
Whymarrh
Tampoco funciona en Bash 5 en OS X, lamentablemente
gotofritz
91

Si el final de la secuencia tiene una longitud máxima de relleno (por ejemplo, si desea 5 dígitos y el comando es "seq 1 10000"), entonces puede usar el indicador "-w" para la secuencia: agrega el relleno mismo.

seq -w 1 10

Produce

01
02
03
04
05
06
07
08
09
10
m_messiah
fuente
77
Esta es obviamente la respuesta correcta. ¿Por qué tiene tan pocos votos a favor? Ad
adius
55
fácil, porque el relleno depende del número máximo que desea alcanzar. Si este es un parámetro que nunca sabe de antemano con cuántos cero terminará
guillem
55
Esto no proporciona una longitud fija especificada, solo resultados que tienen la misma longitud.
Ceisc
78

use printf con "% 05d" ej.

printf "%05d" 1
frankc
fuente
18

Muy simple usando printf

[jaypal:~/Temp] printf "%05d\n" 1
00001
[jaypal:~/Temp] printf "%05d\n" 2
00002
jaypal singh
fuente
12

Use awk así:

awk -v start=1 -v end=10 'BEGIN{for (i=start; i<=end; i++) printf("%05d\n", i)}'

SALIDA:

00001
00002
00003
00004
00005
00006
00007
00008
00009
00010

Actualizar:

Como alternativa de bash puro, puede hacer esto para obtener el mismo resultado:

for i in {1..10}
do
   printf "%05d\n" $i
done

De esta manera, puede evitar el uso de un programa externo seqque NO está disponible en todos los sabores de * nix.

anubhava
fuente
1
Podemos usar la awk's BEGINdeclaración para no tener que usar la heredoctarea.
jaypal singh
@ JaypalSingh: Gracias amigo, ese es un buen punto. Actualicé mi respuesta.
anubhava
9

Relleno la salida con más dígitos (ceros) de los que necesito, luego uso tail para usar solo la cantidad de dígitos que estoy buscando. Tenga en cuenta que debe usar '6' en la cola para obtener los últimos cinco dígitos :)

for i in $(seq 1 10)
do
RESULT=$(echo 00000$i | tail -c 6)
echo $RESULT
done
unifex
fuente
Si desea usar el número correcto de lugares en el argumento -c de tail, podría usar 'echo -n 00000 $ i' ya que esto evita que genere una nueva línea que es uno de los caracteres que regresa tail, por lo tanto, debe ser uno más alto en esta respuesta. Dependiendo de lo que esté haciendo, la nueva línea, si se deja, puede afectar los resultados.
Ceisc
Usar un proceso externo para recortar la variable en el bucle es bastante ineficiente. En su lugar, puede utilizar las funciones de expansión de parámetros del shell . En Bash hay una facilidad para extraer una subcadena particular por índice, o puede usar las sustituciones de prefijos y sufijos con un patrón que coincida con el ancho deseado, aunque requiere un poco de ida y vuelta.
tripleee
4

Si desea N dígitos, agregue 10 ^ N y elimine el primer dígito.

for (( num=100; num<=105; num++ ))
do
  echo ${num:1:3}
done

Salida:

01
02
03
04
05
Burghard Hoffmann
fuente
2

Esto también funcionará:

for i in {0..9}{0..9}{0..9}{0..9}
do
  echo "$i"
done
Chris
fuente
Buena solución! Limpio, fácil de leer, no se necesitan programas adicionales.
Jonathan Cross
2

Otra manera :

zeroos="000"
echo 

for num in {99..105};do
 echo ${zeroos:${#num}:${#zeroos}}${num}
done

Entonces, la función simple para convertir cualquier número sería:

function leading_zero(){

    local num=$1
    local zeroos=00000
    echo ${zeroos:${#num}:${#zeroos}}${num} 

}
Paco
fuente
1

Una forma de utilizar la bifurcación externa del proceso es la manipulación de cadenas, en un caso genérico se vería así:

#start value
CNT=1

for [whatever iterative loop, seq, cat, find...];do
   # number of 0s is at least the amount of decimals needed, simple concatenation
   TEMP="000000$CNT"
   # for example 6 digits zero padded, get the last 6 character of the string
   echo ${TEMP:(-6)}
   # increment, if the for loop doesn't provide the number directly
   TEMP=$(( TEMP + 1 ))
done

Esto también funciona bastante bien en WSL, donde la bifurcación es una operación realmente pesada. Tenía una lista de 110000 archivos, el uso printf "%06d" $NUMtomó más de 1 minuto, la solución anterior se ejecutó en aproximadamente 1 segundo.

Tamisoft
fuente
0

1.) Cree una secuencia de números 'seq' del 1 al 1000 y fije el ancho '-w' (el ancho se determina por la longitud del número final, en este caso 4 dígitos para 1000).

2.) Además, seleccione qué números desea usar 'sed -n' (en este caso, seleccionamos los números 1-100).

3.) 'echo' cada número. Los números se almacenan en la variable 'i', a la que se accede mediante '$'.

Pros: este código es bastante limpio.

Contras: 'seq' no es nativo de todos los sistemas Linux (según tengo entendido)

for i in `seq -w 1 1000 | sed -n '1,100p'`; 
do 
    echo $i; 
done
mella
fuente
0

Si está justo después de rellenar números con ceros para lograr una longitud fija, simplemente agregue el múltiplo más cercano de 10, por ejemplo. para 2 dígitos, agregue 10 ^ 2, luego elimine el primer 1 antes de mostrar la salida.

Esta solución funciona para rellenar / formatear números individuales de cualquier longitud, o una secuencia completa de números usando un bucle for.

# Padding 0s zeros:
# Pure bash without externals eg. awk, sed, seq, head, tail etc.
# works with echo, no need for printf

pad=100000      ;# 5 digit fixed

for i in {0..99999}; do ((j=pad+i))
    echo ${j#?}
done

Probado en Mac OSX 10.6.8, Bash ver 3.2.48

Zimba
fuente