ความหมายที่แท้จริงของ IFS = $ '\ n' คืออะไร?


125

หากตัวอย่างต่อไปนี้ซึ่งตั้งค่าIFSตัวแปรสภาพแวดล้อมเป็นอักขระฟีดบรรทัด ...

IFS=$'\n'
  • อะไรเครื่องหมายดอลลาร์หมายความ ว่า ?
  • มันทำอะไรในกรณีเฉพาะนี้?
  • ฉันจะอ่านเพิ่มเติมเกี่ยวกับการใช้งานเฉพาะนี้ได้ที่ไหน (Google ไม่อนุญาตให้ใช้อักขระพิเศษในการค้นหาและฉันไม่รู้ว่าจะค้นหาอะไรเป็นอย่างอื่น)

ฉันรู้ว่าIFSตัวแปรสภาพแวดล้อมคืออะไรและ\nตัวละครคืออะไร (ฟีดบรรทัด) แต่ทำไมไม่ใช้แบบฟอร์มต่อไปนี้: IFS="\n"(ซึ่งใช้ไม่ได้)

ตัวอย่างเช่นหากฉันต้องการวนซ้ำทุกบรรทัดของไฟล์และต้องการใช้ for loop ฉันสามารถทำได้:

for line in (< /path/to/file); do
    echo "Line: $line"
done

อย่างไรก็ตามการดำเนินการนี้จะใช้ไม่ได้จนกว่าIFSจะตั้งค่าเป็นอักขระป้อนบรรทัด เพื่อให้ใช้งานได้ฉันต้องทำสิ่งนี้:

OLDIFS=$IFS
IFS=$'\n'
for line in (< /path/to/file); do
    echo "Line: $line"
done
IFS=$OLDIFS

หมายเหตุ:ฉันไม่ต้องการวิธีอื่นในการทำสิ่งเดียวกันฉันรู้หลายอย่างแล้ว ... ฉันแค่อยากรู้เรื่องนั้น$'\n'และสงสัยว่าจะมีใครให้คำอธิบายกับฉันได้บ้าง

คำตอบ:


161

โดยปกติbashจะไม่ตีความลำดับการหลีกเลี่ยงในตัวอักษรสตริง ดังนั้นถ้าคุณเขียน\nหรือ"\n"หรือ'\n'นั่นไม่ใช่ linebreak - มันคือตัวอักษรn(ในกรณีแรก) หรือแบ็กสแลชตามด้วยตัวอักษรn(ในอีกสองกรณี)

$'somestring'เป็นไวยากรณ์สำหรับตัวอักษรของสตริงที่มีลำดับหนี จึงไม่เหมือน'\n', $'\n'จริงเป็น LINEBREAK


2
ไม่เป็นเช่นนั้น - \nเป็นเพียงตัวอักษร (Escape) n คุณพูดถูก'\n'และ"\n"มีฟันเฟืองตามด้วย n
Roman Cheplyaka

15
โปรดทราบว่า$'\n'เฉพาะ bash - จะไม่ทำงานใน POSIX shell ( /bin/sh) เพื่อให้ได้เอฟเฟกต์เดียวกันในลักษณะที่สอดคล้องกับ POSIX คุณสามารถพิมพ์IFS='จากนั้นกด return เพื่อพิมพ์อักขระขึ้นบรรทัดใหม่จริงจากนั้นพิมพ์ปิด'
Richard Hansen

23
IFS=$(echo -e '\n')ควรทำด้วยวิธีที่เข้ากันได้กับ POSIX
Vineet

12
@Vineet - มันทำให้ฉันหยุดเพื่อโต้แย้งความคิดเห็นที่ถูกโหวต แม้ว่านี่จะเป็น Posix ที่ถูกต้อง แต่ก็ไม่ได้ผล - ตัวดำเนินการแทนคำสั่งใน bash จะลบอักขระขึ้นบรรทัดใหม่ทั้งหมด ดูนี้สำหรับรายละเอียดเพิ่มเติม
Digital Trauma

9
@DigitalTrauma ผมคิดว่ามันไม่ได้ POSIX: -eไม่ได้กำหนดและ\nโดยไม่ต้อง-eทำงานเป็นส่วนขยาย XSI: pubs.opengroup.org/onlinepubs/9699919799/utilities/... printf '\n'หิน;)
Ciro Santilli 郝海东冠状病六四事件法轮功

21

เพียงเพื่อให้โครงสร้างของมันชื่ออย่างเป็นทางการ : สตริงในรูปแบบ$'...'ที่เรียกว่าสตริง ANSI C-ยกมา

นั่นคือเช่นเดียวกับในสตริง [ANSI] C ลำดับการหลีกเลี่ยงแบ็กแลชได้รับการยอมรับและขยายให้เทียบเท่าตัวอักษร (ดูด้านล่างสำหรับรายการลำดับการหลีกเลี่ยงที่รองรับทั้งหมด)

หลังจากที่ขยายตัวนี้$'...'สตริงในลักษณะเดียวกับ'...'สตริง - คือพวกเขากำลังได้รับการรักษาเป็นตัวอักษรไม่ได้อยู่ภายใต้การใด ๆ [เพิ่มเติม] ขยายเปลือก

ตัวอย่างเช่น$'\n'ขยายเป็นอักขระขึ้นบรรทัดใหม่ตามตัวอักษรซึ่งเป็นสิ่งที่ตัวอักษร bash string ทั่วไป (ไม่ว่า'...'หรือ"...") ไม่สามารถทำได้ [1]

