Comment mettre à zéro une séquence d'entiers en bash pour que tous aient la même largeur?

429

J'ai besoin de boucler quelques valeurs,

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

Pour $firstet $last, j'ai besoin que ce soit de longueur fixe 5. Donc, si l'entrée est 1, j'ai besoin d'ajouter des zéros devant pour qu'ils deviennent 00001. Il boucle jusqu'à 99999par exemple, mais la longueur doit être de 5.

Par exemple: 00002, 00042, 00212, 012312et ainsi de suite.

Une idée sur comment je peux faire ça?

John Marston
la source
22
Une bonne réponse pourrait être: seq - w 1 99999. L'option -w maintient la longueur de sortie constante, remplissant les nombres les plus courts par 0.
Bruno von Paris
Renommez
De nombreuses réponses recommandent ici, for variable in $(something to generate the numbers); do ...mais cela pose problème lorsque la liste des numéros est longue. Il est beaucoup plus efficace à utiliser something to generate the numbers | while read -r variable; do .... Voir aussi mywiki.wooledge.org/DontReadLinesWithFor qui traite de la lecture de lignes à partir de fichiers, etc., mais certains des arguments s'appliquent ici aussi.
tripleee

Réponses:

712

Dans votre cas spécifique, il est probablement plus facile d'utiliser l' -findicateur seqpour obtenir un formatage des nombres lors de la sortie de la liste. Par exemple:

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

produira la sortie suivante:

00010
00011
00012
00013
00014
00015

Plus généralement, basha printfcomme intégré de sorte que vous pouvez remplir la sortie avec des zéros comme suit:

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

Vous pouvez utiliser l' -vindicateur pour stocker la sortie dans une autre variable:

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

Notez que printfprend en charge un format légèrement différent, seqvous devez donc utiliser à la %05dplace de %05g.

