บางคนมีความคิดที่ผิดพลาดนั่นreadคือคำสั่งให้อ่านบรรทัด มันไม่ใช่.
readอ่านคำจากบรรทัด (อาจเป็นแบ็กสแลช - ต่อ) ซึ่งคำนั้น$IFSคั่นด้วยและแบ็กสแลชสามารถใช้เพื่อหลีกเลี่ยงตัวคั่น (หรือต่อบรรทัด)
ไวยากรณ์ทั่วไปคือ:
read word1 word2... remaining_words
readอ่าน stdin หนึ่งไบต์ในเวลาจนกว่าจะพบตัวละครที่ไม่ใช้ Escape ขึ้นบรรทัดใหม่ (หรือจุดสิ้นสุดของการป้อนข้อมูล) แยกว่าเป็นไปตามกฎระเบียบที่ซับซ้อนและร้านค้าผลมาจากการแยกที่เข้าสู่$word1, ...$word2$remaining_words
ตัวอย่างเช่นการป้อนข้อมูลเช่น:
<tab> foo bar\ baz bl\ah blah\
whatever whatever
และมีค่าเริ่มต้นของ$IFS, read a b cจะกำหนด:
$a ⇐ foo
$b ⇐ bar baz
$c ⇐ blah blahwhatever whatever
ทีนี้ถ้าผ่านการโต้แย้งเพียงครั้งเดียวนั่นจะไม่เกิดread lineขึ้น read remaining_wordsก็ยังคง การประมวลผลแบ็กสแลชยังคงดำเนินการอยู่ตัวอักขระช่องว่างของ IFS ยังคงถูกลบออกจากจุดเริ่มต้นและจุดสิ้นสุด
-rตัวเลือกเอาการประมวลผลเครื่องหมาย ดังนั้นคำสั่งเดียวกันข้างต้นด้วย-rแทนที่จะกำหนด
$a ⇐ foo
$b ⇐ bar\
$c ⇐ baz bl\ah blah\
ตอนนี้สำหรับส่วนที่แยกเป็นสิ่งสำคัญที่จะต้องตระหนักว่ามีสองคลาสของตัวอักษรสำหรับ$IFS: ตัวละครที่ช่องว่างของ IFS (คือช่องว่างและแท็บ (และขึ้นบรรทัดใหม่ถึงแม้ว่าที่นี่จะไม่สำคัญจนกว่าคุณจะใช้ -d) ที่จะอยู่ในค่าเริ่มต้นของ$IFS) และอื่น ๆ การรักษาตัวละครสองคลาสนั้นแตกต่างกัน
ด้วยIFS=:( :ไม่ใช่ตัวละครช่องว่างของ IFS) ข้อมูลที่ต้องการ:foo::bar::จะถูกแบ่งออกเป็น"", "foo"และ"", barและ""(และพิเศษ""กับการใช้งานบางอย่างแม้ว่ามันจะไม่สำคัญยกเว้นread -a) ในขณะที่ถ้าเราแทนที่ที่:มีพื้นที่แยกจะทำลงไปเพียงและfoo barนั่นคือการนำหน้าและส่วนท้ายจะถูกละเว้นและลำดับของสิ่งนั้นจะถูกมองเหมือนหนึ่ง $IFSมีกฎระเบียบเพิ่มเติมเมื่อช่องว่างและไม่ว่างตัวอักษรมีการรวมกันในการเป็น การใช้งานบางอย่างสามารถเพิ่ม / ลบการดูแลเป็นพิเศษได้โดยเพิ่มตัวละครเป็นสองเท่าใน IFS ( IFS=::หรือIFS=' ')
ดังนั้นที่นี่หากเราไม่ต้องการให้ตัวอักขระช่องว่างว่างที่นำหน้าและต่อท้ายถูกตัดออกเราจำเป็นต้องลบอักขระช่องว่างสีขาวของ IFS ออกจาก IFS
ถึงแม้จะมีตัวละครไอเอฟเอที่ไม่ใช่ช่องว่างถ้าสายการป้อนข้อมูลที่มีหนึ่ง (และมีเพียงหนึ่ง) ของตัวละครเหล่านั้นและมันเป็นตัวอักษรตัวสุดท้ายในบรรทัด (เช่นIFS=: read -r wordการป้อนข้อมูลเช่นfoo:) กับ POSIX เปลือกหอย (ไม่ได้zshหรือบางpdkshรุ่น), การป้อนข้อมูลที่ ถือเป็นหนึ่งในfooคำเพราะในเปลือกหอยเหล่านั้นตัวละคร$IFSนี้ถือว่าเป็นจุดสิ้นสุดดังนั้นwordจะมีไม่ได้foofoo:
ดังนั้นวิธีบัญญัติของการอ่านอินพุตหนึ่งบรรทัดด้วยreadบิวอินคือ:
IFS= read -r line
(โปรดทราบว่าสำหรับreadการนำไปใช้ส่วนใหญ่จะใช้งานได้เฉพาะกับบรรทัดข้อความเนื่องจากไม่รองรับอักขระ NUL ยกเว้นในzsh)
การใช้var=value cmdไวยากรณ์ทำให้แน่ใจว่าIFSมีการตั้งค่าแตกต่างกันเฉพาะในช่วงเวลาของcmdคำสั่งนั้น
ประวัติความเป็นมา
readbuiltin ได้รับการแนะนำโดยเปลือกบอร์นและมีอยู่แล้วในการอ่านคำไม่สาย มีความแตกต่างที่สำคัญเล็กน้อยกับเชลล์ POSIX ที่ทันสมัย
บอร์นเชลล์readไม่รองรับ-rตัวเลือก (ซึ่งได้รับการแนะนำโดย Korn เชลล์) ดังนั้นจึงไม่มีวิธีที่จะปิดการใช้งานแบ็กสแลชนอกเหนือจากการประมวลผลอินพุตล่วงหน้าด้วยบางอย่างที่sed 's/\\/&&/g'นั่น
เชลล์เป้าหมายไม่ได้มีความคิดเกี่ยวกับอักขระสองคลาส (ซึ่งแนะนำโดย ksh อีกครั้ง) ใน Bourne shell ตัวละครทุกตัวผ่านการบำบัดเช่นเดียวกับตัวละครที่ช่องว่างของ IFS ทำใน ksh ที่อยู่IFS=: read a b cในการป้อนข้อมูลที่foo::barจะกำหนดbarให้$bไม่ใช่สตริงที่ว่างเปล่า
ในเชลล์เป้าหมายด้วย:
var=value cmd
หากcmdเป็นแบบในตัว (เช่นเดียวกับread) ส่วนที่varเหลือจะถูกตั้งค่าเป็นvalueหลังจากcmdเสร็จสิ้น นั่นเป็นสิ่งสำคัญอย่างยิ่ง$IFSเพราะในเชลล์เป้าหมาย$IFSถูกใช้เพื่อแยกทุกอย่างไม่เพียง แต่การขยาย นอกจากนี้หากคุณลบอักขระช่องว่างออกจาก$IFSในเชลล์เป้าหมาย"$@"ไม่ทำงานอีกต่อไป
ในเชลล์เป้าหมายการเปลี่ยนเส้นทางคำสั่งผสมทำให้มันทำงานใน subshell (ในเวอร์ชันแรกสุดแม้กระทั่งสิ่งที่ชอบread var < fileหรือexec 3< file; read var <&3ไม่ทำงาน) ดังนั้นมันจึงไม่ค่อยเกิดขึ้นใน Bourne shell ที่จะใช้readเพื่ออะไรก็ได้ยกเว้นอินพุตผู้ใช้บนเทอร์มินัล (ในกรณีที่การจัดการความต่อเนื่องของบรรทัดนั้นสมเหตุสมผล)
Unices บางอัน (เช่น HP / UX มีอีกหนึ่งในutil-linux) ยังคงมีlineคำสั่งให้อ่านหนึ่งบรรทัดของอินพุต (ซึ่งเคยเป็นคำสั่ง UNIX มาตรฐานจนถึงรุ่น Single UNIX Specification 2 )
โดยพื้นฐานแล้วจะเหมือนกับhead -n 1อ่านยกเว้นทีละหนึ่งไบต์เพื่อให้แน่ใจว่าจะไม่อ่านมากกว่าหนึ่งบรรทัด ในระบบเหล่านั้นคุณสามารถทำได้:
line=`line`
แน่นอนว่าหมายถึงการวางไข่กระบวนการใหม่รันคำสั่งและอ่านเอาต์พุตผ่านไพพ์ดังนั้นจึงมีประสิทธิภาพน้อยกว่า ksh IFS= read -r lineแต่ก็ยังมีสัญชาตญาณมากขึ้น