วิธีการเรียงลำดับเลขจำนวนเต็มเป็นศูนย์ใน 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 ตัวเลือก - คงความยาวเอาท์พุทให้คงที่และเติมตัวเลขที่สั้นที่สุดด้วย 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

คำตอบ:


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" ขอบคุณ!
Ed Manet

12
ยอดเยี่ยมคำตอบที่ครอบคลุม หนึ่งการแก้ไขเล็ก ๆ : พูดอย่างเคร่งครัดseqสนับสนุนชุดย่อยของตัวอักษรรูปแบบ ที่printfรองรับ (และชุดย่อยนั้นรวมถึงgแต่ไม่ใช่d) พฤติกรรมของตัวละครdและgความแตกต่างอย่างละเอียดในdการตีความนั้น0-prefixed strings สตริงเป็นตัวเลขฐานแปดและแปลงให้เป็นทศนิยมในขณะที่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 ต้องเหมาะสำหรับการพิมพ์อาร์กิวเมนต์หนึ่งตัวที่พิมพ์ 'double' โดยค่าเริ่มต้นคือ% .PREC ถ้า FIRST INCREMENT และ LAST เป็นตัวเลขทศนิยมคงที่ทั้งหมดด้วย PREC ที่มีความแม่นยำสูงสุดและเป็นอย่างอื่น% g" ที่เป็นไปได้แปลง specifiersefgaEFGAมี
x-yuri

133

ยังง่ายกว่าที่คุณสามารถทำได้

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

16
สิ่งนี้ใช้ได้กับ Bash เวอร์ชั่น 4.1.2 (CentOS 6) แต่ล้มเหลวในเวอร์ชัน 3.2.25 (CentOS 5) ฉันยอมรับว่านี่เป็นวิธีที่น่าพึงพอใจมากขึ้นในการทำ!
Mike Starov

1
ใช้งานได้ แต่ไม่ให้ค่าสตริงที่เป็นศูนย์บน bash ของฉัน
user2707001

สำหรับ Mac (Bash 4.4) สิ่งนี้ไม่ได้เป็นตัวเลข ใน CentOS และ SuSE มันใช้งานได้ดีมาก!
Stefan Lasiewski

วิธีนี้ใช้งานได้ดีบน 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
เห็นได้ชัดว่านี่คือคำตอบที่ถูกต้อง ทำไมมันมี upvotes น้อยมาก? 😳
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

ปรับปรุง:

ในฐานะที่เป็นทางเลือกบริสุทธิ์ทุบตีคุณสามารถทำได้เพื่อให้ได้ผลลัพธ์เดียวกัน:

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

วิธีนี้คุณสามารถหลีกเลี่ยงการใช้โปรแกรมภายนอกseqซึ่งไม่สามารถใช้ได้กับทุกรสชาติของ * ระวัง


1
เราสามารถใช้awk's BEGINคำสั่งเพื่อที่เราจะได้ไม่ต้องใช้งานที่heredocได้รับมอบหมาย
jaypal singh

@ JaypalSingh: ขอบคุณเพื่อนนั่นเป็นจุดที่ดี อัปเดตคำตอบของฉัน
anubhava

9

ฉันเอาท์พุทที่มีตัวเลข (ศูนย์) มากกว่าที่ฉันต้องการแล้วใช้หางเพื่อใช้เฉพาะตัวเลขที่ฉันกำลังมองหา โปรดสังเกตว่าคุณต้องใช้ '6' ในส่วนท้ายเพื่อให้ได้ตัวเลขห้าตัวสุดท้าย :)

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

หากคุณต้องการใช้จำนวนสถานที่ที่ถูกต้องในอาร์กิวเมนต์ -c ของ tail คุณสามารถใช้ 'echo -n 00000 $ i' เนื่องจากจะหยุดการแสดงบรรทัดใหม่ซึ่งเป็นหนึ่งใน chars tail กำลังกลับมาดังนั้นจึงจำเป็นต้อง สูงขึ้นหนึ่งคำตอบ ขึ้นอยู่กับสิ่งที่คุณทำขึ้นบรรทัดใหม่หากปล่อยทิ้งไว้อาจส่งผลต่อผลลัพธ์
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

ทางออกที่ดี! ทำความสะอาดง่ายต่อการอ่านไม่จำเป็นต้องใช้โปรแกรมเพิ่มเติม
Jonathan Cross

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 ถึง 1,000 และแก้ไขความกว้าง '-w' (ความกว้างถูกกำหนดโดยความยาวของจำนวนสิ้นสุดในกรณีนี้ 4 หลักสำหรับ 1,000)

2. ) นอกจากนี้เลือกหมายเลขที่คุณต้องการใช้ 'sed -n' (ในกรณีนี้เราเลือกหมายเลข 1-100)

3. ) 'echo' ออกแต่ละหมายเลข ตัวเลขจะถูกเก็บไว้ในตัวแปร 'i' ซึ่งเข้าถึงได้โดยใช้ '$'

ข้อดี: รหัสนี้ค่อนข้างสะอาด

ข้อด้อย: 'seq' ไม่ใช่ระบบ Linux ทั้งหมด (ตามที่ฉันเข้าใจ)

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

0

หากคุณอยู่หลังตัวเลขที่เติมด้วยศูนย์เพื่อให้ได้ความยาวคงที่ให้เพิ่มจำนวนที่ใกล้ที่สุด 10 เท่าเช่น สำหรับ 2 หลักเพิ่ม 10 ^ 2 จากนั้นลบ 1 แรกก่อนที่จะแสดงผลลัพธ์

วิธีนี้ใช้ได้กับแผ่น / จัดรูปแบบหมายเลขเดียวที่มีความยาวใด ๆ หรือเรียงลำดับหมายเลขทั้งหมดโดยใช้สำหรับการวนซ้ำ

# 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

โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.