ไม่มีที่สิ้นสุดในขณะที่วนซ้ำในสคริปต์ BASH BASH: คำอธิบายของ for, while, until loops และตัวอย่างการใช้งาน ตัวอย่าง: การค้นหาไฟล์ปฏิบัติการ


ผู้เขียน : พอล คอบเบาต์
วันที่เผยแพร่: 16 ตุลาคม 2014
แปล: อ. ภานิน
วันที่แปล: 21 ธันวาคม 2014

บทที่ 22 วนซ้ำในสคริปต์

คำสั่งทดสอบ

คำสั่ง test ช่วยให้คุณกำหนดได้ว่านิพจน์เป็นจริงหรือเท็จ เริ่มต้นด้วยการทดสอบว่าค่าจำนวนเต็ม 10 มากกว่าค่าจำนวนเต็ม 55 หรือไม่ $ test 10 -gt 55 ; สะท้อน $? 1$

คำสั่ง test จะส่งคืน 1 หากนิพจน์เป็นเท็จ และดังที่คุณจะเห็นในตัวอย่างต่อไปนี้ คำสั่ง test จะส่งคืนค่า 0 หากนิพจน์ประเมินว่าเป็นจริง $ ทดสอบ 56 -gt 55 ; สะท้อน $? $0

หากคุณสะดวกกว่าที่จะทำงานกับสตริงจริงและเท็จ คุณสามารถใช้คำสั่ง test ดังที่แสดงด้านล่าง $ ทดสอบ 56 -gt 55 && เสียงสะท้อนจริง || echo false true $ ทดสอบ 6 -gt 55 && echo true || สะท้อนเท็จเท็จ

คำสั่งทดสอบยังสามารถแทนที่ด้วยวงเล็บเหลี่ยมได้ ดังนั้นคำสั่งในตัวอย่างด้านล่างจึงเหมือนกับคำสั่งในตัวอย่างด้านบนทุกประการ $ [ 56 -gt 55 ] && สะท้อนจริง || echo false จริง $ [ 6 -gt 55 ] && echo true || สะท้อนเท็จเท็จ

ด้านล่างนี้เป็นตัวอย่างการใช้งานเช็คบางรายการ อ้างถึงหน้าทดสอบคนเพื่อดูภาพรวมของ คุณลักษณะเพิ่มเติมการดำเนินการตรวจสอบต่างๆ [ -d foo ] มีไดเร็กทอรี foo หรือไม่? [ -e bar ] มีไฟล์ bar หรือไม่? [ "/etc" = $PWD ] /etc เทียบเท่ากับค่าของ $PWD หรือไม่ [ $1 != "secret" ] ค่าของพารามิเตอร์สคริปต์แรกแตกต่างจากสตริงลับหรือไม่? [ 55 -lt $bar ] ค่าจำนวนเต็ม 55 น้อยกว่าค่าของ $bar หรือไม่? [ $foo -ge 1,000 ] ค่าของ $foo มากกว่าหรือเท่ากับค่าจำนวนเต็ม 1,000 หรือไม่? ["เอบีซี"< $bar ] Будет ли строка abc расположена выше значения переменной $bar в списке после сортировки? [ -f foo ] Является ли foo обычным файлом? [ -r bar ] Является ли bar ไฟล์ที่สามารถอ่านได้? [ foo -nt bar ] foo ใหม่กว่า bar เหรอ? [ -o nounset ] ตัวเลือก nounset shell เปิดใช้งานอยู่หรือไม่

ตัวดำเนินการตรวจสอบสามารถรวมกับตัวดำเนินการที่เกี่ยวข้องได้ การดำเนินการเชิงตรรกะ"และ" และ "หรือ" paul@RHEL4b:~$ [ 66 -gt 55 -a 66 -lt 500 ] && echo จริง || echo false จริง paul@RHEL4b:~$ [ 66 -gt 55 -a 660 -lt 500 ] && echo true || echo false false paul@RHEL4b:~$ [ 66 -gt 55 -o 660 -lt 500 ] && เสียงสะท้อนจริง || สะท้อนเท็จจริง

กระโดดแบบมีเงื่อนไขถ้าเป็นอย่างอื่น

โครงสร้าง if then else มีวัตถุประสงค์เพื่อเลือกตัวเลือกโค้ด หากเงื่อนไขใดเงื่อนไขหนึ่งเป็นจริง บางโค้ดจะถูกดำเนินการ ไม่เช่นนั้นโค้ดอื่น ๆ บางส่วนจะถูกดำเนินการ ตัวอย่างด้านล่างจะตรวจสอบการมีอยู่ของไฟล์ หลังจากนั้นหากสมมติฐานของการมีอยู่ของไฟล์ได้รับการยืนยัน ข้อความที่เกี่ยวข้องจะปรากฏขึ้น #!/bin/bash ถ้า [ -f isit.txt ] ก็แสดงว่ามีไฟล์ isit.txt อยู่! ไม่พบไฟล์ echo isit.txt! ฟิ

ในกรณีที่เราบันทึก รหัสนี้ในไฟล์ชื่อ "choice" ก็สามารถดำเนินการได้ในลักษณะเดียวกัน ไม่พบไฟล์ $ ./choice isit.txt! $ touch isit.txt $ ./choice มีไฟล์ isit.txt แล้ว! $

กระโดดแบบมีเงื่อนไขถ้าเป็นเอลฟ์

คุณสามารถโพสต์ได้ ผู้ดำเนินการใหม่การกระโดดแบบมีเงื่อนไขหากอยู่ในบล็อกอื่นโดยใช้ตัวดำเนินการ elif ด้านล่างนี้เป็นตัวอย่างง่ายๆ ของรายการดังกล่าว #!/bin/bash count=42 ถ้า [ $count -eq 42 ] ดังนั้น echo "42 เป็นค่าที่ถูกต้อง" elif [ $count -gt 42 ] จากนั้นก้องว่า "มากเกินไป" อย่างอื่นสะท้อนว่า "ไม่เพียงพอ" ฟิ

สำหรับวง

ตัวอย่างด้านล่างแสดงไวยากรณ์ของ for loop แบบคลาสสิกใน bash shell สำหรับฉันใน 1 2 4 สะท้อน $ ฉันทำเสร็จแล้ว

ตัวอย่างของการใช้ for loop รวมกับการเรียกเชลล์แบบอินไลน์ #!/bin/ksh สำหรับตัวนับใน `seq 1 20` ทำเสียงสะท้อนนับจาก 1 ถึง 20 มูลค่าปัจจุบัน $counter sleep 1 เสร็จแล้ว

สคริปต์ที่คล้ายกับที่นำเสนอข้างต้นโดยสิ้นเชิงสามารถสร้างได้โดยไม่ต้องใช้เชลล์คำสั่งแบบฝังโดยใช้การประกาศ bash shell สำหรับช่วงของค่า (จากค่า .. ถึงค่า) #!/bin/bash สำหรับตัวนับใน (1..20) ทำเสียงสะท้อนตั้งแต่ 1 ถึง 20 มูลค่าปัจจุบัน $counter sleep 1 เสร็จแล้ว

