บางคนมีความคิดที่ผิดพลาดนั่น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
จะมีไม่ได้foo
foo:
ดังนั้นวิธีบัญญัติของการอ่านอินพุตหนึ่งบรรทัดด้วยread
บิวอินคือ:
IFS= read -r line
(โปรดทราบว่าสำหรับread
การนำไปใช้ส่วนใหญ่จะใช้งานได้เฉพาะกับบรรทัดข้อความเนื่องจากไม่รองรับอักขระ NUL ยกเว้นในzsh
)
การใช้var=value cmd
ไวยากรณ์ทำให้แน่ใจว่าIFS
มีการตั้งค่าแตกต่างกันเฉพาะในช่วงเวลาของcmd
คำสั่งนั้น
ประวัติความเป็นมา
read
builtin ได้รับการแนะนำโดยเปลือกบอร์นและมีอยู่แล้วในการอ่านคำไม่สาย มีความแตกต่างที่สำคัญเล็กน้อยกับเชลล์ 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
แต่ก็ยังมีสัญชาตญาณมากขึ้น