Как обнулить последовательность целых чисел в bash, чтобы все они имели одинаковую ширину?

429

Мне нужно зациклить некоторые значения,

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

Для $firstи $lastмне нужно, чтобы он был фиксированной длины 5. Так что, если ввод 1, мне нужно добавить нули перед таким, чтобы он стал 00001. Это петли до 99999, например, но длина должна быть 5.

Например: 00002, 00042, 00212, 012312и так далее.

Любая идея о том, как я могу это сделать?

Джон Марстон
источник
22
Хороший ответ может быть следующим: seq - w 1 99999. Опция -w поддерживает постоянную длину вывода, добавляя кратчайшие числа с 0.
Bruno von Paris
Также переименуйте файлы: stackoverflow.com/questions/55754/bash-script-to-pad-file-names
Ciro Santilli 郝海东 冠状 病 六四 事件 法轮功
Многие ответы здесь рекомендуют, for variable in $(something to generate the numbers); do ...но это проблематично, когда список чисел длинный. Это гораздо эффективнее в использовании something to generate the numbers | while read -r variable; do .... Смотрите также mywiki.wooledge.org/DontReadLinesWithFor, в котором обсуждается чтение строк из файлов и т. Д., Но некоторые аргументы применимы и здесь.
tripleee

Ответы:

713

Хотя в вашем конкретном случае, вероятно, проще всего использовать -fфлаг, seqчтобы заставить его форматировать числа при выводе списка. Например:

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

выдаст следующий вывод:

00010
00011
00012
00013
00014
00015

В более общем смысле, bashимеет printfвстроенную функцию, так что вы можете дополнить вывод нулями следующим образом:

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

Вы можете использовать -vфлаг, чтобы сохранить выходные данные в другой переменной:

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

Обратите внимание, что printfподдерживается немного другой формат, seqпоэтому вам нужно использовать %05dвместо %05g.

Дэйв Уэбб
источник
5
%05gвместо того, чтобы %05dисправить это для меня. «00026» давал мне «00022» . Спасибо!
Эд Мане
12
Отличный, исчерпывающий ответ. Одно небольшое исправление: строго говоря, seqподдерживает подмножество символов формата. который printfподдерживает (и что включает в себя подмножества g, но не d). Поведение персонажей dи gотличается тонко в том , что dинтерпретирует 0-prefixed числа строк в восьмеричном чисел и преобразует их в десятичной системе , а gрассматривает их как десятичные дроби. (@EdManet: именно поэтому «00026» превратился в «00022» с d). Еще одна вещь, о которой стоит упомянуть: seq -wвыполняет автоматическое заполнение нулями выходных чисел на основе самого широкого сгенерированного числа.
mklement0
Это помогло мне создать список шестнадцатеричных символов. for (( i = 0; i <= 0xffffffff; i++ )) do printf "%08x\n" $i ; done >> hex.txtсоздал 8-значный шестнадцатеричный список. Спасибо.
cd
seq --help: «FORMAT должен быть пригоден для печати одного аргумента типа 'double'; по умолчанию используется% .PRECf, если FIRST, INCREMENT и LAST являются десятичными числами с фиксированной запятой с максимальной точностью PREC и% g в противном случае." Возможные спецификаторы преобразования являются efgaEFGA.
x-
133

Проще еще можно просто сделать

for i in {00001..99999}; do
  echo $i
done
Инди
источник
16
Это работает в Bash версии 4.1.2 (CentOS 6), но не работает в версии 3.2.25 (CentOS 5). Я согласен, что это гораздо более эстетичный способ сделать это!
Майк Старов
1
Работает, но не дает заполненных нулями строк на моем bash
user2707001
На Mac (Bash 4.4) это не дополняет цифры. На CentOS & SuSE это прекрасно работает!
Стефан Ласевский
Это хорошо работает на macOS с Bash4.4.23(1)-release
Whymarrh
К сожалению, не работает на Bash 5 на OS X
gotofritz
91

Если конец последовательности имеет максимальную длину заполнения (например, если вы хотите 5 цифр и команда имеет значение «seq 1 10000»), то вы можете использовать флаг «-w» для seq - он добавляет сам заполнитель.

seq -w 1 10

производить