for loop นี้ใช้กลไกในการค้นหาไฟล์ตามรูปแบบ (นำไปใช้เป็นส่วนหนึ่งของกลไกการขยายคำสั่ง) หากคำแนะนำข้างต้นถูกโพสต์โดยตรงใน บรรทัดคำสั่งมันก็จะทำงานในลักษณะเดียวกัน kahlan@solexp11$ ls count.ksh go.ksh kahlan@solexp11$ สำหรับไฟล์ใน *.ksh ; ทำ cp $file $file.backup ; เสร็จแล้ว kahlan@solexp11$ ls count.ksh count.ksh.backup go.ksh go.ksh.backup

ในขณะที่วนซ้ำ

ด้านล่างนี้เป็นตัวอย่างง่ายๆ ของการใช้ while loop ผม=100; ในขณะที่ [ $i -ge 0 ] ; ทำ echo นับถอยหลังจาก 100 ถึง 0 มูลค่าปัจจุบัน $i; ปล่อยให้ฉัน--; เสร็จแล้ว

การวนซ้ำไม่สิ้นสุดสามารถนำมาใช้ได้โดยใช้การประกาศ while true หรือ while: โดยที่สัญลักษณ์: เทียบเท่ากับการดำเนินการที่ขาดหายไปใน Korn เชลล์และ bash #!/bin/ksh # วนซ้ำไม่สิ้นสุดในขณะที่: ทำ echo สวัสดี sleep 1 เสร็จแล้ว

จนกระทั่งวนซ้ำ

ด้านล่างนี้เป็นตัวอย่างง่ายๆ ของการใช้การวนซ้ำจนกระทั่ง ให้ i=100; จนกระทั่ง [ $i -le 0 ] ; ทำ echo นับถอยหลังจาก 100 ถึง 1 มูลค่าปัจจุบัน $i; ปล่อยให้ฉัน--; เสร็จแล้ว

แบบฝึกหัด: การทดสอบและลูปในสคริปต์

3. พัฒนาสคริปต์ที่จะใช้การวนซ้ำ while เพื่อนับ 3 ถึง 7

4. พัฒนาสคริปต์ที่จะใช้การวนซ้ำจนถึงการนับถอยหลังจาก 8 ถึง 4

5. พัฒนาสคริปต์ที่จะนับไฟล์ที่มีนามสกุล .txt ในไดเร็กทอรีปัจจุบัน

6. ใช้คำสั่ง if ในสคริปต์ที่สร้างขึ้นเพื่อให้ทำงานได้อย่างถูกต้องหากไม่มีไฟล์ที่มีนามสกุล .txt ในไดเร็กทอรีปัจจุบัน

ขั้นตอนที่ถูกต้องในการทำงานภาคปฏิบัติให้เสร็จสิ้น: ตรวจสอบและวนซ้ำในสคริปต์

1. พัฒนาสคริปต์ที่จะใช้ for loop เพื่อนับ 3 ถึง 7

#!/bin/bash for i ใน 3 4 5 6 7 do echo นับจาก 3 ถึง 7 มูลค่าปัจจุบัน $i เสร็จแล้ว

2. พัฒนาสคริปต์ที่จะใช้ for loop เพื่อนับจาก 1 ถึง 17000

bash shell รองรับลูปซึ่งช่วยให้คุณสามารถวนซ้ำลำดับของค่าได้ นั่นคือสิ่งที่มันเป็น โครงสร้างพื้นฐานรอบดังกล่าว:

สำหรับคำสั่ง var in list do เสร็จสิ้น
ในการวนซ้ำแต่ละครั้งของลูป ตัวแปร var จะถูกเขียนไปยังค่าถัดไปจาก รายการ. การผ่านครั้งแรกของลูปจะใช้ค่าแรกจากรายการ ในวินาที - วินาทีและอื่น ๆ - จนกระทั่งการวนซ้ำถึงองค์ประกอบสุดท้าย

การวนซ้ำค่าธรรมดา

บางทีตัวอย่างที่ง่ายที่สุดของการ for loop ในสคริปต์ bash คือการวนซ้ำรายการค่าง่าย ๆ :

#!/bin/bash สำหรับ var ในวินาทีแรกวินาทีที่สามสี่ห้าทำ echo รายการ $var เสร็จแล้ว
ผลลัพธ์ของสคริปต์นี้แสดงอยู่ด้านล่าง คุณจะเห็นได้อย่างชัดเจนว่าตัวแปร $var มีองค์ประกอบจากรายการตามลำดับ สิ่งนี้จะเกิดขึ้นจนกว่าวงจรจะถึงรอบสุดท้าย


ง่ายสำหรับการวนซ้ำ

โปรดทราบว่าตัวแปร $var จะคงค่าไว้เมื่อออกจากลูป เนื้อหาของตัวแปรสามารถเปลี่ยนแปลงได้ และโดยทั่วไป คุณสามารถทำงานกับตัวแปรดังกล่าวได้เหมือนกับตัวแปรอื่นๆ

การวนซ้ำค่าที่ซับซ้อน

รายการที่ใช้ในการเริ่มต้น for loop ไม่เพียงแต่ประกอบด้วยสตริงธรรมดาที่ประกอบด้วยคำเดียวเท่านั้น แต่ยังรวมถึงวลีทั้งหมดที่มีหลายคำและเครื่องหมายวรรคตอนด้วย ตัวอย่างเช่น อาจมีลักษณะดังนี้:

#!/bin/bash สำหรับ var ในอันแรก "อันที่สอง" "อันที่สาม" "ฉันจะทำมัน" ทำเสียงสะท้อน "นี่คือ: $var" เสร็จแล้ว
นี่คือสิ่งที่เกิดขึ้นหลังจากการวนซ้ำนี้ผ่านรายการ อย่างที่คุณเห็นผลลัพธ์ค่อนข้างคาดหวัง


การวนซ้ำค่าที่ซับซ้อน
TNW-CUS-FMP - รหัสโปรโมชั่นส่วนลด 10% สำหรับบริการของเรา เปิดใช้งานได้ภายใน 7 วัน"

การเริ่มต้นการวนซ้ำด้วยรายการที่ได้รับจากผลลัพธ์ของคำสั่ง

อีกวิธีหนึ่งในการเริ่มต้น for loop คือการส่งผ่านรายการ ซึ่งเป็นผลลัพธ์ของคำสั่ง ที่นี่การทดแทนคำสั่งใช้เพื่อดำเนินการและรับผลลัพธ์ของงาน

#!/bin/bash file="myfile" สำหรับ var ใน $(cat $file) ทำ echo " $var" เสร็จแล้ว
ตัวอย่างนี้ใช้คำสั่ง cat ซึ่งอ่านเนื้อหาของไฟล์ รายการค่าผลลัพธ์จะถูกส่งผ่านไปยังลูปและแสดงบนหน้าจอ โปรดทราบว่าไฟล์ที่เรากำลังเข้าถึงมีรายการคำที่คั่นด้วยการขึ้นบรรทัดใหม่ ไม่มีการเว้นวรรค


การวนซ้ำที่วนซ้ำเนื้อหาของไฟล์

ที่นี่เราต้องคำนึงว่าแนวทางดังกล่าวหากคาดว่าจะมีการประมวลผลข้อมูลแบบทีละบรรทัดจะไม่ทำงานสำหรับไฟล์ที่มีโครงสร้างที่ซับซ้อนกว่านี้ บรรทัดนั้นอาจมีคำหลายคำคั่นด้วยช่องว่าง การวนซ้ำจะประมวลผลแต่ละคำ ไม่ใช่บรรทัด

จะเกิดอะไรขึ้นถ้านี่ไม่ใช่สิ่งที่คุณต้องการเลย?

