bash เปลี่ยนพฤติกรรมขึ้นอยู่กับค่าของตัวแปร“ IFS”


18

เมื่อฉันตั้งค่าIFSตัวแปรเป็นช่องว่างให้bashถือว่าหลายช่องว่างเป็นหนึ่งช่องว่าง ( myprogramเป็นโปรแกรมที่พิมพ์อาร์กิวเมนต์บรรทัดคำสั่งที่ได้รับ):

IFS=" "
x="hello   hi   world"
./myprogram $x
argv[1] = hello
argv[2] = hi
argv[3] = world

แต่เมื่อฉันตั้งค่าIFSตัวแปรเป็นเครื่องหมายจุลภาคbashไม่ถือว่าเครื่องหมายจุลภาคหลายรายการเป็นเครื่องหมายจุลภาคเดียว:

IFS=","
x="hello,,,hi,,,world"
./myprogram $x
argv[1] = hello
argv[2] = 
argv[3] = 
argv[4] = hi
argv[5] = 
argv[6] = 
argv[7] = world

ทำไมถึงเป็นอย่างนั้น?


เพียงสำหรับการอ้างอิง "ไอเอฟเอ" หมายถึงภายในสนามคั่น
pr1268

คำตอบ:


21

man bashนี้ถูกบันทึกไว้ใน การเกิดขึ้นครั้งเดียวของอักขระใด ๆ ใน IFS ที่ไม่ใช่ช่องว่างคั่นเขตข้อมูล

จากman bash:

เชลล์ใช้อักขระแต่ละตัวของ IFS เป็นตัวคั่นและแยกผลลัพธ์ของการขยายตัวอื่น ๆ ออกเป็นคำโดยใช้อักขระเหล่านี้เป็นตัวยุติฟิลด์ ถ้าไอเอฟเอไม่มีการตั้งค่าหรือความคุ้มค่าเป็นสิ่ง<space><tab><newline>เริ่มต้นแล้วลำดับของ<space>, <tab>และ<newline>ที่จุดเริ่มต้นและจุดสิ้นสุดของผลของการขยายตัวก่อนหน้านี้จะถูกละเลยและลำดับตัวอักษรใด ๆ ไอเอฟเอไม่ได้อยู่ที่จุดเริ่มต้นหรือจุดสิ้นสุดทำหน้าที่ในการกำหนดเขต คำ. หาก IFS มีค่าอื่นที่ไม่ใช่ค่าเริ่มต้นลำดับของพื้นที่ว่างของอักขระช่องว่างแท็บและขึ้นบรรทัดใหม่จะถูกละเว้นที่จุดเริ่มต้นและจุดสิ้นสุดของคำตราบใดที่อักขระช่องว่างอยู่ในค่าของ IFS (ตัวอักษรช่องว่าง IFS ) อักขระใด ๆ ใน IFS ที่ไม่ใช่ช่องว่าง IFS พร้อมกับอักขระช่องว่าง IFS ที่อยู่ติดกันใด ๆ จะคั่นเขตข้อมูล ลำดับของอักขระช่องว่างของ IFS ยังถือว่าเป็นตัวคั่น หากค่าของ IFS เป็นโมฆะจะไม่เกิดการแบ่งคำ [เน้นเพิ่มแล้ว]

ตัวอย่าง: การแยกฟิลด์

หาก IFS ไม่มีอักขระช่องว่างช่องว่างจะรวมอยู่ในฟิลด์:

$ ( IFS=',' x='one , two,three'; printf "<%s>\n" $x )
<one >
< two>
<three>

หาก IFS มีทั้งช่องว่างและเครื่องหมายจุลภาคดังนั้นลำดับของช่องว่างตามด้วยเครื่องหมายจุลภาคตามด้วยลำดับของช่องว่างจะถือว่าเป็นตัวคั่นเดียว:

$ ( IFS=' ,' x='one , two,three'; printf "<%s>\n" $x )
<one>
<two>
<three>

ลำดับของเครื่องหมายจุลภาคถูกตีความว่าเป็นลำดับของฟิลด์ว่าง:

$ ( IFS=' ,' x='one,,,two,three'; printf "<%s>\n" $x )
<one>
<>
<>
<two>
<three>

ตัวอย่าง: ช่องว่างนำหน้าและต่อท้าย

หาก IFS ไม่มีช่องว่างดังนั้นช่องว่างนำหน้าและต่อท้ายใด ๆ จะถูกเก็บไว้ในฟิลด์:

$ ( IFS=',' x='  one , two,three  ,'; printf "<%s>\n" $x )
<  one >
< two>
<three  >

หาก IFS มีช่องว่างดังนั้นลำดับชั้นนำหรือส่วนท้ายของช่องว่างจะถูกลบออก:

$ ( IFS=' ,' x='  one , two,three  ,'; printf "<%s>\n" $x )
<one>
<two>
<three>

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

@JeffSchaller ความคิดที่ยอดเยี่ยม: ฉันเพิ่งเพิ่มส่วนในนั้น
John1024


ถ้าคุณมีไฟล์คั่นด้วยแท็บที่มีค่าหายไป เช่นคุณไม่ต้องการให้ลำดับของแท็บถูกจัดเป็นแท็บเดียว นอกจากนี้เขตข้อมูลมีเครื่องหมายจุลภาคดังนั้นจึงไม่สามารถใช้เป็นตัวคั่นได้ เป็นวิธีเดียวที่จะใช้ตัวคั่นอื่น (ไม่ใช่แท็บ)?
Davos

@Davos สำหรับข้อมูลที่มีแต่ละเขตคั่นด้วยแท็บเดียวก็อาจจะเป็นธรรมชาติมากขึ้นที่จะใช้เครื่องมืออื่น ๆ ที่จัดการนี้เช่นง่ายดายเช่นเดียวawkกับตัวเลือกหรือ-F'\t' cutหรือถ้าคุณมีรุ่นล่าสุดของbashคุณอาจจะไม่สามารถที่จะแยกช่องที่ใช้readarrayกับ-d$'\t'ตัวเลือก
John1024
โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.