01
02
03
04
05
06
07
08
09
10
m_messiah
источник
7
Это, очевидно, правильный ответ. Почему у него так мало голосов? Ad
adius
5
легко, потому что заполнение зависит от максимального числа, которое вы хотите достичь. Если это параметр, вы никогда не знаете заранее, сколько нулей вы получите
guillem
5
Это не дает заданную фиксированную длину, просто результаты, которые имеют одинаковую длину.
Ceisc
78

используйте printf с "% 05d", например

printf "%05d" 1
frankc
источник
18

Очень простое использование printf

[jaypal:~/Temp] printf "%05d\n" 1
00001
[jaypal:~/Temp] printf "%05d\n" 2
00002
Джайпал Сингх
источник
12

Используйте awk следующим образом:

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

ВЫВОД:

00001
00002
00003
00004
00005
00006
00007
00008
00009
00010

Обновить:

В качестве чистой альтернативы bash вы можете сделать это, чтобы получить тот же результат:

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

Таким образом, вы можете избежать использования внешней программы, seqкоторая НЕ доступна для всех разновидностей * nix.

анубхава
источник
1
Мы можем использовать awk's BEGINоператор так, чтобы нам не приходилось использовать heredocприсвоение.
Джайпал Сингх
@JaypalSingh: Спасибо, приятель, это хороший момент. Обновил мой ответ.
анубхава
9

Я дополняю вывод большим количеством цифр (нулей), чем мне нужно, затем использую tail, чтобы использовать только то количество цифр, которое я ищу. Обратите внимание, что вы должны использовать «6» в хвосте, чтобы получить последние пять цифр :)

for i in $(seq 1 10)
do
RESULT=$(echo 00000$i | tail -c 6)
echo $RESULT
done
Unifex
источник
Если вы хотите использовать правильное количество мест в аргументе -c хвоста, вы можете использовать 'echo -n 00000 $ i', так как это останавливает вывод новой строки, возвращаемой одним из символов, возвращаемым хвостом, следовательно, ему нужно быть на один уровень выше в этом ответе. В зависимости от того, что вы делаете, символ новой строки, если он останется, может повлиять на результаты.
Ceisc
Использование внешнего процесса для обрезки переменной в цикле довольно неэффективно. Вместо этого вы можете использовать функции расширения параметров оболочки . В Bash есть средство для извлечения конкретной подстроки по индексу, или вы можете использовать подстановку префикса и суффикса с шаблоном, который соответствует желаемой ширине, хотя это требует немного вперед-назад.
tripleee
4

Если вы хотите N цифр, добавьте 10 ^ N и удалите первую цифру.

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

Вывод:

01
02
03
04
05
Бургхард Хоффманн
источник
2

Это будет работать также:

for i in {0..9}{0..9}{0..9}{0..9}
do
  echo "$i"
done
Крис
источник
Отличное решение! Чистый, легко читаемый, никаких дополнительных программ не требуется.
Джонатан Кросс
2

Другой путь :

zeroos="000"
echo 

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

Так что простая функция для преобразования любого числа будет:

function leading_zero(){

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

}
Paco
источник
1

Один из способов без использования внешнего процесса - это манипулирование строками, в общем случае это будет выглядеть так:

#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

Это хорошо работает и на WSL, где разветвление - очень тяжелая операция. У меня был список 110000 файлов, использование printf "%06d" $NUMзаняло более 1 минуты, решение выше заняло около 1 секунды.

Tamisoft
источник
0

1.) Создайте последовательность чисел 'seq' от 1 до 1000 и зафиксируйте ширину '-w' (ширина определяется длиной конечного числа, в данном случае 4 цифры на 1000).

2.) Кроме того, выберите, какие цифры вы хотите, используя «sed -n» (в этом случае мы выбираем номера 1-100).

3.) «эхо» каждого номера. Числа хранятся в переменной «i», доступ к которой осуществляется с помощью «$».

Плюсы: этот код довольно чистый.

Минусы: seq не свойственен всем системам Linux (насколько я понимаю)

for i in `seq -w 1 1000 | sed -n '1,100p'`; 
do 
    echo $i; 
done
Ник
источник
0

Если вы просто добавляете числа с нулями для достижения фиксированной длины, просто добавьте ближайшее кратное 10, например. для 2 цифр добавьте 10 ^ 2, затем удалите первую 1 перед отображением вывода.

Это решение работает для заполнения / форматирования отдельных чисел любой длины или целой последовательности чисел с использованием цикла 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

Протестировано на Mac OSX 10.6.8, Bash ver 3.2.48

Zimba
источник