เครื่องแยกสนาม

เหตุผลของคุณสมบัติข้างต้นคือความพิเศษ ตัวแปรสภาพแวดล้อมซึ่งเรียกว่า IFS (Internal Field Separator) และอนุญาตให้คุณระบุตัวคั่นฟิลด์ได้ ตามค่าเริ่มต้น bash shell จะถือว่าอักขระต่อไปนี้เป็นตัวคั่นฟิลด์:
  • ช่องว่าง
  • อักขระแท็บ
  • อักขระป้อนบรรทัด
หาก bash พบอักขระเหล่านี้ในข้อมูล จะถือว่านำหน้าด้วยค่าอิสระถัดไปในรายการ

เมื่อต้องการแก้ไขปัญหา คุณสามารถเปลี่ยนตัวแปรสภาพแวดล้อม IFS ได้ชั่วคราว ต่อไปนี้เป็นวิธีดำเนินการใน bash script โดยสมมติว่าคุณต้องการเพียงขึ้นบรรทัดใหม่เป็นตัวคั่นฟิลด์:

ไอเอฟเอส=$"\n"
เมื่อคุณเพิ่มคำสั่งนี้ลงในสคริปต์ทุบตีของคุณ มันจะทำงานตามที่คาดไว้ โดยไม่สนใจช่องว่างและแท็บ และถือว่าเฉพาะอักขระขึ้นบรรทัดใหม่เป็นตัวคั่นฟิลด์

#!/bin/bash file="/etc/passwd" IFS=$"\n" สำหรับ var ใน $(cat $file) ทำ echo " $var" เสร็จแล้ว
หากสคริปต์นี้ถูกรัน มันจะส่งออกสิ่งที่ต้องการอย่างแน่นอน โดยให้สิทธิ์ในการเข้าถึงบรรทัดถัดไปที่เขียนลงในไฟล์ในการวนซ้ำแต่ละครั้ง


การข้ามไฟล์ทีละบรรทัดใน for loop

ตัวคั่นสามารถเป็นอักขระอื่นได้ ตัวอย่างเช่น ด้านบนเราได้แสดงเนื้อหาของไฟล์ /etc/passwd ข้อมูลผู้ใช้ในบรรทัดจะถูกคั่นด้วยเครื่องหมายทวิภาค หากคุณต้องการประมวลผลสตริงดังกล่าวในลูป คุณสามารถกำหนดค่า IFS ได้ดังนี้:

การข้ามไฟล์ที่มีอยู่ในไดเร็กทอรี

หนึ่งในการใช้งานที่พบบ่อยที่สุดของ for loops ในสคริปต์ทุบตีคือการสำรวจไฟล์ที่อยู่ในไดเร็กทอรีและประมวลผลไฟล์เหล่านั้น

ตัวอย่างเช่น ต่อไปนี้เป็นวิธีแสดงรายการไฟล์และโฟลเดอร์:

#!/bin/bash สำหรับไฟล์ใน /home/likegeeks/* do if [ -d "$file" ] จากนั้น echo "$file is a directory" elif [ -f "$file" ] จากนั้น echo "$file is a ไฟล์" เสร็จแล้ว
หากคุณเข้าใจเนื้อหาก่อนหน้านี้ในบทความชุดนี้ คุณควรเข้าใจโครงสร้างของโครงสร้างแบบ if-then รวมถึงวิธีแยกไฟล์ออกจากโฟลเดอร์ หากคุณพบว่าโค้ดข้างต้นเข้าใจได้ยาก โปรดอ่านเนื้อหานี้อีกครั้ง

นี่คือสิ่งที่สคริปต์จะส่งออก


การแสดงเนื้อหาของโฟลเดอร์

ให้ความสนใจกับวิธีที่เราเริ่มต้นการวนซ้ำกล่าวคือ ไวด์การ์ด"*" ที่อยู่ท้ายโฟลเดอร์ สัญลักษณ์นี้สามารถมองได้ว่าเป็นสัญลักษณ์แทน: “ไฟล์ทั้งหมดที่มีชื่อใดก็ได้” ช่วยให้คุณสามารถจัดระเบียบได้ การทดแทนอัตโนมัติชื่อไฟล์ที่ตรงกับรูปแบบ

เมื่อทดสอบเงื่อนไขในคำสั่ง if เราจะใส่ชื่อตัวแปรไว้ในเครื่องหมายคำพูด การดำเนินการนี้เนื่องจากชื่อไฟล์หรือโฟลเดอร์อาจมีช่องว่าง

สไตล์ C สำหรับลูป

หากคุณคุ้นเคยกับภาษาการเขียนโปรแกรม C ไวยากรณ์สำหรับการอธิบาย bash for loops อาจดูแปลกสำหรับคุณ เนื่องจากคุณคุ้นเคยกับการอธิบายลูปในลักษณะนี้อย่างชัดเจน:

สำหรับ (i = 0; i< 10; i++) { printf("number is %d\n", i); }
ในสคริปต์ทุบตีคุณสามารถใช้ for loops ได้ คำอธิบายซึ่งดูคล้ายกับลูปสไตล์ C มาก แม้ว่าจะมีความแตกต่างบางประการก็ตาม แผนภาพวงจรด้วยวิธีนี้มีลักษณะดังนี้:

สำหรับ ((ค่าเริ่มต้นของตัวแปร; เงื่อนไขสำหรับการสิ้นสุดลูป; การเปลี่ยนแปลงของตัวแปร))
ใน bash สามารถเขียนได้ดังนี้:

สำหรับ ((a = 1;< 10; a++))
นี่คือตัวอย่างการทำงาน:

#!/bin/bash สำหรับ ((i=1; i<= 10; i++)) do echo "number is $i" done
รหัสนี้จะแสดงรายการตัวเลขตั้งแต่ 1 ถึง 10

วนลูปสไตล์ซี

ในขณะที่วนซ้ำ

for build ไม่ใช่วิธีเดียวในการจัดระเบียบลูปในสคริปต์ทุบตี คุณยังสามารถใช้ while ลูปได้ที่นี่ ในลูปดังกล่าว คุณสามารถระบุคำสั่งเพื่อตรวจสอบเงื่อนไขบางอย่างและดำเนินการเนื้อหาของลูปจนกว่าเงื่อนไขที่จะทดสอบจะส่งกลับค่าศูนย์ หรือส่งสัญญาณว่าการดำเนินการบางอย่างเสร็จสมบูรณ์ได้สำเร็จ เมื่อเงื่อนไขลูปส่งคืนค่าที่ไม่ใช่ศูนย์ ซึ่งหมายถึงข้อผิดพลาด การวนซ้ำจะหยุดลง

นี่คือไดอะแกรมของการจัดระเบียบของ while loop
ขณะสั่งตรวจสอบสภาพ
ทำ
ทีมอื่นๆ
เสร็จแล้ว

ลองมาดูตัวอย่างสคริปต์ที่มีการวนซ้ำดังนี้:

#!/bin/bash var1=5 ในขณะที่ [ $var1 -gt 0 ] ทำ echo $var1 var1=$[ $var1 - 1 ] เสร็จแล้ว
ที่ทางเข้าสู่ลูป จะมีการตรวจสอบว่าตัวแปร $var1 มากกว่าศูนย์หรือไม่ ถ้าเป็นเช่นนั้น เนื้อความของลูปจะถูกดำเนินการ โดยอันหนึ่งจะถูกลบออกจากค่าของตัวแปร สิ่งนี้จะเกิดขึ้นในการวนซ้ำแต่ละครั้ง และเราจะพิมพ์ค่าของตัวแปรไปยังคอนโซลก่อนที่จะมีการแก้ไข ทันทีที่ $var1 ถึงค่า 0 การวนซ้ำจะหยุดลง

