ใช้“ ในขณะที่อ่าน…” ในสคริปต์ linux


34

ใครช่วยกรุณาอธิบายวิธีการทำงานของรหัสต่อไปนี้?

echo '1 2 3 4 5 6' | while read a b c
do
  echo $c $b $a
done

โดยเฉพาะฉันต้องการทราบว่าเหตุใดผลลัพธ์ของลูปนี้คือ3 4 5 6 2 1แทนที่จะเป็น3 2 1และ6 5 4แยกกันสองบรรทัด ฉันดูเหมือนจะห่อใจไม่ได้ ...

คำตอบ:


41

readอ่านทั้งบรรทัดจากอินพุตมาตรฐานแยกบรรทัดลงในฟิลด์และกำหนดฟิลด์นี้ให้กับตัวแปรที่กำหนด หากมีชิ้นส่วนมากกว่าตัวแปรชิ้นส่วนที่เหลือจะถูกกำหนดให้กับตัวแปรสุดท้าย

ในกรณีของคุณ$aจะได้รับมอบหมาย1, $bได้รับมอบหมาย2และส่วนที่เหลืออีก$c3 4 5 6


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

24

การเขียนวนซ้ำด้วยวิธีนี้จะเผยให้เห็นสิ่งที่เกิดขึ้น:

echo '1 2 3 4 5 6' | while read a b c
  do
    echo '(iteration beginning)' a="$a" b="$b" c="$c" '(iteration ending)'
  done

สิ่งนี้จะให้เป็นเอาท์พุท:

(iteration beginning) a=1 b=2 c=3 4 5 6 (iteration ending)

ขอให้สังเกตก่อนว่ามีเพียงคำสั่ง echo เดียวเท่านั้นที่รัน หากมีการเรียกใช้มากกว่าหนึ่งครั้งคุณจะเห็นสิ่งที่พิมพ์(iteration beginning)และวัสดุ(iteration ending)พิมพ์มากกว่าหนึ่งครั้ง

นี่คือการพูดว่าการwhileวนซ้ำที่นี่ไม่ได้สำเร็จอะไรเลย readbuiltin อ่านช่องว่างที่คั่นข้อความ1ลงในตัวแปรที่ระบุไว้ในแต่ละ อินพุตพิเศษจะถูกต่อท้ายส่วนท้ายของตัวแปรสุดท้ายที่ระบุ 2ดังนั้นตัวแปรaและbใช้เวลาในการค่า1และ2ตามลำดับในขณะที่ใช้เวลาในค่าc3 4 5 6

เมื่อเงื่อนไขลูป ( while read a b c) ถูกประเมินเป็นครั้งที่สองจะไม่มีอินพุตอีกต่อไปจากไพพ์ (เราเพียงไพพ์มันเป็นข้อความบรรทัดเดียว) ดังนั้นreadคำสั่งจะประเมินเป็นเท็จแทนที่จะเป็นจริงและลูปหยุด (ก่อนที่จะรัน ร่างกายเป็นครั้งที่สอง)

1 : เพื่อเป็นทางด้านเทคนิคและเฉพาะbuiltinเมื่อผ่านชื่อตัวแปรเป็นอาร์กิวเมนต์อ่านอินพุตแยกมันกลายเป็น "คำว่า" แยกจากกันเมื่อพบไอเอฟเอช่องว่าง (เห็นคำถามนี้และบทความนี้ )read

2 : readพฤติกรรมของการติดขัดของช่องพิเศษของการป้อนข้อมูลลงในตัวแปรสุดท้ายที่ระบุไม่ได้ใช้งานได้ง่ายเพื่อ Scripters จำนวนมากในตอนแรก มันกลายเป็นเรื่องง่ายที่จะเข้าใจเมื่อคุณพิจารณาว่าเป็นคำตอบ Florian Diesch กล่าวว่า , readมักจะ (พยายาม) อ่านบรรทัดทั้งหมด - และที่readมีจุดมุ่งหมายที่จะใช้งานได้ทั้งที่มีและไม่มีห่วง


Eliah ขอบคุณที่สละเวลาอธิบายรายละเอียดทั้งหมด ฉันสงสัยwhileว่าไม่ได้ให้บริการตามวัตถุประสงค์ตามปกติในตัวอย่างนี้ แต่จากนั้นreadคำสั่งก็โยนฉันออกไป ... อย่างใดฉันก็ตีความว่าเป็น "ในขณะที่read a b cไม่ได้เป็นเท็จทำecho ..." ขอบคุณที่อธิบายว่ามันใช้งานได้จริงอย่างไร ฉันเจอรหัสนี้เมื่อวานนี้และรู้ว่ามันจะบั๊กฉันจนกว่าฉันจะคิดออก ... lol
linuxgringo

@linuxgringo จริง ๆ แล้ว body loop จะถูกประมวลผลทุกครั้งที่read a b cประเมินเป็นจริงและเงื่อนไข loop ( read a b c) ทำงานมากกว่าหนึ่งครั้ง บิตจะประเมินเป็นจริงครั้งที่ 1 เท่านั้น เวลาที่ 2 ไม่มีการป้อนข้อมูลมากขึ้นที่จะอ่านจากท่อดังนั้นจุดสิ้นสุดของแฟ้มจะพบก่อให้เกิดreadผลตอบแทนที่เป็นเท็จ (ดูส่วนสุดท้ายของผลลัพธ์ของhelp read, ใน "Exit Status", สำหรับรายละเอียด, สังเกตว่า, ในเชลล์สคริปต์, zero หมายถึงเป็นจริงและไม่ใช่ศูนย์หมายถึงเป็นเท็จ) ถ้าคุณ piped อินพุตมากกว่าหนึ่งบรรทัดwhile read ..., ร่างกายลูปจะ ถูกดำเนินการหลายครั้ง
Eliah Kagan
โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.