อะไรคือความแตกต่างระหว่างเครื่องหมายคำพูด“ …”, '…', $ '…' และ $“ …”?


49

บางครั้งผมเห็นสคริปต์ใช้ทั้งหมดของวิธีการที่แตกต่างกันเหล่านี้อ้างข้อความบางส่วน: "...", '...', และ$'...' $"..."เหตุใดจึงมีการใช้เครื่องหมายคำพูดต่าง ๆ มากมาย?

พวกเขามีพฤติกรรมที่แตกต่างหรือส่งผลกระทบต่อสิ่งที่ฉันสามารถทำได้ภายในพวกเขา?


1
ซ้ำไซต์ที่เป็นไปได้ คำตอบนี้ให้ข้อมูลสรุปของ (หรือลิงค์ไป) ความหมายของคำพูดประเภทต่าง ๆ ทั้งหมด
chepner

คำตอบ:


66

ทั้งหมดเหล่านี้มีความหมายแตกต่างกันและคุณสามารถเขียนสิ่งต่าง ๆ ภายในพวกเขา (หรือสิ่งเดียวกันกับความหมายที่แตกต่างกัน) เครื่องหมายคำพูดประเภทต่างๆตีความลำดับการหลีกเลี่ยงที่แตกต่างกันภายใน ( \something) หรือทำหรือไม่อนุญาตการแก้ไขตัวแปร ( $something) และการขยายประเภทอื่น ๆ

ในระยะสั้น:

  • '...' เป็นตัวอักษรทั้งหมด
  • "..." อนุญาตให้ทั้งตัวแปรและอักขระเครื่องหมายคำพูดฝังตัว
  • $'...'ดำเนินการ\nยกเว้นอักขระเช่นแต่ไม่ขยายตัวแปร
  • $"..." สำหรับการแปลภาษามนุษย์ใน Bash และ ksh

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

สิ่งที่คุณเขียนระหว่างคำพูดเดียวจะได้รับการปฏิบัติอย่างแท้จริงและไม่ได้รับการประมวลผลเลย เครื่องหมายแบ็กสแลชและเครื่องหมายดอลลาร์ไม่มีความหมายพิเศษ ซึ่งหมายความว่าคุณไม่สามารถ backslash-escape อักขระ (รวมถึงเครื่องหมายอัญประกาศเดี่ยวอื่น ๆ !) สอดแทรกตัวแปรหรือใช้คุณสมบัติเชลล์อื่น ๆ

ตัวอย่างทั้งหมดเหล่านี้ส่งผลให้สิ่งที่เขียนระหว่างคำพูด:

'hello world'                     => hello world
'/pkg/bin:$PATH'                  => /pkg/bin:$PATH
'hello\nworld'                    => hello\nworld
'`echo abc`'                      => `echo abc`
'I\'dn\'t've'                     => I\dn'tve

อันสุดท้ายมีความซับซ้อน - มีสองสายอักขระที่มีเครื่องหมายคำพูดเดียวทำงานร่วมกับข้อความบางส่วนที่ไม่ได้ยกมา I\คนแรกที่มี ข้อความที่ไม่มีdn\'tเครื่องหมายอัญประกาศประกอบด้วยเครื่องหมายอัญประกาศเดี่ยวที่อยู่ที่ระดับเชลล์ดังนั้นจึงไม่เริ่มต้นสตริงที่ยกมาและรวมเป็นอักขระตัวอักษร (ดังนั้นdn't) veสตริงยกสุดท้ายเป็นเพียง ทั้งหมดนั้นรวมเข้าด้วยกันเป็นคำเดียวในวิธีปกติที่เชลล์ใช้งานได้

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

'let x="'$PATH\"

จะส่งผลให้

let x="/usr/bin:/bin"

เป็นคำเดียว (ดีกว่าเพื่ออ้างสองครั้ง$PATHเช่นกันในกรณี - ช่องว่างหรือตัวอักษรกลมในค่าตัวแปรอาจถูกประมวลผลเป็นอย่างอื่น - แต่เพื่อประโยชน์ของตัวอย่างการทำงานที่อ่านได้ฉันไม่ได้)


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

ภายในเครื่องหมายอัญประกาศคู่การประมวลผลส่วนขยายสองประเภทจะได้รับการประมวลผลและคุณสามารถใช้เครื่องหมายแบ็กสแลชเพื่อยกเว้นอักขระเพื่อป้องกันไม่ให้มีการประมวลผลส่วนขยายหรือส่วนขยาย

มีการขยายสองประเภทที่เกิดขึ้นภายในเครื่องหมายคำพูดคู่:

