ฉันจะเขียน for loop ใน bash ได้อย่างไร


96

ฉันกำลังมองหาลูปพื้นฐานเช่น:

for(int i = 0; i < MAX; i++) {
  doSomething(i);
}

แต่สำหรับทุบตี


คำตอบ:


107

จากไซต์นี้ :

for i in $(seq 1 10);
do
    echo $i
done

10
มันกล่าวถึงมูลค่าการว่าช่วงที่ระบุไว้ที่นี่เป็นที่รวม จากนั้นฉันหมายความว่าคุณจะเห็นช่วงทั้งหมด (1 ถึง 10) พิมพ์ลงในคอนโซล
Jamie


34

bash forประกอบด้วยตัวแปร (ตัววนซ้ำ) และรายการคำที่ตัววนซ้ำจะทำซ้ำ

ดังนั้นหากคุณมีรายการคำที่ จำกัด ให้ใส่ไว้ในไวยากรณ์ต่อไปนี้:

for w in word1 word2 word3
do
  doSomething($w)
done

คุณอาจต้องการวนซ้ำตามตัวเลขเพื่อให้คุณสามารถใช้seqคำสั่งเพื่อสร้างรายการตัวเลขสำหรับคุณ: (จาก 1 ถึง 100 เป็นต้น)

seq 1 100

และใช้ในวง FOR:

for n in $(seq 1 100)
do
  doSomething($n)
done

สังเกต$(...)ไวยากรณ์ เป็นพฤติกรรมทุบตีช่วยให้คุณสามารถส่งเอาต์พุตจากคำสั่งหนึ่ง (ในกรณีของเราจากseq) ไปยังอีกคำสั่ง(the for)

สิ่งนี้มีประโยชน์มากเมื่อคุณต้องทำซ้ำในไดเรกทอรีทั้งหมดในบางเส้นทางเช่น:

for d in $(find $somepath -type d)
do
  doSomething($d)
done

ความเป็นไปได้ไม่มีที่สิ้นสุดในการสร้างรายการ


2
คำตอบที่ดี แต่คุณอาจต้องการรวม for ((i = 0; i <MAX; i ++)); ทำ doSomething ($ i); ทำตัวแปรเช่นกัน ฉันคิดว่าโดยทั่วไปแล้วสิ่งนี้ต้องการสำหรับตัวแปร for i ใน $ (seq 0 MAX) เนื่องจากตัวหลังจะสร้างตัวเลขทั้งหมดจาก 0 ถึง MAX ก่อนที่จะดำเนินการวนซ้ำจริง
mweerden

30

Bash 3.0+สามารถใช้ไวยากรณ์นี้:

for i in {1..10} ; do ... ; done

.. ซึ่งหลีกเลี่ยงการวางไข่โปรแกรมภายนอกเพื่อขยายลำดับ (เช่นseq 1 10)

แน่นอนว่าปัญหานี้มีปัญหาเช่นเดียวกับการfor(())แก้ปัญหาการผูกติดกับ bash และแม้แต่รุ่นใดรุ่นหนึ่ง (หากเป็นเรื่องสำคัญสำหรับคุณ)


14

ลองใช้bashความช่วยเหลือในตัว:


$ help for

for: for NAME [in WORDS ... ;] do COMMANDS; done
    The `for' loop executes a sequence of commands for each member in a
    list of items.  If `in WORDS ...;' is not present, then `in "$@"' is
    assumed.  For each element in WORDS, NAME is set to that element, and
    the COMMANDS are executed.
