Bagaimana nol pad urutan bilangan bulat di bash sehingga semua memiliki lebar yang sama?

429

Saya perlu mengulang beberapa nilai,

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

Untuk $firstdan $last, saya perlu panjangnya tetap 5. Jadi jika inputnya 1, saya perlu menambahkan nol di depan sehingga menjadi 00001. 99999Misalnya loop , tetapi panjangnya harus 5.

Misalnya: 00002, 00042, 00212, 012312dan sebagainya.

Ada ide tentang bagaimana saya bisa melakukan itu?

John Marston
sumber
22
Jawaban yang bagus adalah: seq - w 1 99999. Opsi -w membuat output tetap konstan, menambahkan angka terpendek dengan 0.
Bruno von Paris
Juga ganti nama file: stackoverflow.com/questions/55754/bash-script-to-pad-file-names
Ciro Santilli 郝海东 冠状 病 六四 六四 事件 法轮功
Banyak jawaban di sini merekomendasikan for variable in $(something to generate the numbers); do ...tetapi ini bermasalah ketika daftar angka panjang. Ini jauh lebih efisien untuk digunakan something to generate the numbers | while read -r variable; do .... Lihat juga mywiki.wooledge.org/DontReadLinesWithFor yang membahas membaca baris dari file dll, tetapi beberapa argumen juga berlaku di sini.
tripleee

Jawaban:

712

Dalam kasus spesifik Anda, mungkin paling mudah menggunakan -fbendera sequntuk memformat angka saat mengeluarkan daftar. Sebagai contoh:

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

akan menghasilkan output berikut:

00010
00011
00012
00013
00014
00015

Secara umum, bashmemiliki printfbuilt-in sehingga Anda dapat menambahkan output dengan nol sebagai berikut:

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

Anda bisa menggunakan -vflag untuk menyimpan output di variabel lain:

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

Perhatikan bahwa printfmendukung format yang sedikit berbeda untuk seqsehingga Anda perlu menggunakan %05dbukan %05g.

Dave Webb
sumber
5
%05gbukannya %05dmemperbaikinya untuk saya. "00026" memberi saya "00022" . Terima kasih!
Ed Manet
12
Jawaban hebat dan komprehensif. Satu koreksi kecil: tegasnya, seqmendukung subset dari format chars. yang printfmendukung (dan himpunan bagian itu termasuk g, tetapi tidak d). Perilaku karakter ddan gberbeda halus dalam dmenafsirkan 0-prefixed nomor string sebagai oktal angka dan bertobat mereka untuk desimal, sedangkan gmemperlakukan mereka sebagai desimal. (@EdManet: itu sebabnya '00026' berubah menjadi '00022' dengan d). Hal lain yang layak disebut: seq -wmelakukan pengisian-nol otomatis dari nomor-nomor keluaran berdasarkan pada angka terlebar yang dihasilkan.
mklement0
Ini membantu saya menghasilkan daftar karakter hex. for (( i = 0; i <= 0xffffffff; i++ )) do printf "%08x\n" $i ; done >> hex.txtmenghasilkan daftar heksadesimal 8 karakter. Terima kasih.
cde
seq --help: "FORMAT harus sesuai untuk mencetak satu argumen dengan tipe 'ganda'; standarnya adalah%. PRECf jika PERTAMA, PENINGKATAN, dan TERAKHIR adalah semua angka desimal titik tetap dengan presisi PREC maksimum, dan untuk% g sebaliknya." Kemungkinan penentu konversi adalah efgaEFGA.
x-yuri
133

Lebih mudah masih bisa Anda lakukan

for i in {00001..99999}; do
  echo $i
done
Indie
sumber
16
Ini berfungsi pada Bash versi 4.1.2 (CentOS 6) tetapi gagal dalam versi 3.2.25 (CentOS 5). Saya setuju bahwa ini cara yang jauh lebih estetis untuk melakukannya!
Mike Starov
1
Bekerja, tetapi tidak memberikan nol string empuk pada bash saya
user2707001
Di Mac (Bash 4.4), ini tidak sesuai dengan angka. Di CentOS & SuSE, ini bekerja dengan sangat baik!
Stefan Lasiewski
Ini berfungsi baik di macOS dengan Bash4.4.23(1)-release
Whymarrh
Sayangnya, tidak bekerja pada Bash 5 pada OS X, sayangnya
dapatkan pada
91

Jika akhir urutan memiliki panjang maksimal padding (misalnya, jika Anda ingin 5 digit dan perintahnya adalah "seq 1 10000"), maka Anda dapat menggunakan flag "-w" untuk seq - menambahkan padding itu sendiri.

seq -w 1 10

menghasilkan

