ทำความเข้าใจกับค่าเริ่มต้นของ IFS


10

ใน GNU bash รุ่น 4.2.8 ของฉัน IFS มีค่าเริ่มต้นของพื้นที่แท็บและตัวป้อนบรรทัดตามค่าเริ่มต้น:

usr@T42 ~ $ echo -n "$IFS" | hexdump -C
00000000  20 09 0a                                          | ..|
00000003
usr@T42 ~ $ 

มีเหตุผลสำหรับ IFS เริ่มต้นดังกล่าวหรือไม่ นอกจากนี้ที่สาธารณูปโภคใช้ไอเอฟเอนอกเหนือจากการทุบตีในตัวread?

คำตอบ:


13

ตัวแปรไอเอฟเอจะใช้ทุกครั้งที่เปลือกดำเนินงานที่เรียกว่าแยกคำ กรณีทั่วไปที่มีการใช้งานนี้คือหลังจากการขยายพารามิเตอร์ (เช่น$var) หรือการทดแทนคำสั่ง (เช่น$(some-command)หรือ backticks ที่เลิกใช้แล้ว) ในคำสั่ง ที่นี่หากการขยายตัวมีIFSตัวละครใด ๆแล้วมันจะแบ่งออกเป็น 'คำ' ที่แตกต่างกันก่อนที่คำสั่งจะถูกประมวลผล อย่างมีประสิทธิภาพนี่หมายความว่าอักขระเหล่านี้แบ่งข้อความที่ถูกแทนที่ออกเป็นอาร์กิวเมนต์ต่าง ๆ (รวมถึงชื่อของคำสั่งหากระบุตัวแปรไว้ก่อน)

ดังนั้นเหตุผลสำหรับค่าเริ่มต้นของIFSการเป็นพื้นที่แท็บและการขึ้นบรรทัดใหม่คือสิ่งเหล่านี้เป็นอักขระช่องว่างที่ปกติแล้วจะต้องแบ่งคำ

วิธีหนึ่งในการป้องกันไม่ให้เกิดการแยกคำเกิดขึ้นคือใช้เครื่องหมายคำพูดคู่รอบส่วนขยาย ( "$var") - อันที่จริงแล้วคุณได้ทำสิ่งนี้ในคำถามของคุณแล้ว หากคุณไม่ได้ทำสิ่งนี้จะไม่มีผลลัพธ์จากการechoที่มันจะไม่มีข้อโต้แย้งเฉพาะอักขระที่แยกอาร์กิวเมนต์

โปรดทราบว่าสถานที่สองแห่งที่การแยกคำไม่เกิดขึ้นหลังจากการขยายพารามิเตอร์ขึ้นอยู่กับการกำหนดตัวแปร (เช่นvar=$othervarและใช้ได้var=$(somecommand)) และภายใน[[ ]]โครงสร้าง ( [[ $var = $othervar ]]ก็โอเค แต่[ $var = $othervar ]ควรอ้างอิง)

ในที่สุดเมื่อนักปราชญ์ชี้ให้ฉันฟังครั้งหนึ่งความเข้าใจผิดที่พบบ่อยคือการป้องกันการแยกคำเป็นเพียงเหตุผลเดียวที่อ้างถึงตัวแปร ไม่ใช่การอ้างอิงยังป้องกันการขยายชื่อพา ธหรือการขยายแบบกลมเนื่องจากเป็นที่รู้จักกันมากกว่า หากตัวแปรมีอักขระ glob เช่น*นั้นสิ่งเหล่านี้อาจถูกขยายเป็นชื่อไฟล์เมื่อมีการใช้ตัวแปร unquote ในคำสั่ง เช่นพิจารณา:

var=*
echo $var

นี่จะแสดงชื่อของไฟล์ในไดเรกทอรีปัจจุบัน

ในฐานะที่เป็นจุด Stephane ดังต่อไปนี้คำสั่งของตัวละครภายในอย่างมีนัยสำคัญเมื่อการขยายตัวIFS "$*"จากbashหน้าคน:

"$*" is equivalent to "$1c$2c...", where c is the first character of the value of
the IFS variable.  If IFS is unset, the parameters are separated by spaces.  If
IFS is null, the parameters are joined without intervening separators.

สำหรับตัวอย่างเพิ่มเติมของการแยกคำโปรดดูคำตอบนี้ - https://unix.stackexchange.com/a/118444/48083


1
ตัวอักษรตัวแรกของ$IFSยังถูกใช้"$*"ซึ่งเป็นสาเหตุที่คำสั่งซื้อมีความสำคัญ
Stéphane Chazelas

2
นอกจากนี้โปรดทราบว่าzshมีอักขระ NUL ในค่าเริ่มต้น$IFS(เชลล์อื่นไม่สนับสนุนการถืออักขระ NUL ในตัวแปรของพวกเขา)
Stéphane Chazelas
โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.