for ((: for (( exp1; exp2; exp3 )); do COMMANDS; done
    Equivalent to
        (( EXP1 ))
        while (( EXP2 )); do
            COMMANDS
            (( EXP3 ))
        done
    EXP1, EXP2, and EXP3 are arithmetic expressions.  If any expression is
    omitted, it behaves as if it evaluates to 1.



5
#! /bin/bash

function do_something {
   echo value=${1}
}

MAX=4
for (( i=0; i<MAX; i++ )) ; {
   do_something ${i}
}

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

Z=$(date) awk 'BEGIN { for ( i=0; i<4; i++ ) { print i,"hello",ENVIRON["Z"]; } }'

แต่ขอให้โชคดีที่ทำสิ่งที่มีประโยชน์ภายในawk: ฉันจะใช้ตัวแปรเชลล์ในสคริปต์ awk ได้อย่างไร


2
ฉันไม่เคยสังเกตมาก่อน แต่มีการแสดงไวยากรณ์ที่คล้ายกันในหนึ่งในคำตอบก่อนหน้านี้ สิ่งที่เป็นเอกลักษณ์ของที่นี่คือการใช้วงเล็บปีกกาแทนแบบทั่วไปdo/ doneคู่
Brent Bradburn

4

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

ตัวอย่าง:

ฉันต้องการเรียกใช้คำสั่ง uptime บนโฮสต์ส่วนหน้า 1-5 และโฮสต์แบ็กเอนด์ 1-3:

% for host in {frontend{1..5},backend{1..3}}.mycompany.com
    do ssh $host "echo -n $host; uptime"
  done

ฉันมักจะเรียกใช้สิ่งนี้เป็นคำสั่งบรรทัดเดียวโดยมีเครื่องหมายอัฒภาคที่ส่วนท้ายของบรรทัดแทนที่จะเป็นเวอร์ชันที่อ่านได้มากขึ้นด้านบน ข้อควรพิจารณาในการใช้งานหลักคือวงเล็บปีกกาช่วยให้คุณระบุค่าหลายค่าที่จะแทรกลงในสตริง (เช่น pre {foo, bar} ผลลัพธ์ของโพสต์ใน prefoopost, prebarpost) และอนุญาตให้มีการนับ / ลำดับโดยใช้จุดคู่ (คุณสามารถใช้ a. .z เป็นต้น) อย่างไรก็ตามไวยากรณ์ช่วงเวลาคู่เป็นคุณลักษณะใหม่ของ bash 3.0 เวอร์ชันก่อนหน้าจะไม่รองรับสิ่งนี้


เกี่ยวกับเรื่องนี้จะเกิดอะไรขึ้นถ้า $ host var เป็นบรรทัดว่างโดยบังเอิญ? มันจะยังคงยิง ssh ดังนั้นฉันจะหลีกเลี่ยงสิ่งนั้นได้อย่างไร ในกรณีของฉันฉันกำลังทำอะไรบางอย่างที่แตกต่างออกไปคำตอบของคุณจะช่วยฉันได้ ฉันกำลังพยายามตรวจสอบ Gmail เพื่อหาข้อความใหม่และหากพบให้ส่ง SMS จากและหัวเรื่อง คำถามของฉันมีข้อความว่า "Connecting Two Bash Commands" ถ้าคุณต้องการอ่าน
Volomike

ฉันไม่เชื่อว่าคุณจะได้ $ host var ว่างเปล่า เนื่องจากตัวอย่างด้านบนใช้การขยายตัวของวงเล็บปีกกา for loop ตั้งค่าตัวแปร $ host อย่างชัดเจนเป็นค่า: frontend1.mycompany.com frontend2.mycompany.com . backend1.mycompany.com แต่ถ้าคุณเห็นวิธีที่จะมีค่า null ฉันสนใจที่จะรู้ คุณสามารถดำเนินการ ssh ภายในการทดสอบตามเงื่อนไขได้หากเป็นปัญหา
บริการ

1

หากคุณสนใจเฉพาะในการทุบตีโซลูชัน "for ((... )) ที่นำเสนอข้างต้นเป็นวิธีที่ดีที่สุด แต่ถ้าคุณต้องการบางสิ่งที่สอดคล้องกับ POSIX SH ซึ่งจะใช้ได้กับทุกหน่วยคุณจะต้องใช้" expr "และ "while" และนั่นเป็นเพราะ "(())" หรือ "seq" หรือ "i = i + 1" ไม่สามารถพกพาได้ระหว่างเชลล์ต่างๆ


0

ฉันใช้รูปแบบนี้ตลอดเวลาในการประมวลผลไฟล์ ...

สำหรับไฟล์ใน * .log; ทำ echo "Do stuff with: $ files"; echo "ทำสิ่งต่างๆได้มากขึ้นด้วย: $ files"; เสร็จแล้ว;

หากการประมวลผลรายการของไฟล์คือสิ่งที่คุณกำลังสนใจในการมองเข้าไปใน-execdirเลือกสำหรับไฟล์


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