ผลลัพธ์ของการวนซ้ำ while

หากคุณไม่แก้ไขตัวแปร $var1 จะทำให้สคริปต์สิ้นสุดในการวนซ้ำไม่สิ้นสุด

ลูปซ้อนกัน

คุณสามารถใช้คำสั่งใดก็ได้ในส่วนเนื้อหาของลูป รวมถึงการเรียกใช้ลูปอื่นๆ ด้วย โครงสร้างดังกล่าวเรียกว่าลูปแบบซ้อน:

#!/bin/bash สำหรับ ((a = 1;<= 3; a++)) do echo "Start $a:" for ((b = 1; b <= 3; b++)) do echo " Inner loop: $b" done done
ด้านล่างนี้คือสิ่งที่สคริปต์นี้จะส่งออก อย่างที่คุณเห็น ขั้นแรกให้ทำการวนซ้ำครั้งแรกของวงนอก จากนั้นวนซ้ำสามครั้งในวงใน หลังจากเสร็จสิ้นแล้ว วงนอกจะกลับมาเล่นอีกครั้ง จากนั้นจึงวนซ้ำวงในอีกครั้ง

ลูปซ้อนกัน

กำลังประมวลผลเนื้อหาไฟล์

ส่วนใหญ่มักจะใช้ลูปที่ซ้อนกันเพื่อประมวลผลไฟล์ ดังนั้นลูปด้านนอกกำลังวนซ้ำบรรทัดของไฟล์ และลูปด้านในทำงานกับแต่ละบรรทัดอยู่แล้ว ตัวอย่างเช่น นี่คือลักษณะการประมวลผลไฟล์ /etc/passwd:

#!/bin/bash IFS=$"\n" สำหรับการป้อนข้อมูลใน $(cat /etc/passwd) do echo "Values ​​​​in $entry –" IFS=: สำหรับค่าใน $entry do echo " $value" เสร็จสิ้น เสร็จแล้ว
มีสองลูปในสคริปต์นี้ อันแรกข้ามบรรทัดโดยใช้อักขระขึ้นบรรทัดใหม่เป็นตัวคั่น อันภายในกำลังยุ่งอยู่กับการแยกวิเคราะห์สตริงที่มีฟิลด์คั่นด้วยเครื่องหมายทวิภาค

การประมวลผลข้อมูลไฟล์

วิธีการนี้สามารถนำไปใช้เมื่อประมวลผลไฟล์ CSV หรือไฟล์ที่คล้ายกัน โดยการเขียนอักขระตัวคั่นลงในตัวแปรสภาพแวดล้อม IFS ตามต้องการ

การจัดการวงจร

บางที หลังจากเข้าสู่ลูป คุณจะต้องหยุดเมื่อตัวแปรลูปถึงค่าที่กำหนดซึ่งไม่สอดคล้องกับเงื่อนไขที่ระบุไว้ในตอนแรกสำหรับการสิ้นสุดลูป ในสถานการณ์เช่นนี้ จำเป็นต้องรอให้วงจรเสร็จสิ้นตามปกติหรือไม่? ไม่แน่นอน และในกรณีเช่นนี้ คำสั่งสองคำสั่งต่อไปนี้จะมีประโยชน์:
  • หยุดพัก
  • ดำเนินการต่อ

คำสั่งทำลาย

คำสั่งนี้ช่วยให้คุณสามารถขัดจังหวะการทำงานของลูปได้ สามารถใช้ได้ทั้ง for และ while loops:

#!/bin/bash สำหรับ var1 ใน 1 2 3 4 5 6 7 8 9 10 ทำ if [ $var1 -eq 5 ] แล้วทำลาย fi echo "Number: $var1" เสร็จแล้ว
การวนซ้ำดังกล่าวภายใต้สภาวะปกติจะผ่านรายการค่าทั้งหมดจากรายการ อย่างไรก็ตาม ในกรณีของเรา การดำเนินการจะถูกขัดจังหวะเมื่อตัวแปร $var1 เท่ากับ 5

ออกจาก for loop ก่อนกำหนด

นี่คือสิ่งเดียวกัน แต่สำหรับ while loop:

#!/bin/bash var1=1 ในขณะที่ [ $var1 -lt 10 ] do if [ $var1 -eq 5 ] แล้วทำลาย fi echo "Iteration: $var1" var1=$(($var1 + 1)) เสร็จแล้ว
คำสั่ง break ซึ่งดำเนินการเมื่อ $var1 ถึง 5 จะเป็นการหยุดลูป คอนโซลจะแสดงสิ่งเดียวกับในตัวอย่างก่อนหน้า

ดำเนินการคำสั่งต่อไป

เมื่อพบคำสั่งนี้ในเนื้อความของลูป การวนซ้ำปัจจุบันจะสิ้นสุดก่อนกำหนดและการดำเนินการถัดไปจะเริ่มต้นโดยไม่ต้องออกจากลูป ลองดูคำสั่ง Continue ใน For Loop:

#!/bin/bash สำหรับ ((var1 = 1; var1< 15; var1++)) do if [ $var1 -gt 5 ] && [ $var1 -lt 10 ] then continue fi echo "Iteration number: $var1" done
เมื่อเงื่อนไขภายในลูปเป็นไปตามนั้น นั่นคือเมื่อ $var1 มากกว่า 5 และน้อยกว่า 10 เชลล์จะดำเนินการคำสั่ง Continue ซึ่งส่งผลให้ข้ามคำสั่งที่เหลือในเนื้อความของลูปและไปยังการวนซ้ำครั้งถัดไป

คำสั่ง Continue ใน For Loop

การประมวลผลเอาต์พุตที่ทำงานเป็นวง

เอาต์พุตข้อมูลจากลูปสามารถประมวลผลได้โดยการเปลี่ยนเส้นทางเอาต์พุตหรือส่งผ่านไปยังไปป์ไลน์ ซึ่งทำได้โดยการเพิ่มคำสั่งการประมวลผลเอาต์พุตหลังคำสั่งที่เสร็จสิ้น

ตัวอย่างเช่น แทนที่จะแสดงบนหน้าจอว่ามีอะไรเอาต์พุตเป็นลูป คุณสามารถเขียนทั้งหมดลงในไฟล์หรือส่งต่อไปที่อื่นได้:

#!/bin/bash สำหรับ ((a = 1;< 10; a++)) do echo "Number is $a" done >myfile.txt echo "เสร็จสิ้น"
เชลล์จะสร้างไฟล์ myfile.txt และเปลี่ยนเส้นทางเอาต์พุตของคำสั่ง for ไปยังไฟล์นั้น มาเปิดไฟล์และตรวจสอบให้แน่ใจว่าไฟล์นั้นมีสิ่งที่เราคาดหวัง

เปลี่ยนเส้นทางเอาต์พุตลูปไปยังไฟล์

ตัวอย่าง: ค้นหาไฟล์ปฏิบัติการ