ภายในคำพูดเครื่องหมายสามารถยับยั้งการขยายเหล่านั้นโดยวางไว้ก่อนหรือ$ `นอกจากนี้ยังสามารถหลีกเลี่ยงการปิดการอ้างอิงสองครั้งดังนั้น\"รวม"ไว้ในสตริงของคุณหรือแบ็กสแลชอื่น เครื่องหมายแบ็กสแลชอื่น ๆ จะถูกเก็บรักษาไว้อย่างแท้จริง - ไม่มีทางหนีรอดเพื่อสร้างตัวละครอื่น ๆ และจะไม่ถูกลบออก

ตัวอย่างเหล่านี้บางอย่างมีลักษณะแตกต่างไปจากเมื่อก่อนและบางตัวอย่างก็ไม่:

"hello world"                     => hello world
"/pkg/bin:$PATH"                  => /pkg/bin:/bin:/usr/bin
"hello\nworld"                    => hello\nworld
"hello\\nworld"                   => hello\nworld
"`echo abc`"                      => abc
"I\'dn\'t've"                     => I\'dn\'t've
"I'dn't've"                       => I'dn't've
"I\"dn\"t've"                     => I"dn"t've

$ 'ANSI-C ข้อความ'

การอ้างถึงชนิดนี้อนุญาตให้ใช้เครื่องหมายแบคสแลชแบบ C-style แต่ไม่สามารถใช้ตัวแปรหรือการแทนที่แบบฝังได้ มันเป็นเพียงชนิดของข้อความที่สนับสนุนตัวละครหนี

นี่คือส่วนขยายจาก ksh ปัจจุบันสนับสนุนใน Bash, zsh และเชลล์อื่น ๆ เช่นกัน มันยังไม่ได้เป็นส่วนหนึ่งของมาตรฐาน POSIX ดังนั้นสคริปต์แบบพกพาสูงสุดไม่สามารถใช้งานได้ แต่สคริปต์ Bash หรือ ksh นั้นฟรี

ทั้งหมดหนีเหล่านี้สามารถนำมาใช้กับความหมายของพวกเขา C: \a, \b, \f, \n, \r, \t, \vและหนีตัวอักษร\\, \', และ\" \?พวกเขายังสนับสนุนส่วนขยาย\e(อักขระหลบหนี) และใน Bash และ ksh \cx(สิ่งที่จะถูกป้อนโดย Ctrl-xเช่น\cMคืนรถ) เชลล์มีช่วงของการขยายเล็กน้อยของตัวเอง

นอกจากนี้ยังช่วยให้ตัวละครทั่วไปสี่ชนิดหนีออกมาได้:

  • \nnnไบต์เดียวที่มีค่าฐานแปดnnn
  • \xHHไบต์เดียวที่มีค่าเลขฐานสิบหกHH
  • \uHHHHตัวเข้ารหัส Unicode ที่มีดัชนีเลขฐานสิบหกคือHHHH
  • \UHHHHHHHHตัวเข้ารหัส Unicode ที่มีดัชนีเลขฐานสิบหกคือHHHHHHHHH

ตัวเลขทั้งหมดเหล่านี้เป็นทางเลือกหลังจากตัวเลขแรก

$และ`ไม่มีความหมายและเก็บรักษาไว้อย่างแท้จริงดังนั้นคุณจึงไม่สามารถรวมตัวแปรที่นั่น

$'hello world'                    => hello world
$'/pkg/bin:$PATH'                 => /pkg/bin:$PATH
$'hello\nworld'                   => hello
                                     world
$'`echo abc`'                     => `echo abc`
$'I\'dn\'t\'ve'                   => I'dn't've
$'\U1f574\u263A'                  => 🕴☺

ส่วนใหญ่หนีเหล่านี้คุณสามารถจำลองการใช้คำสั่งแม้ว่า POSIX เพียงต้องการ, , , , , , , และทำงานที่นั่น คุณสามารถใช้แทนคำสั่งการฝังราคาคู่ภายในถ้าจำเป็น:printf\\\a\b\f\n\r\t\v\nnnprintf"Path:$(printf '\t')$PATH"


$ "การแปลสถานที่"

นี่เป็นส่วนขยายเฉพาะ ksh- และ Bash สำหรับการแปลสตริงข้อความภาษาธรรมชาติและทำการค้นหาส่วนภายในเครื่องหมายคำพูดในแค็ตตาล็อกข้อความ จะดำเนินการขยายคำพูดสองครั้งทั้งหมดก่อน หากไม่พบสตริงในฐานข้อมูลการแปลจะใช้เป็นการแปลของตนเอง สมมติฐานในตัวคือสตริงเป็นภาษาอังกฤษ

คุณอาจไม่ต้องการใช้อันนี้ แต่ถ้าคุณเห็นมันคุณสามารถถือว่ามันเป็นอัญประกาศปกติ


จุดหนึ่งของโน้ตก็คือว่ามีไม่มีชนิดของข้อความที่ช่วยให้ทั้งการขยายตัวพารามิเตอร์ฝังและฝังตัวหนีตัวอักษร ในกรณีส่วนใหญ่ที่คุณต้องการคุณจะดีกว่า (ปลอดภัยกว่า) โดยใช้printf:

printf 'New path: \e[1m%s\e[0m' "/pkg/bin:$PATH:"

สิ่งนี้แยกส่วนที่ชัดเจนอย่างชัดเจนเพื่อหลีกเลี่ยงอักขระและค่าข้อมูล

อีกอย่างคือรูปแบบการอ้างอิงทั้งหมดเหล่านี้สร้าง "word" คำเดียวในเชลล์เว้นแต่จะใช้ $@หรือมีการขยายอาร์เรย์${x[@]}ภายในเครื่องหมายคำพูดคู่ ทั้งแบบฟอร์มคำพูดเดี่ยวเป็นหนึ่งคำเสมอและไม่เคยขยายออกไปอีก


$"..."มาจาก ksh93, เพิ่มใน bash ใน 2.0
Stéphane Chazelas

มีไม่ได้ใน\cX zsh( \CXหรือ\C-Xมี\cความหมายพิเศษอยู่แล้วecho)
Stéphane Chazelas

'let x="'$PATH\"มีความผิดในรายการบริบทในเชลล์ที่นอกเหนือจากzshที่$PATHไม่ได้อ้างถึง (ดังนั้นจะต้องแยก + glob ซึ่งคุณไม่ต้องการที่นี่)
Stéphane Chazelas

คุณอาจต้องการชี้แจงว่าคุณกำลังพูดถึงเปลือกหอยเหมือน Korn การประมวลผลการเสนอราคาแตกต่างกันใน csh, rc, ปลา ...
Stéphane Chazelas

โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.