คุณสมบัติที่น่าสนใจอีกประการหนึ่งคือสตริงที่ยกมา ANSI C สามารถหลีกเลี่ยง'(เครื่องหมายคำพูดเดี่ยว) เป็น\'ซึ่ง'...'(สตริงที่ยกมาเดี่ยวทั่วไป) ไม่สามารถ:

echo $'Honey, I\'m home' # OK; this cannot be done with '...'

รายการลำดับการหลีกเลี่ยงที่รองรับ :

ลำดับการหลีกเลี่ยงแบ็กสแลชหากมีอยู่จะถูกถอดรหัสดังนี้:

\ การแจ้งเตือน (กระดิ่ง)

\ b backspace

\ e \ E อักขระหลีก (ไม่ใช่ ANSI C)

\ f ฟีดแบบฟอร์ม

\ n ขึ้นบรรทัดใหม่

\ r กลับรถ

แท็บแนวนอน

\ v แท็บแนวตั้ง

\ แบ็กสแลช

\ 'คำพูดเดียว

\ "เครื่องหมายคำพูดคู่

\ nn อักขระแปดบิตที่มีค่าเป็นค่าฐานแปด nnn (หนึ่งถึงสามหลัก)

\ xHH อักขระแปดบิตที่มีค่าเป็นค่าฐานสิบหก HH (เลขฐานสิบหกหนึ่งหรือสองหลัก)

\ uHHHH อักขระ Unicode (ISO / IEC 10646) ที่มีค่าเป็นค่าเลขฐานสิบหก HHHH (เลขฐานสิบหกหนึ่งถึงสี่หลัก)

\ UHHHHHHH อักขระ Unicode (ISO / IEC 10646) ที่มีค่าเป็นค่าเลขฐานสิบหก HHHHHHHH (เลขฐานสิบหกหนึ่งถึงแปดหลัก)

\ cx อักขระ control-x

ผลลัพธ์ที่ขยายเป็นเครื่องหมายคำพูดเดียวราวกับว่าไม่มีเครื่องหมายดอลลาร์


[1] อย่างไรก็ตามคุณสามารถฝังบรรทัดใหม่จริงในสตริง "... " และ "... " กล่าวคือคุณสามารถกำหนดสตริงที่ครอบคลุมหลายบรรทัด


16

จากhttp://www.linuxtopia.org/online_books/bash_guide_for_beginners/sect_03_03.html :

คำในรูปแบบ "$ 'STRING'" ได้รับการปฏิบัติด้วยวิธีพิเศษ คำขยายเป็นสตริงโดยแทนที่อักขระที่ใช้เครื่องหมายแบ็กสแลชจะถูกแทนที่ตามที่ระบุโดยมาตรฐาน ANSI-C Backslash Escape sequences สามารถพบได้ในเอกสาร Bash.found

ฉันเดาว่ามันบังคับให้สคริปต์หนีจากบรรทัดฟีดไปเป็นมาตรฐาน ANSI-C ที่เหมาะสม


8

การกู้คืน IFS เริ่มต้น - OLDIFS=$IFSไม่จำเป็น รัน IFS ใหม่ใน subshell เพื่อหลีกเลี่ยงการแทนที่ IFS เริ่มต้น:

ar=(123 321); ( IFS=$'\n'; echo ${ar[*]} )

นอกจากนี้ฉันไม่เชื่อจริงๆว่าคุณกู้ IFS เก่าได้อย่างสมบูรณ์ OLDIFS="$IFS"คุณดับเบิลควรพูดมันเพื่อหลีกเลี่ยงการทำลายเส้นเช่น


2
นี่เป็นเทคนิคที่มีประโยชน์มาก args=$(IFS='&'; echo "$*")ฉันเพียงแค่ใช้มันสำหรับเปลือกทำความสะอาดเข้าร่วมสหกรณ์: การฟื้นฟูIFSการ$' \t\n'ในลักษณะที่เป็นมิตรเปลือกบอร์นจะไม่มีความหมายเพลง
jeberle

Re Besides I don't really believe you recover the old IFS fully: การแยกคำไม่ได้ดำเนินการใน RHS ของการกำหนดตัวแปร (แต่การลบเครื่องหมายคำพูดคือ) ดังนั้นOLDIFS=$IFSและOLDIFS="$IFS"ทำงานในลักษณะเดียวกัน
mklement0

3

ANSI C-quoted strings เป็นจุดสำคัญ ขอบคุณข้อมูล @ mklement0

คุณสามารถทดสอบสตริง ANSI C-quoted ด้วยคำสั่ง od

echo -n $'\n' | od -c
echo -n '\n' | od -c
echo -n $"\n" | od -c
echo -n "\n" | od -c

ขาออก:

0000000  \n  
0000001

0000000   \   n   
0000002

0000000   \   n   
0000002

0000000   \   n   
0000002

คุณสามารถทราบความหมายได้อย่างชัดเจนจากผลลัพธ์


-7

เหมือนกับการดึงค่าจากตัวแปร:

VAR='test'
echo VAR
echo $VAR

มีความแตกต่างกันดังนั้นเครื่องหมายดอลลาร์จึงประเมินเนื้อหาโดยทั่วไป


6
สิ่งนี้ไม่เกี่ยวข้องกับตัวแปร $'FOO'( $FOOซึ่งแตกต่างจากคำถามนี้ไม่ได้เกี่ยวกับ) เป็นสตริงตามตัวอักษร หากคุณดำเนินการecho $'VAR'คุณจะเห็นว่ามันพิมพ์สตริงไม่VAR test
sepp2k
โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.