ลองใช้สิ่งที่เราได้กล่าวถึงไปแล้วและเขียนสิ่งที่มีประโยชน์กันดีกว่า ตัวอย่างเช่น หากคุณต้องการค้นหาไฟล์ปฏิบัติการที่มีอยู่ในระบบ คุณสามารถสแกนโฟลเดอร์ทั้งหมดที่บันทึกไว้ในตัวแปรสภาพแวดล้อม PATH เรามีเครื่องมือทั้งหมดที่จำเป็นสำหรับสิ่งนี้อยู่แล้ว เราแค่ต้องรวบรวมมันเข้าด้วยกัน:

#!/bin/bash IFS=: สำหรับโฟลเดอร์ใน $PATH ทำ echo "$folder:" สำหรับไฟล์ใน $folder/* ทำถ้า [ -x $file ] แล้ว echo " $file" fi เสร็จแล้ว
สคริปต์นี้มีขนาดเล็กและเรียบง่าย ช่วยให้เราสามารถรับรายการไฟล์ปฏิบัติการที่จัดเก็บไว้ในโฟลเดอร์จาก PATH

ค้นหาไฟล์ปฏิบัติการในโฟลเดอร์จากตัวแปร PATH

ผลลัพธ์

วันนี้เราได้พูดถึง for และ while loops ใน bash scripts วิธีรัน และวิธีจัดการ ตอนนี้คุณรู้วิธีการประมวลผลสตริงที่มีตัวคั่นต่างกันในลูป คุณรู้วิธีเปลี่ยนเส้นทางข้อมูลเอาต์พุตเป็นลูปไปยังไฟล์ วิธีดูและวิเคราะห์เนื้อหาของไดเร็กทอรี

หากเราถือว่าคุณเป็นผู้พัฒนาสคริปต์ทุบตีที่รู้เฉพาะสิ่งที่ระบุไว้ในส่วนแรกของบทความชุดนี้และในวินาทีนี้คุณก็สามารถเขียนสิ่งที่มีประโยชน์ได้แล้ว ข้างหน้าคือส่วนที่สาม หลังจากทำความเข้าใจแล้วว่าคุณจะได้เรียนรู้วิธีส่งพารามิเตอร์และสลับบรรทัดคำสั่งไปเป็นสคริปต์ทุบตี และจะทำอย่างไรกับมันทั้งหมด

คำอธิบายสั้น ๆ เกี่ยวกับความแตกต่างในประเภทลูป:

สำหรับ - จะดำเนินการตราบเท่าที่มีวัตถุที่จะดำเนินการ (เช่นการอ่านสตรีมจาก stdin ไฟล์หรือฟังก์ชัน)
ในขณะที่ - ดำเนินการจนกระทั่ง เงื่อนไขเป็นความจริง;
จนกระทั่ง - จะถูกดำเนินการตราบเท่าที่ เงื่อนไขจะไม่เป็นจริงเช่น สำหรับตอนนี้มันเป็นเท็จ

สำหรับห่วง

ลองพิจารณาสคริปต์เวอร์ชันนี้แบบวนซ้ำ:

$ cat loop.sh #!/bin/bash สำหรับตัวแปรใน `ls -1` ทำ echo "$variable" เสร็จแล้ว

ไวยากรณ์นั้นง่ายมากและแสดงให้เห็นอย่างชัดเจนในตัวอย่าง:

สำหรับ (เริ่มลูป) ตัวแปร (ประกาศตัวแปรที่เราจะดำเนินการ) ใน (ส่งโฟลว์ไปยังลูป) `ls -1` (คำสั่งที่จะดำเนินการและส่งผ่านไปยังตัวแปร $variable) สิ่งที่ทำและทำเสร็จแล้วคือ "เนื้อหา" ของลูป ซึ่งภายในการดำเนินการหลักจะดำเนินการกับข้อมูลที่ได้รับ และเสียงสะท้อน "$variable" คือการกระทำจริงที่ดำเนินการโดยลูป

ตอนนี้เรามาเปลี่ยนตัวอย่างกันสักหน่อย และแทนที่จะระบุคำสั่งอย่างชัดเจน เราจะใช้ตัวแปรตัวที่สอง:

$ cat loop.sh #!/bin/bash ls=`ls -1` สำหรับตัวแปรใน $ls ทำ echo "$variable" เสร็จแล้ว

ตอนนี้คำสั่ง ls -1 ถูกส่งผ่านในตัวแปรแยกต่างหาก ซึ่งช่วยให้คุณทำงานกับลูปได้อย่างยืดหยุ่นมากขึ้น แทนที่จะใช้ตัวแปรในลูป คุณยังสามารถใช้ฟังก์ชันได้:

$ cat loop.sh #!/bin/bash lsl () ( ls -1 ) สำหรับตัวแปรใน `lsl` ทำ echo "$variable" เสร็จแล้ว

เงื่อนไขหลักของ for loop คือมันจะถูกดำเนินการตราบใดที่คำสั่งที่ส่งไปนั้นมีออบเจ็กต์สำหรับการดำเนินการ ตามตัวอย่างด้านบน - ตราบใดที่ ls -1 มีไฟล์ที่จะแสดง - ลูปจะส่งผ่านไฟล์เหล่านั้นไปยังตัวแปรและดำเนินการ "loop body" ทันทีที่รายการไฟล์ในไดเร็กทอรีสิ้นสุดลง ลูปจะดำเนินการให้เสร็จสิ้น

มาทำให้ตัวอย่างซับซ้อนขึ้นอีกหน่อย

ไดเรกทอรีประกอบด้วยรายการไฟล์:

$ ls -1 file1 file2 file3 file4 file5 loop.sh nofile1 nofile2 nofile3 nofile4 nofile5

เราต้องเลือกจากพวกเขาเฉพาะที่ไม่มีคำว่า " เลขที่«:

$ cat loop.sh #!/bin/bash lsl=`ls -1` สำหรับตัวแปรใน $lsl do echo "$variable" | grep -v "ไม่" เสร็จแล้ว $ ./loop.sh file1 file2 file3 file4 file5 loop.sh

คุณยังสามารถใช้นิพจน์แบบมีเงื่อนไขในลูป ( การแสดงออกตามเงื่อนไข) […] เพื่อตรวจสอบเงื่อนไขและคำสั่งแบ่งเพื่อขัดจังหวะลูปหากเงื่อนไขถูกทริกเกอร์

ลองพิจารณาตัวอย่างนี้:

$ cat loop.sh #!/bin/bash lsl=`ls -1` สำหรับตัวแปรใน $lsl do if [ $variable != "loop.sh" ] จากนั้น echo "$variable" | grep -v "no" อย่างอื่นพังเสร็จเรียบร้อย

การวนซ้ำจะดำเนินต่อไปจนกว่าจะพบไฟล์ loop.sh ทันทีที่การดำเนินการของลูปมาถึงไฟล์นี้ ลูปจะถูกขัดจังหวะด้วยคำสั่ง break:

$ ./loop.sh ไฟล์1 ไฟล์2 ไฟล์3 ไฟล์4 ไฟล์5

อีกตัวอย่างหนึ่งคือการใช้การดำเนินการทางคณิตศาสตร์ทันทีก่อนดำเนินการเนื้อความของลูป:

$ cat loop.sh #!/bin/bash สำหรับ ((count=1; count<11; count++)) do echo "$count" done

ที่นี่เราตั้งค่าคำสั่งควบคุมสามคำสั่ง - count=1, เงื่อนไขการควบคุม - ในขณะที่จำนวนน้อยกว่า 11 และคำสั่งให้ดำเนินการ - count +1:

WHILE และ UNTIL วนซ้ำ

ตัวอย่างง่ายๆ ที่แสดงให้เห็นอย่างชัดเจนว่า while loop ทำงานอย่างไร:

$ cat loop.sh #!/bin/bash count=0 ในขณะที่ [ $count -lt 10 ] do ((count++)) echo $count เสร็จแล้ว

เราตั้งค่าตัวแปร $count ให้เป็นศูนย์ จากนั้นรันคำสั่ง whi le โดยมีเงื่อนไข “ในขณะที่ $count น้อยกว่าสิบ ให้ดำเนินการลูป” ในเนื้อความของลูปที่เราดำเนินการ การเพิ่มขึ้นภายหลัง+1 ให้กับตัวแปร $count และผลลัพธ์จะถูกพิมพ์ไปที่ stdout

ผลการดำเนินการ:

$ ./loop.sh 1 2 3 4 5 6 7 8 9 10

ทันทีที่ค่าของตัวแปร $count กลายเป็น 10 การวนซ้ำก็หยุดลง

ตัวอย่างที่ดีของการวนซ้ำแบบ "ไม่มีที่สิ้นสุด" ที่สาธิตวิธีการทำงานของ while:

$ cat loop.sh #!/bin/bash count=10 ในขณะที่ [ 1 = 1 ] ทำ ((นับ++)) echo $count เสร็จแล้ว $ ./loop.sh ... 5378 5379 5380 5381 5382 5383 ^C

การวนซ้ำจนกระทั่งทำงานในลักษณะเดียวกัน แต่ไปในทิศทางตรงกันข้าม:

$ cat loop.sh #!/bin/bash count=0 จนถึง [ $count -gt 10 ] do ((count++)) echo $count เสร็จสิ้น

ที่นี่เราตั้งค่าเงื่อนไขที่คล้ายกัน แต่แทนที่จะระบุ "ในขณะที่ตัวแปรน้อยกว่า 10" เราระบุ "จนกว่าตัวแปรจะมีค่ามากกว่า 10" ผลการดำเนินการ:

$ ./loop.sh 1 2 3 4 5 6 7 8 9 10 11

หากตัวอย่างข้างต้นของ “endless loop” ถูกดำเนินการโดยใช้ until มันจะไม่ส่งออกสิ่งใด ซึ่งแตกต่างจาก while:

$ cat loop.sh #!/bin/bash count=10 จนถึง [ 1 = 1 ] do ((count++)) echo $count เสร็จแล้ว $ ./loop.sh $

เพราะ " เงื่อนไข"เดิมที" จริง"—เนื้อความของลูปจะไม่ถูกดำเนินการ

เช่นเดียวกับใน for loop คุณสามารถใช้ฟังก์ชันใน while และ until ได้ ตัวอย่างเช่น การวนซ้ำจากสคริปต์ในชีวิตจริงที่ตรวจสอบสถานะของเซิร์ฟเวอร์ แมวตัวผู้(PID ถูกนำมาจากระบบ สลสอาจแตกต่างกันในระบบอื่น) เวอร์ชันที่เรียบง่ายเล็กน้อย:

$ cat loop.sh #!/bin/bash check_tomcat_status () ( RUN=`ps aux | grep tomcat | grep -v grep | grep java | awk "(พิมพ์ $2)"` ) ในขณะที่ check_tomcat_status ทำถ้า [ -n "$ RUN" ] จากนั้น printf "คำเตือน: Tomcat ยังคงทำงานโดยมี PID $RUN" อย่างอื่น printf "Tomcat หยุด ดำเนินการต่อ...nn" พังเสร็จเรียบร้อย

ผลการดำเนินการ:

$ ./loop.sh คำเตือน: Tomcat ยังคงทำงานด้วย PID 14435 26548 คำเตือน: Tomcat ยังคงทำงานด้วย PID 14435 26548 คำเตือน: Tomcat ยังคงทำงานด้วย PID 14435 26548 คำเตือน: Tomcat ยังคงทำงานด้วย PID 14435 26548 คำเตือน: Tomcat ยังคง ทำงานด้วย PID 14435 26548 คำเตือน: Tomcat ยังคงทำงานด้วย PID 14435 26548 คำเตือน: Tomcat ยังคงทำงานด้วย PID 14435 26548 คำเตือน: Tomcat ยังคงทำงานด้วย PID 14435

เวอร์ชันเต็ม:

Check_tomcat_status () ( RUN=`ps aux | grep tomcat | grep -v grep | grep java | awk "(พิมพ์ $2)"` ) ในขณะที่ check_tomcat_status; จะทำอย่างไรถ้า [ -n "$RUN" ] จากนั้น printf "คำเตือน: Tomcat ยังคงทำงานด้วย PID $RUN หยุดไหม " ตอบ "หยุด Tomcat..." "กำลังดำเนินการติดตั้ง..." && $CATALINA_HOME/bin/shutdown . sh 2&>1 /dev/null || พัก sleep 2 ถ้า [ -n "$RUN" ] แล้ว printf "Tomcat ยังคงทำงานอยู่ ฆ่ามันเหรอ" ตอบ "กำลังฆ่า Tomcat..." "กำลังดำเนินการติดตั้ง...n" && kill $RUN || พักนอน 2 อย่างอื่น printf "Tomcat หยุดแล้วดำเนินการต่อ ... nn" พักเสร็จเรียบร้อยแล้ว

ฟังก์ชันคำตอบได้อธิบายไว้ในบทความ แต่มีการใช้เวอร์ชันที่ได้รับการปรับปรุงเล็กน้อย:

คำตอบ () ( ขณะที่อ่านคำตอบ ทำ echo case $response ใน |) printf "$1n" return 0 break ;; |) printf "$2n" คืน 1 ตัวแบ่ง ;; *) printf "กรุณากรอก Y(ใช่) หรือ N(no)! " esac เสร็จสิ้น )

ที่นี่คุณสามารถใช้ทั้ง while และ until - แต่ไม่ใช่ for loop เนื่องจาก for ใช้งานได้ครั้งเดียว (รับ PID และสิ้นสุด)

การวนซ้ำเป็นสิ่งที่สะดวกอย่างยิ่งเมื่อเขียนโปรแกรมหรือสคริปต์ใดๆ แม้จะจำเป็นก็ตาม พวกมันอนุญาตให้เรารันโค้ดบางส่วนตามจำนวนครั้งที่ระบุ โดยธรรมชาติแล้ว bash มีลูปหลายประเภท เราจะอธิบายวงจร สำหรับใน, สำหรับ, ในขณะที่, จนกระทั่ง. แม้ว่า for in และ for จะถือเป็นไวยากรณ์ที่แตกต่างกันของข้อความเดียวกัน แต่ในความคิดของฉัน มันแตกต่างกันมากกว่า while from until

ห่วงพร้อมตัวนับสำหรับเข้า:

วงจร สำหรับในนี่คือการวนซ้ำพร้อมตัวนับ บล็อกของโค้ดที่อยู่ในเนื้อหาของลูปจะถูกทำซ้ำหลาย ๆ ครั้งตามที่มีค่าที่มีอยู่ในรายการของ for in โอเปอเรเตอร์ และในการทำซ้ำแต่ละครั้งตัวแปรตัวนับ (ในที่นี้เรียกว่า var แต่แน่นอน คุณสามารถเรียกมันว่าอะไรก็ได้ที่คุณต้องการ) มีค่าขององค์ประกอบถัดไปของรายการ
หากคีย์เวิร์ด do อยู่ในบรรทัดเดียวกับคำว่า for คุณจะต้องใส่เครื่องหมายอัฒภาคหลังรายการอาร์กิวเมนต์ (ก่อนทำ)
แต่ละองค์ประกอบ<список>อาจมีหลายข้อโต้แย้ง สิ่งนี้มีประโยชน์เมื่อประมวลผลกลุ่มของพารามิเตอร์ ในกรณีนี้ เพื่อบังคับให้แยกวิเคราะห์ข้อโต้แย้งแต่ละรายการ<списке>คุณต้องใช้คำสั่งชุด
คุณสามารถใช้ตัวแปรเป็นรายการใน for loop ได้
ใน<списке>for loop สามารถใช้ชื่อไฟล์ ซึ่งในทางกลับกันสามารถมีอักขระไวด์การ์ดได้ สิ่งนี้มีประโยชน์มากเมื่อทำงานกับไฟล์จำนวนมาก
ถ้า<список>ไม่ได้ระบุใน for loop จากนั้นจึงใช้ตัวแปร $@ เป็นรายการอาร์กิวเมนต์บรรทัดคำสั่ง
เมื่อสร้างรายการอาร์กิวเมนต์ คุณสามารถใช้การทดแทนคำสั่งใน for loop ได้
เอาต์พุตของการวนซ้ำสามารถเปลี่ยนเส้นทางจาก stdout ไปยังไฟล์หรือที่อื่นได้ (คุณสามารถเรียนรู้เพิ่มเติมเกี่ยวกับสิ่งนี้ได้โดยดูที่การเปลี่ยนเส้นทาง I/O)

ไวยากรณ์:
สำหรับ var in<список>
ทำ
<выполняемые команды>
เสร็จแล้ว

ตัวอย่าง:
สำหรับชื่อในชื่อ1 ชื่อ2 ชื่อ3 ชื่อ4
ทำ
สะท้อนชื่อ $
เสร็จแล้ว

ตัวดำเนินการวนซ้ำ สำหรับมีวิธีการเขียนอีกวิธีหนึ่ง - คล้ายกับไวยากรณ์ของตัวดำเนินการ for ในภาษา C มาก ในกรณีนี้เมื่อเริ่มต้นตัวนับจะมีการตั้งค่าค่าเริ่มต้นของตัวแปรหรือตัวแปรหนึ่งตัวและหลังจากผ่านลูปแต่ละครั้งจะมีเงื่อนไข ถูกเลือก หากเช็คคืนค่าเป็นจริง การวนรอบครั้งถัดไปจะเริ่มต้นขึ้น ในบล็อก<приращение счётчиков>ค่าของตัวนับตัวแปรของเราต้องเปลี่ยนแปลง (ไม่จำเป็นต้องสูงขึ้น) เพื่อว่าเมื่อตรวจสอบเงื่อนไข ไม่ช้าก็เร็วเราจะได้ค่าเท็จ ไม่เช่นนั้นการวนซ้ำจะไม่มีวันสิ้นสุด ตัวเลือกที่สะดวกและคุ้นเคยที่สำคัญที่สุดหากจำเป็นต้องทำซ้ำตามจำนวนที่ระบุ

ด้วยไวยากรณ์ที่คล้ายกัน:
สำหรับ ((<инициализация счётчиков>; <проверка условия>; <приращение счётчиков>))
ทำ
<выполняемые команды>
เสร็จแล้ว

ตัวอย่าง:
สำหรับ ((var=1; var<= LIMIT ; var++))
ทำ
เสียงสะท้อน $var
เสร็จแล้ว

ในขณะที่วนซ้ำ:

นี่เป็นโครงสร้างที่ค่อนข้างง่ายที่จะตรวจสอบสภาพเบื้องหลังของผู้ปฏิบัติงาน ในขณะที่และหากเงื่อนไขนี้เป็นจริง มันจะดำเนินการบล็อกของคำสั่งที่อยู่ระหว่างคำว่า do และ Done จากนั้นจึงดำเนินการตรวจสอบเงื่อนไขอีกครั้ง หากการตรวจสอบส่งคืนเท็จ รอบจะสิ้นสุดและคำสั่งต่อไปนี้จะเริ่มดำเนินการ: เสร็จแล้ว. จำเป็นอย่างยิ่งที่จะต้องแน่ใจว่า<проверка условия>ขึ้นอยู่กับโค้ดที่ทำงานอยู่ในลูป มิฉะนั้น หากผลลัพธ์ของการตรวจสอบไม่เปลี่ยนแปลง คุณจะเกิดการวนซ้ำไม่สิ้นสุด
อุปกรณ์อินพุตมาตรฐานสำหรับลูป while สามารถเปลี่ยนเส้นทางไปยังไฟล์ได้โดยใช้คำสั่งการเปลี่ยนเส้นทาง< в конце цикла.

ไวยากรณ์:
ในขณะที่<Проверка условия>
ทำ
<Блок команд, обязательно меняющий переменные влияющие на проверку условия>
เสร็จแล้ว

ตัวอย่าง:
ในขณะที่ [ $var0 -eq 100 ]
ทำ
เสียงสะท้อน $var
วาร์++
เสร็จแล้ว

ผู้ดำเนินการ ในขณะที่อาจมีเงื่อนไขหลายประการ แต่มีเพียงคนสุดท้ายเท่านั้นที่จะกำหนดความเป็นไปได้ในการดำเนินวงจรต่อไป ในกรณีนี้ ไวยากรณ์ของตัวดำเนินการลูปจะแตกต่างจากรูปแบบปกติ
ไวยากรณ์(ฉันขอย้ำอีกครั้งว่าเฉพาะเงื่อนไขสุดท้ายเท่านั้นที่ส่งผลต่อการดำเนินการของลูป) :
ในขณะที่
<условие1>
<условие2>

<условиеN>
ทำ
<выполняемые команды - тело цикла>
เสร็จแล้ว

จนกระทั่งวนซ้ำ:

ผู้ดำเนินการ จนกระทั่งคล้ายกับ while มาก นอกจากนี้ยังประเมินเงื่อนไขด้วย แต่จะประมวลผลเนื้อความของลูปหากผลลัพธ์ของการคำนวณเป็นเท็จ อาจดูผิดปกติ แต่จนกระทั่งประเมินเงื่อนไขก่อนที่จะผ่านครั้งแรกของลูป เช่น ในขณะที่ ไม่ใช่หลังจากนั้น เช่นเดียวกับ for/in loops เมื่อวางคีย์เวิร์ด do ในบรรทัดเดียวกับการประกาศ loop คุณต้องแทรกอักขระ ";" ก่อนทำ
เช่นเดียวกับในกรณีก่อนหน้านี้ สิ่งสำคัญคือต้องจำไว้ว่าเงื่อนไขต้องขึ้นอยู่กับการดำเนินการในเนื้อหาของลูป ไม่เช่นนั้นสคริปต์ของเราจะไม่มีวันเสร็จสมบูรณ์

ไวยากรณ์:
จนกระทั่ง<Проверка условия>
ทำ
<Блок команд, обязательно меняющий переменные влияющие на проверку условия>
เสร็จแล้ว

