ไวยากรณ์สำหรับ Bash บรรทัดเดียวแบบไม่ จำกัด ในขณะที่วนซ้ำ


633

ฉันกำลังมีปัญหาในการหาเซมิโคลอนและ / หรือเครื่องหมายปีกกาที่ถูกต้อง ฉันต้องการทำเช่นนี้ แต่เป็นหนึ่งซับจากบรรทัดคำสั่ง:

while [ 1 ]
do
    foo
    sleep 2
done

4
แทนที่บรรทัดใหม่ด้วยเครื่องหมายอัฒภาค การทำงานแบบเดียวกันสำหรับลูป
Tom

23
@Tom: มันไม่ได้ผลเสมอไป หลังจากที่ทำคุณต้องมีคำสั่งแรกไม่อัฒภาค
สเตฟาโนโอบอรินี่

คำตอบ:


1230
while true; do foo; sleep 2; done

โดยวิธีการถ้าคุณพิมพ์เป็น multiline (ตามที่คุณแสดง) ที่พรอมต์คำสั่งแล้วเรียกประวัติด้วยลูกศรขึ้นคุณจะได้รับมันในบรรทัดเดียวคั่นอย่างถูกต้อง

$ while true
> do
>    echo "hello"
>    sleep 2
> done
hello
hello
hello
^C
$ <arrow up> while true; do    echo "hello";    sleep 2; done

2
"ถ้าคุณพิมพ์เป็น multiline (ขณะที่คุณกำลังแสดง) ที่พรอมต์คำสั่งแล้วเรียกประวัติด้วยลูกศรขึ้นคุณจะได้รับมันในบรรทัดเดียวคั่นด้วยเครื่องหมายถูกต้อง" ไม่เป็นความจริงสำหรับฉัน
Vincent Scheib

@VincentScheib ให้ตรวจสอบcmdhistตัวเลือกว่าคุณใช้ทุบตีหรือไม่?
Alok Singhal

ยอดเยี่ยม ทำงานได้อย่างสมบูรณ์บน Mavericks (Mac OS-X 10.9) และอนุญาตให้ฉันใช้ vpn ต่อไป Openconnect ยกเลิกการเชื่อมต่อหลังจากสองสามชั่วโมงโดยมีข้อผิดพลาดเกี่ยวกับคุกกี้ที่ไม่ดี ดังนั้นฉันจึงใส่คำสั่ง openconnect ไว้ในเชลล์สคริปต์, sudo su เพื่อเป็นรูท, และใช้ cmd line นี้: while true; do sh /Users/myuser/bin/vpn ; done
Blisterpeanuts

170

นอกจากนี้ยังเป็นไปได้ที่จะใช้คำสั่ง sleep ในขณะที่สภาพของ ทำให้สายการบินหนึ่งดูสะอาดยิ่งขึ้น

while sleep 2; do echo thinking; done

16
สิ่งนี้ทำมากกว่าการเปลี่ยนไวยากรณ์ - มันจะดำเนินการคำสั่งหลังสลีป ในคำตอบก่อนหน้าคำสั่งจะถูกดำเนินการทันที สิ่งที่ควรทราบ
DanGordon

@DanGordon while echo thinking ; do sleep 2 ; done แน่นอนถ้าคำสั่ง [ขณะ] ล้มเหลววงออกดังนั้นคุณจะต้องwhile echo thinking || true ; do sleep 2 ; doneแต่แล้วคุณจะกลับมาwhile true ; ...
Brian Carcich

69

โคลอนเป็น "จริง" เสมอ:

while :; do foo; sleep 2; done

15
ทำไมลำไส้ใหญ่ถึงเป็นจริงเสมอ
Jürgen Paul

8
@Pinapple Under the Sea: จากหน้าคนทุบตี: (ในส่วนคำสั่งของเปลือกอาคาร BUILTIN) : [arguments] ไม่มีผลกระทบ; คำสั่งไม่ทำอะไรเลยนอกเหนือจากการขยายข้อโต้แย้งและดำเนินการเปลี่ยนเส้นทางที่ระบุ ส่งคืนรหัสทางออกศูนย์
เอเดรียน W

2
แนะนำให้ใช้ไวยากรณ์นี้เป็น: เป็นส่วนหนึ่งของเชลล์เองเช่น: เป็นคำสั่งเชลล์บิวด์อิน
avner

@analytik คุณจะบอกว่าเป็นบวกหรือลบ? ;-)
Brian Carcich

33

คุณสามารถใช้เครื่องหมายอัฒภาคเพื่อแยกข้อความสั่งได้:

$ while [ 1 ]; do foo; sleep 2; done

3
ฉันชอบคำตอบนี้เพราะมันจะอธิบายเวลาและเหตุผล; (เซมิโคลอน) จำเป็นต้องมี
นาย AndreasGeo

29

คุณยังสามารถใช้ประโยชน์จากuntilคำสั่ง:

until ((0)); do foo; sleep 2; done

โปรดทราบว่าในทางตรงกันข้ามกับwhile,untilจะดำเนินการคำสั่งที่อยู่ภายในวงตราบใดที่สภาพการทดสอบมีสถานะทางออกที่ไม่เป็นศูนย์