Dave Webb
la source
5
%05gau lieu de le %05dréparer pour moi. "00026" me donnait "00022" . Merci!
Ed Manet
12
Grande réponse complète. Une petite correction: à proprement parler, seqprend en charge un sous - ensemble des caractères de format. qui printfprend en charge (et que les sous-ensembles incluent g, mais pas d). Le comportement des caractères det gdiffère subtilement en ce qu'il dinterprète les 0chaînes de nombres préfixés comme des nombres octaux et les convertit en décimales, alors qu'il les gtraite comme des décimales. (@EdManet: c'est pourquoi '00026' est devenu '00022' avec d). Une autre mention de la valeur de chose: seq -wne automatique zéro padding des numéros de sortie en fonction du plus grand nombre possible généré.
mklement0
Cela m'a aidé à générer une liste de caractères hexadécimaux. for (( i = 0; i <= 0xffffffff; i++ )) do printf "%08x\n" $i ; done >> hex.txtproduit une liste hexadécimale à 8 caractères. Merci.
cde
seq --help: "FORMAT doit être approprié pour imprimer un argument de type 'double'; il vaut par défaut% .PRECf si FIRST, INCREMENT et LAST sont tous des nombres décimaux à virgule fixe avec une précision maximale PREC et à% g sinon." Les spécificateurs de conversion possibles sont efgaEFGA.
x-yuri
133

Plus simple encore, vous pouvez simplement le faire

for i in {00001..99999}; do
  echo $i
done
Indépendant
la source
16
Cela fonctionne sur la version Bash 4.1.2 (CentOS 6) mais échoue dans la version 3.2.25 (CentOS 5). Je suis d'accord que c'est une façon beaucoup plus esthétique de le faire!
Mike Starov
1
Fonctionne, mais ne donne pas de chaînes matelassées nulles sur mon bash
user2707001
Sur un Mac (Bash 4.4), cela ne remplit pas les chiffres. Sur CentOS et SuSE, cela fonctionne très bien!
Stefan Lasiewski
Cela fonctionne très bien sur macOS avec Bash4.4.23(1)-release
Whymarrh
Malheureusement, ne fonctionne pas sur Bash 5 sur OS X
gotofritz
91

Si la fin de la séquence a une longueur maximale de remplissage (par exemple, si vous voulez 5 chiffres et que la commande est "seq 1 10000"), vous pouvez utiliser l'indicateur "-w" pour seq - il ajoute le remplissage lui-même.

seq -w 1 10

produire

01
02
03
04
05
06
07
08
09
10
m_messiah
la source
7
C'est évidemment la bonne réponse. Pourquoi a-t-il si peu de votes positifs? 😳
adius
5
facile, car le rembourrage dépend du nombre maximum que vous souhaitez atteindre. S'il s'agit d'un paramètre que vous ne savez jamais à l'avance avec combien de zéro vous vous retrouverez
guillem
5
Cela ne donne pas une longueur fixe spécifiée, juste des résultats qui sont tous de la même longueur.
Ceisc
78

utiliser printf avec "% 05d" par exemple

printf "%05d" 1
Frankc
la source
18

Utilisation très simple printf

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

Utilisez awk comme ceci:

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

PRODUCTION:

00001
00002
00003
00004
00005
00006
00007
00008
00009
00010

Mise à jour:

Comme alternative bash pure, vous pouvez le faire pour obtenir la même sortie:

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

De cette façon, vous pouvez éviter d' utiliser un programme externe seqqui n'est PAS disponible sur toutes les versions de * nix.

anubhava
la source
1
Nous pouvons utiliser l' awk's BEGINinstruction afin de ne pas avoir à utiliser l' heredocaffectation.
jaypal singh
@JaypalSingh: Merci mon pote, c'est un bon point. Mis à jour ma réponse.
anubhava
9

Je remplis la sortie avec plus de chiffres (zéros) que je n'en ai besoin, puis j'utilise tail pour n'utiliser que le nombre de chiffres que je recherche. Notez que vous devez utiliser '6' en queue pour obtenir les cinq derniers chiffres :)

for i in $(seq 1 10)
do
RESULT=$(echo 00000$i | tail -c 6)
echo $RESULT
done
unifex
la source
Si vous vouliez utiliser le nombre correct de places dans l'argument -c de la queue, vous pourriez utiliser 'echo -n 00000 $ i' car cela l'empêche de sortir une nouvelle ligne qui est l'un des caractères que la queue retourne, d'où la nécessité de soyez un plus haut dans cette réponse. Selon ce que vous faites alors, la nouvelle ligne, si elle est laissée, peut affecter les résultats.
Ceisc
L'utilisation d'un processus externe pour découper la variable dans la boucle est plutôt inefficace. Vous pouvez utiliser les fonctionnalités d' extension des paramètres du shell à la place. Dans Bash, il est possible d'extraire une sous-chaîne particulière par index, ou vous pouvez utiliser les substitutions de préfixe et de suffixe avec un modèle qui correspond à la largeur souhaitée, bien que cela nécessite un peu de va-et-vient.
tripleee
4

Si vous voulez N chiffres, ajoutez 10 ^ N et supprimez le premier chiffre.

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

Production:

01
02
03
04
05
Burghard Hoffmann
la source
2

Cela fonctionnera également:

for i in {0..9}{0..9}{0..9}{0..9}
do
  echo "$i"
done
Chris
la source
Bonne solution! Propre, facile à lire, aucun programme supplémentaire n'est nécessaire.
Jonathan Cross
2

Autre moyen:

zeroos="000"
echo 

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

La fonction si simple pour convertir n'importe quel nombre serait:

function leading_zero(){

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

}
Paco
la source
1

Une façon sans utiliser de forking de processus externe est la manipulation de chaînes, dans un cas générique, cela ressemblerait à ceci:

#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

Cela fonctionne également très bien sur WSL, où la fourche est une opération très lourde. J'avais une liste de 110000 fichiers, en utilisant printf "%06d" $NUMplus de 1 minute, la solution ci-dessus a fonctionné en environ 1 seconde.

Tamisoft
la source
0

1.) Créez une séquence de nombres «seq» de 1 à 1000 et fixez la largeur «-w» (la largeur est déterminée par la longueur du numéro de fin, dans ce cas, 4 chiffres pour 1000).

2.) Sélectionnez également les numéros que vous souhaitez en utilisant 'sed -n' (dans ce cas, nous sélectionnons les numéros 1-100).

3.) 'écho' sur chaque numéro. Les nombres sont stockés dans la variable «i», accessible à l'aide du «$».

Avantages: Ce code est assez propre.

Inconvénients: 'seq' n'est pas natif sur tous les systèmes Linux (si je comprends bien)

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

Si vous êtes juste après le remplissage des nombres avec des zéros pour obtenir une longueur fixe, ajoutez simplement le multiple de 10 le plus proche, par exemple. pour 2 chiffres, ajoutez 10 ^ 2, puis supprimez le premier 1 avant d'afficher la sortie.

Cette solution fonctionne pour remplir / formater des nombres simples de n'importe quelle longueur, ou une séquence entière de nombres en utilisant une boucle 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

Testé sur Mac OSX 10.6.8, Bash ver 3.2.48

Zimba
la source