ตัวอย่าง:
จนถึง [ $var0 -gt 100] # มีการตรวจสอบเงื่อนไขเมื่อเริ่มต้นการวนซ้ำ
ทำ
เสียงสะท้อน $var
วาร์--
เสร็จแล้ว

ก็น่าจะเพียงพอแล้วสำหรับตอนนี้ :)

  • กลับ
  • ซึ่งไปข้างหน้า

บทความใหม่:

  • การค้นพบเครือข่ายไม่เปิดขึ้นใน Windows 7/8/2008/2012
  • ข้อผิดพลาด: แอปพลิเคชันนี้ไม่สามารถเริ่มทำงานได้เนื่องจากไม่พบหรือโหลดปลั๊กอินแพลตฟอร์ม Qt "windows"
  • การกำหนดค่าการรีสตาร์ทอัตโนมัติของกระบวนการของผู้ปฏิบัติงาน rphost.exe บนเซิร์ฟเวอร์ 1C 8.3
  • วิธีการลดขนาดของบันทึกธุรกรรม (.ldf) ใน MS SQL 2008/20012

    MS SQL เช่นเดียวกับ DBMS อุตสาหกรรมที่ดีอื่นๆ พร้อมด้วยฐานข้อมูล จะเก็บบันทึกธุรกรรมที่ช่วยให้คุณสามารถย้อนกลับสถานะ...

0 มีรัน บาลา-กุมารัน

ฉันกำลังพยายามเข้าใจจริงๆ ว่าทำไมการวนซ้ำ while จึงไม่สิ้นสุด เมื่อการวนซ้ำเริ่มต้น ตัวแปร LOC ของฉันถูกตั้งค่าเป็น Testing/ ซึ่งเป็นไดเร็กทอรีที่ฉันสร้างขึ้นเพื่อทดสอบโปรแกรมนี้มีเลย์เอาต์ดังต่อไปนี้:

ฉันต้องการให้การวนซ้ำสิ้นสุดเมื่อไดเร็กทอรีทั้งหมดใช้ฟังก์ชัน "นับ" แล้ว
นี่คือสิ่งที่ฉันลอง

ฉันตรวจสอบฟังก์ชันการนับแล้ว แต่มันไม่สร้างการวนซ้ำไม่สิ้นสุด

ฉันพยายามเรียกใช้อัลกอริทึมด้วยตนเอง

PARSE=1 LOC=$LOC/ count AVAILABLEDIR=$(ls $LOC -AFl | sed "1 d" | grep "/$" | awk "( print $9 )") ในขณะที่ [ $PARSE = "1" ] do if [[ $(AVAILABLEDIR[@]) == "" ]]; จากนั้น PARSE=0 fi DIRBASE=$LOC สำหรับ a ใน $(AVAILABLEDIR[@]); do LOC="$(DIRBASE)$(a)" LOCLIST="$LOCLIST $LOC" นับเสร็จแล้วสำหรับ a ใน $(LOCLIST[@]); ทำ TMPAVAILABLEDIR=$(ls $a -AFl | sed "1 d" | grep "/$" | awk "( พิมพ์ $9 )") PREPEND=$a ถ้า [[ $(TMPAVAILABLEDIR[@]) == "" ] ]; จากนั้นดำเนินการต่อ fi สำหรับ a in $(TMPAVAILABLEDIR[@]); ทำ TMPAVAILABLEDIR2="$TMPAVAILABLEDIR2 $(PREPEND[@])$(a)" เสร็จสิ้น NEWAVAILABLEDIR="$NEWAVAILABLEDIR $TMPAVAILABLEDIR2" เสร็จสิ้น AVAILABLEDIR=$NEWAVAILABLEDIR NEWAVAILABLEDIR="" LOC="" เสร็จสิ้น

ฉันกำลังดิ้นรนจริงๆ และข้อเสนอแนะใดๆ จะได้รับการชื่นชมอย่างมาก ฉันพยายามคิดหาคำตอบนี้ในช่วงสองชั่วโมงที่ผ่านมา

ทุบตีวงอนันต์

4 คำตอบ

คุณควรลองรันสคริปต์ด้วยอาร์กิวเมนต์ -x หรือเขียนไว้ในบรรทัดแรก:

#!/bin/bash -x

จากนั้นเขาจะบอกคุณทุกอย่างที่เขาทำ

ในกรณีนี้ คุณอาจสังเกตเห็นข้อผิดพลาดสองประการ:

    คุณไม่เคยโหลด TMPAVAILABLEDIR2 ใหม่

    คุณยังทำ ls กับไฟล์ปกติด้วย

หากคุณต้องหลีกเลี่ยงการเรียกซ้ำจริงๆ ให้ลองทำสิ่งนี้โดยสมบูรณ์โดยไม่ต้องเรียกซ้ำ:

#!/bin/bash count() ( echo counting "$1" ) todo=(Testing) while test $(#todo[@]) != 0 do doit=("$(todo[@])") todo= () สำหรับ dir ใน "$(doit[@])" do สำหรับรายการใน "$dir"/* # ถ้า dir ว่างเปล่า นี่จะแสดงรายการชื่อ "*" do test -e "$entry" || ดำเนินการต่อ # ข้ามรายการ "*" ของจำนวน dir ที่ว่างเปล่า "$entry" test -d "$entry" || Continue todo+=("$entry") เสร็จแล้ว เสร็จแล้ว

อย่างไรก็ตาม โปรดบอกฉันว่าทำไมคุณไม่สามารถใช้การเรียกซ้ำได้ อาการแบบนี้เป็นภูมิแพ้หรือเปล่า? คำสาบาน? มีกฎหมายท้องถิ่นเกี่ยวกับซอฟต์แวร์แบบเรียกซ้ำในที่ที่คุณอาศัยอยู่หรือไม่?

คุณเขียนว่าคุณต้องการ "นับ" ในการตัดทั้งหมด ตรวจสอบตัวเลือกการค้นหา:

ค้นหา $LOC -พิมพ์ d | ในขณะที่อ่าน dir; ทำ cd $LOC cd $(dir) นับเสร็จแล้ว

หรือสั้นกว่า (เมื่อตัวนับฟังก์ชันของคุณรับไดเร็กทอรีเป็นพารามิเตอร์ 1)

ค้นหา $LOC -พิมพ์ d | xargs นับ

ตอนนี้ฉันเห็นว่าคุณไม่ต้องการใช้ find หรือ ls -R (ฟังก์ชันเรียกซ้ำ) จากนั้นคุณควรสร้างฟังก์ชันแบบเรียกซ้ำของคุณเองเช่น

ฟังก์ชั่น parseDir ( ls -d */ $1 | ในขณะที่อ่าน dir; ให้นับ parseDir $1/$dir เสร็จสิ้น)

ฉันไม่รู้ว่าสิ่งนี้จะได้ผลหรือไม่ แต่เป็นคำถามที่น่าสนใจที่ฉันหยุดคิดไม่ได้เลย ขอให้โชคดี

ในขณะที่จริง; ทำเพื่อคำใน "$(echo *)" ; ทำ if [[ -d "$word" ]] ; จากนั้น d[$((i++))]="$PWD"/"$word" elif [[ -f "$word" ]] ; จากนั้น f[$((j++))]="$PWD"/"$ word" fi เสร็จแล้ว [[ $k -gt $i ]] && cd .. cd "$d[$((k++))]" || พังเสร็จแล้ว