01
02
03
04
05
06
07
08
09
10
m_messiah
sumber
7
Ini jelas jawaban yang benar. Mengapa hanya ada sedikit upvotes? 😳
adius
5
mudah, karena padding tergantung pada jumlah maks yang ingin Anda capai. Jika ini adalah parameter yang Anda tidak pernah tahu sebelumnya berapa banyak nol Anda akan berakhir dengan
guillem
5
Ini tidak memberikan panjang tetap yang ditentukan, hanya hasil yang semuanya memiliki panjang yang sama .
Ceisc
78

gunakan printf dengan misalnya "% 05d"

printf "%05d" 1
frankc
sumber
18

Penggunaannya sangat sederhana printf

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

Gunakan awk seperti ini:

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

KELUARAN:

00001
00002
00003
00004
00005
00006
00007
00008
00009
00010

Memperbarui:

Sebagai alternatif bash murni Anda dapat melakukan ini untuk mendapatkan hasil yang sama:

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

Dengan cara ini Anda dapat menghindari menggunakan program eksternal seqyang TIDAK tersedia pada semua rasa * nix.

anubhava
sumber
1
Kita bisa menggunakan awk's BEGINpernyataan sehingga kita tidak harus menggunakan heredoctugas.
jaypal singh
@ JaypalSingh: Terima kasih sobat, itu poin yang bagus. Memperbarui jawaban saya.
anubhava
9

I pad output dengan lebih banyak digit (nol) daripada yang saya butuhkan kemudian gunakan tail untuk hanya menggunakan jumlah digit yang saya cari. Perhatikan bahwa Anda harus menggunakan '6' untuk mendapatkan lima digit terakhir :)

for i in $(seq 1 10)
do
RESULT=$(echo 00000$i | tail -c 6)
echo $RESULT
done
unifex
sumber
Jika Anda ingin menggunakan jumlah tempat yang benar dalam argumen -c dari tail, Anda bisa menggunakan 'echo -n 00000 $ i' karena ini menghentikannya menghasilkan baris baru yang merupakan salah satu dari karakter yang dikembalikan, maka perlu untuk jadilah yang lebih tinggi dalam jawaban ini. Tergantung apa yang Anda lakukan, baris baru, jika dibiarkan, dapat memengaruhi hasil.
Ceisc
Menggunakan proses eksternal untuk memangkas variabel dalam loop agak tidak efisien. Anda dapat menggunakan shell fitur ekspansi parameter sebagai gantinya. Di Bash ada fasilitas untuk mengekstraksi substring tertentu dengan indeks, atau Anda dapat menggunakan pengganti awalan dan akhiran dengan pola yang cocok dengan lebar yang diinginkan, meskipun itu membutuhkan sedikit bolak-balik.
tripleee
4

Jika Anda ingin N digit, tambahkan 10 ^ N dan hapus digit pertama.

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

Keluaran:

01
02
03
04
05
Burghard Hoffmann
sumber
2

Ini akan bekerja juga:

for i in {0..9}{0..9}{0..9}{0..9}
do
  echo "$i"
done
Chris
sumber
Solusi bagus! Bersih, mudah dibaca, tidak perlu program tambahan.
Jonathan Cross
2

Cara lain :

zeroos="000"
echo 

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

Jadi fungsi sederhana untuk mengonversi angka apa pun adalah:

function leading_zero(){

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

}
Paco
sumber
1

Salah satu cara tanpa menggunakan forking proses eksternal adalah manipulasi string, dalam kasus umum akan terlihat seperti ini:

#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

Ini berfungsi dengan baik di WSL juga, di mana forking adalah operasi yang sangat berat. Saya memiliki daftar 110000 file, menggunakan printf "%06d" $NUMwaktu lebih dari 1 menit, solusi di atas berjalan dalam waktu sekitar 1 detik.

Tamisoft
sumber
0

1.) Buat urutan angka 'seq' dari 1 hingga 1000, dan perbaiki lebar '-w' (lebar ditentukan oleh panjang angka akhir, dalam hal ini 4 digit untuk 1000).

2.) Juga, pilih angka yang ingin Anda gunakan 'sed -n' (dalam hal ini, kami memilih angka 1-100).

3.) 'gema' setiap nomor. Angka disimpan dalam variabel 'i', diakses menggunakan '$'.

Pro: Kode ini cukup bersih.

Cons: 'seq' bukan asli dari semua sistem Linux (seperti yang saya mengerti)

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

Jika Anda hanya setelah nomor padding dengan nol untuk mencapai panjang tetap, cukup tambahkan kelipatan terdekat dari 10 misalnya. untuk 2 digit, tambahkan 10 ^ 2, lalu hapus 1 pertama sebelum menampilkan output.

Solusi ini berfungsi untuk mem-pad / memformat angka tunggal dengan panjang berapa pun, atau seluruh urutan angka menggunakan for 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

Diuji pada Mac OSX 10.6.8, Bash ver 3.2.48

Zimba
sumber