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


426

Мені потрібно циклічити деякі значення,

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.
Бруно фон Париж,


Багато відповідей тут рекомендують, for variable in $(something to generate the numbers); do ...але це проблематично, коли список номерів довгий. Це набагато ефективніше використовувати something to generate the numbers | while read -r variable; do .... Дивіться також mywiki.wooledge.org/DontReadLinesWithДля якої обговорюється читання рядків з файлів тощо, але деякі аргументи застосовуються і тут.
трійка

Відповіді:


710

У вашому конкретному випадку, хоча, мабуть, найпростіше використовувати -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вбудовані рядки чисел як вісімкові числа та перетворює їх у десяткові, тоді як gтрактує їх як десяткові. (@EdManet: тому "00026" перетворився на "00022" з d). Ще одна річ, яку варто згадати: seq -wчи робить автоматичне нульове прокладення вихідних чисел на основі найширшого створеного числа.
mklement0

Це допомогло мені генерувати шістнадцятковий список символів. for (( i = 0; i <= 0xffffffff; i++ )) do printf "%08x\n" $i ; done >> hex.txtстворив 8-символьний шістнадцятковий список. Дякую.
cde

seq --help: "FORMAT повинен бути придатним для друку одного аргументу типу" подвійний "; він за замовчуванням до% .PRECf, якщо FIRST, INCREMENT та LAST - це десяткові числа з фіксованою точкою з максимальною точністю PREC, і в% g в іншому випадку." Можливі специфікатори перетворення є efgaEFGA.
x-yuri

133

Простіше все-таки просто зробити

for i in {00001..99999}; do
  echo $i
done

16
Це працює в Bash версії 4.1.2 (CentOS 6), але не працює у версії 3.2.25 (CentOS 5). Я згоден, що це набагато естетичніший спосіб зробити це!
Майк Старов

1
Працює, але не дає нульових рядків на моєму
баші

На 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

7
Це, очевидно, правильна відповідь. Чому в ньому так мало оновлень? 😳
adius

5
легко, адже прокладка залежить від максимальної кількості, яку ви хочете досягти. Якщо це параметр, ви ніколи не знаєте заздалегідь, скільки нулів ви закінчите
guillem

5
Це не дає заданої фіксованої довжини, а результати, які мають однакову довжину.
Ceisc



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завдання.
jaypal singh

@JaypalSingh: Спасибі, товариш, це хороший момент. Оновлено мою відповідь.
анубхава

9

Я проводжу висновок з більшою кількістю цифр (нулів), ніж мені потрібно, тоді використовую хвіст, щоб використовувати лише кількість цифр, які я шукаю. Зауважте, що вам потрібно використати "6" в хвіст, щоб отримати останні п'ять цифр :)

for i in $(seq 1 10)
do
RESULT=$(echo 00000$i | tail -c 6)
echo $RESULT
done

Якщо ви хочете використовувати правильну кількість місць в аргументі -c хвоста, ви можете використовувати "echo -n 00000 $ i", оскільки це зупиняє його виведення нового рядка, який повертається одним із символів "chars", отже, йому потрібно бути на цю відповідь вище. Залежно від того, що ви тоді робите, новий рядок, якщо він залишиться, може вплинути на результати.
Ceisc

Використання зовнішнього процесу для обрізки змінної в циклі є досить неефективним. Ви можете замість цього використовувати функції розширення параметрів оболонки . У Bash є можливість вилучення певної підрядки за індексом, або ви можете використовувати замінники префікса та суфікса з малюнком, який відповідає бажаній ширині, хоча для цього потрібно трохи назад і вперед.
трійка

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} 

}

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 секунду.


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, наприклад. для двох цифр додайте 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

Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.