ใช้whileวง:

while read i; do foo; sleep 2; done < /dev/urandom

ใช้forวง:

for ((;;)); do foo; sleep 2; done

วิธีอื่นโดยใช้until:

until [ ]; do foo; sleep 2; done

until ((0)); do foo; sleep 2; doneดูเหมือนจะไม่ทำงาน มันไม่มีที่สิ้นสุดอย่างต่อเนื่อง
030

11

วนรอบไม่สิ้นสุดง่ายมาก .. :)

while true ; do continue ; done

fr คำถามของคุณมันจะเป็น:

while true; do foo ; sleep 2 ; done

8

ฉันต้องการใช้เครื่องหมายอัฒภาคสำหรับคำสั่ง WHILE เท่านั้นและตัวดำเนินการ && เพื่อให้ลูปทำมากกว่าหนึ่งอย่าง ...

ดังนั้นฉันจะทำเช่นนี้เสมอ

while true ; do echo Launching Spaceship into orbit && sleep 5s && /usr/bin/launch-mechanism && echo Launching in T-5 && sleep 1s && echo T-4 && sleep 1s && echo T-3 && sleep 1s && echo T-2 && sleep 1s && echo T-1 && sleep 1s && echo liftoff ; done

1
การใช้&&วงวนนั้นเหมือนกับเวลาอื่น ๆ จริง ๆ ใช่ไหม คุณต้องการสิ่งที่สองที่จะเกิดขึ้นเฉพาะในกรณีที่เกิดขึ้นครั้งแรกแล้วใช้&&อย่างอื่น;พอเพียง จริงๆแล้วคุณต้องการให้เนื้อหาของวงนั้นสั้นและเรียบง่ายเป็นเลิศเพียงคำสั่งเดียวดังนั้นฟังก์ชั่นหรือสคริปต์
thecoshman


6

การใช้while:

while true; do echo 'while'; sleep 2s; done

ใช้forวน:

for ((;;)); do echo 'forloop'; sleep 2; done

การใช้Recursion(แตกต่างจากด้านบนเล็กน้อยขัดจังหวะโดยแป้นพิมพ์จะไม่หยุด)

list(){ echo 'recursion'; sleep 2; list; } && list;

5

หากคุณต้องการให้ลูป while หยุดหลังจากเงื่อนไขบางอย่างและfooคำสั่งของคุณจะส่งกลับไม่ใช่ศูนย์เมื่อตรงตามเงื่อนไขนี้แล้วคุณจะได้รับลูปที่จะแบ่งเป็นดังนี้

while foo; do echo 'sleeping...'; sleep 5; done;

ตัวอย่างเช่นหากfooคำสั่งกำลังลบสิ่งต่าง ๆ ในแบตช์และมันจะส่งคืน 1 เมื่อไม่มีอะไรเหลือให้ลบ

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

ตัวอย่างเช่นสมมติว่าคุณมีสคริปต์ไพ ธ อนbatch_update.pyซึ่งจะอัปเดต 100 แถวในฐานข้อมูลและส่งคืน0หากมีมากกว่าที่จะอัปเดตและ1หากไม่มีอีกต่อไป คำสั่งต่อไปนี้จะช่วยให้คุณอัปเดตแถวละ 100 พร้อมกับพักเป็นเวลา 5 วินาทีระหว่างการปรับปรุง:

while batch_update.py; do echo 'sleeping...'; sleep 5; done;

แล้วคุณจะออกจากอย่างไร
AK_

คุณทำการfooออกคำสั่งด้วยรหัส1เมื่อคุณต้องการให้ลูป while หยุดพัก ฉันได้อัปเดตคำตอบของฉันด้วยตัวอย่าง
Yep_It's_Me

2

ถ้าฉันสามารถยกตัวอย่างสองตัวอย่าง (พร้อมกับ "อารมณ์")

สิ่งนี้จะเขียนชื่อของไฟล์ทั้งหมดที่ลงท้ายด้วย ".jpg" ในโฟลเดอร์ "img":

for f in *; do if [ "${f#*.}" == 'jpg' ]; then echo $f; fi; done

วิธีนี้จะลบ:

for f in *; do if [ "${f#*.}" == 'jpg' ]; then rm -r $f; fi; done

แค่พยายามมีส่วนร่วม


1
@JKnight - สำหรับตัวอย่างเหล่านี้คุณจะไม่ทำls -1 *.jpgและrm *.jpg
Kevin Fegan

2
ทั้งคู่ไม่ใช่ลูปอนันต์และไม่ใช่ขณะลูป
แมเรียน

2

คุณสามารถลองทำสิ่งนี้ได้เช่นกันคำเตือน: สิ่งนี้คุณไม่ควรทำ แต่เนื่องจากคำถามที่ถามถึงการวนซ้ำแบบไม่มีที่สิ้นสุดโดยไม่สิ้นสุด ... นี่คือวิธีที่คุณทำได้

while [[ 0 -ne 1 ]]; do echo "it's looping";   sleep 2; done

ทำไมคุณถึงทำอย่างนั้น
gniourf_gniourf

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