อะไรคือความแตกต่างระหว่าง echo `date ', echo“` date'” และ echo '' date ''?


23

ความแตกต่างระหว่างสามคำสั่งเหล่านี้คืออะไร?

echo `date`
echo "`date`"
echo '`date`'

ฉันสับสนในความแตกต่างจริง ๆ ฉันคิดว่าเมื่อ 'อยู่ใกล้ก็หมายความว่ามันเป็นสตริงดังนั้นเสียงก้องจะออกสตริงdateแทนที่จะแสดงวันที่?

คำตอบ:


19

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

ใน"` date` "เครื่องหมายคำพูดคู่เป็นเครื่องหมายคำพูดที่อ่อนแอดังนั้นพวกเขาจะขยายตัวแปร (ลอง" $ PWD ") และดำเนินการทดแทนคำสั่ง ผลลัพธ์ของการขยายจะถูกส่งผ่านเป็นอาร์กิวเมนต์เดียวไปยังechoคำสั่งโดยมีการเว้นวรรคติดต่อกัน: นั่นคือการแยกคำไม่ได้ดำเนินการ

ใน'`date' 'เครื่องหมายคำพูดเดี่ยวเป็นเครื่องหมายคำพูดที่แข็งแกร่งดังนั้นพวกเขาจะไม่อนุญาตให้มีการขยายตัวของตัวแปรหรือการทดแทนคำสั่งภายในพวกเขา

อ้างถึงลิงค์นี้สำหรับคำอธิบายเพิ่มเติม

แก้ไขจุดเป็นครั้งแรกที่ชี้ให้เห็นอย่างถูกต้องโดยไมเคิล Suelmann ในความคิดเห็นด้านล่าง


1
อักขระ `ที่เรียกว่าวันที่โดยรอบคืออะไร? หากฉันเข้าใจอย่างถูกต้องอักขระเมตาจะไม่ทำงานในการเสนอราคาเดียว?
จอห์น

หากฉันเข้าใจอย่างถูกต้องอักขระเมตาจะไม่ทำงานในการเสนอราคาเดียว?
จอห์น

8
`มักจะถูกเรียกว่า" backtick "ในสถานการณ์นั้นและเอกสาร / หนังสือ Unix ต่างๆ มันไม่ได้ถูกใช้เป็นสำเนียง Unicode เมื่อมันเป็นของตัวเองแม้ว่ามันจะเป็นชื่อของสัญลักษณ์ก็ตาม และคุณก็ถูกต้องว่าจะไม่มีการขยายตัวของเมตา / ตัวอักษรนิพจน์หากคุณล้อมด้วยเครื่องหมายคำพูดเดี่ยว
Jim Stewart

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

1
@BonsiScott ช่องว่างพิเศษระหว่าง "พ.ย. " และ "1" จะถูกลบใน HTML เช่นกัน)
Izkata

16

ทั้งสอง

echo `date`

และ

echo "`date`"

จะแสดงวันที่ เอาต์พุตจากหลังดูเหมือนว่าเอาต์พุตจากการรันdateด้วยตัวเอง

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

นี่คือตัวอย่างของความแตกต่างที่ลึกซึ้ง:

echo `date`

ผลิต:

Fri Nov 1 01:48:45 EST 2013

แต่:

echo "`date`"

ผลิต:

Fri Nov  1 01:48:49 EST 2013

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

สิ่งนี้มีความสำคัญมากกว่าในคำสั่งอื่นที่ไม่ใช่เสียงสะท้อน ตัวอย่างเช่นลองจินตนาการถึงคำสั่งfooที่ต้องการอาร์กิวเมนต์สองตัวคือวันที่และที่อยู่อีเมล

สิ่งนี้จะทำงานในสถานการณ์นั้น:

foo "`date`" joeuser@example.com

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

foo `date` joeuser@example.com

3
คุณขัดแย้งกับตนเองในประโยคแรกของคุณ แบบฟอร์มที่หนึ่งและที่สองจะไม่ส่งออกสิ่งเดียวกันกับที่คุณแสดงในภายหลัง
jlliagre

ขอบคุณ ฉันเปลี่ยนถ้อยคำให้ชัดเจนขึ้น
Jim Stewart

3

ใน POSIX shells `date`เป็นรูปแบบการทดแทนคำสั่งโบราณ $(date)ไวยากรณ์ที่ทันสมัย

ในทั้งสองกรณีพวกเขาขยายไปยังเอาต์พุตของdateด้วยอักขระขึ้นบรรทัดใหม่ที่ต่อท้ายที่ถูกปล้น (โดยที่เอาต์พุตนั้นไม่มีอักขระ NUL)

อย่างไรก็ตามเมื่อไม่อยู่ในเครื่องหมายคำพูดคู่และในบริบทรายการ (ตัวอย่างเช่นในการขัดแย้งกับคำสั่งง่าย ๆ เช่นechoในกรณีของคุณ) การขยายตัวนั้นขึ้นอยู่กับ:

  1. แยก Word ที่นั่นคือ"การส่งออกของdateด้วยตัวอักษรขึ้นบรรทัดใหม่ปล้น"คือแยกตามมูลค่าปัจจุบันของ$IFSตัวแปร (โดยเริ่มต้นที่มีพื้นที่แท็บและการขึ้นบรรทัดใหม่ (และ NUL ด้วยzsh)) เป็นหลายคำ

    ตัวอย่างเช่นถ้าdateเอาท์พุทFri 1 Nov 14:11:15 GMT 2013\n(เหมือนมันมักจะอยู่ในสถานที่ภาษาอังกฤษและในแผ่นดินใหญ่เขตเวลาอังกฤษ) และ$IFSในปัจจุบันมี:ที่จะแยกออกเป็น 3 คำ : Fri 1 Nov 14, และ1115 GMT 2013

  2. ชื่อแฟ้มรุ่น (aka globbing ) (ยกเว้นด้วยzsh) นั่นคือแต่ละคำที่เกิดจากการแยกข้างต้นมองหาอักขระตัวแทน ( *, ?, [...]แม้ว่าเปลือกหอยบางคนมีมากขึ้น) และขยายไปยังรายการของชื่อไฟล์ที่ตรงกับรูปแบบเหล่านั้น ตัวอย่างเช่นหากการส่งออกของdateเป็น?%? 33 */*/* UVC 3432(เหมือนมันมักจะอยู่ในสถานที่ศุกร์และ UVC เขต) และ$IFSเป็นค่าเริ่มต้น) แล้วที่จะขยายไปยังทุกที่ไม่ใช่ที่ซ่อนอยู่ 3 ชื่อไฟล์ตัวอักษรในไดเรกทอรีปัจจุบันที่มีตัวอักษรกลาง%, 33, ทุกไฟล์ที่ไม่ใช่ที่ซ่อนอยู่ในทุกไดเรกทอรีย่อยที่ไม่ใช่ที่ซ่อนอยู่ของทุกไดเรกทอรีย่อยที่ไม่ใช่ซ่อนของไดเรกทอรีปัจจุบันและUVC3432

นั่นคือเหตุผล:

  1. คุณควรอ้างอิง (ด้วยเครื่องหมายอัญประกาศคู่) แทนคำสั่งเว้นแต่ว่าคุณต้องการแยกคำหรือสร้างชื่อไฟล์ตามที่มีการขยาย
  2. หากคุณต้องการแยกคำคุณควรตั้ง$IFSเป็นอักขระที่คุณต้องการแยก
  3. หากคุณต้องการแยกคำแต่ไม่สร้างชื่อไฟล์คุณต้องออก a set +fเพื่อปิดการใช้งาน

อัญประกาศเดียวอ้างทุกอย่างดังนั้นทำให้อักขระ backtick ถูกถ่ายอย่างแท้จริง

ตัวอย่าง (การใช้-xทำให้ง่ายต่อการดูว่าเกิดอะไรขึ้น):

$ bash --norc -x
bash-4.2$ IFS=:
+ IFS=:
bash-4.2$ echo `date`
++ date
+ echo 'Fri  1 Nov 14' 42 '33 GMT 2013'
Fri  1 Nov 14 42 33 GMT 2013
bash-4.2$ echo "`date`"
++ date
+ echo 'Fri  1 Nov 14:42:41 GMT 2013'
Fri  1 Nov 14:42:41 GMT 2013

bash-4.2$ cd /lib/modules
+ cd /lib/modules
bash-4.2$ export TZ=UVC LC_ALL=vs_VS
+ export TZ=UVC LC_ALL=vs_VS
+ TZ=UVC
+ LC_ALL=vs_VS
bash-4.2$ unset -v IFS     # get the default behaviour
+ unset -v IFS
bash-4.2$ echo `date`
++ date
+ echo '?%?' 33 3.10-2-amd64/build/arch 3.10-2-amd64/build/include 3.10-2-amd64/build/Makefile 3.10-2-amd64/build/Module.symvers 3.10-2-amd64/build/scripts 3.10-2-amd64/kernel/arch 3.10-2-amd64/kernel/crypto 3.10-2-amd64/kernel/drivers 3.10-2-amd64/kernel/fs 3.10-2-amd64/kernel/lib 3.10-2-amd64/kernel/mm 3.10-2-amd64/kernel/net 3.10-2-amd64/kernel/sound 3.10-2-amd64/source/arch 3.10-2-amd64/source/include 3.10-2-amd64/source/Makefile 3.10-2-amd64/source/scripts 3.10-2-amd64/updates/dkms 3.10-3-amd64/build/arch 3.10-3-amd64/build/include 3.10-3-amd64/build/Makefile 3.10-3-amd64/build/Module.symvers 3.10-3-amd64/build/scripts 3.10-3-amd64/kernel/arch 3.10-3-amd64/kernel/crypto 3.10-3-amd64/kernel/drivers 3.10-3-amd64/kernel/fs 3.10-3-amd64/kernel/lib 3.10-3-amd64/kernel/mm 3.10-3-amd64/kernel/net 3.10-3-amd64/kernel/sound 3.10-3-amd64/source/arch 3.10-3-amd64/source/include 3.10-3-amd64/source/Makefile 3.10-3-amd64/source/scripts 3.10-3-amd64/updates/dkms UVC 3432
?%? 33 3.10-2-amd64/build/arch 3.10-2-amd64/build/include 3.10-2-amd64/build/Makefile 3.10-2-amd64/build/Module.symvers 3.10-2-amd64/build/scripts 3.10-2-amd64/kernel/arch 3.10-2-amd64/kernel/crypto 3.10-2-amd64/kernel/drivers 3.10-2-amd64/kernel/fs 3.10-2-amd64/kernel/lib 3.10-2-amd64/kernel/mm 3.10-2-amd64/kernel/net 3.10-2-amd64/kernel/sound 3.10-2-amd64/source/arch 3.10-2-amd64/source/include 3.10-2-amd64/source/Makefile 3.10-2-amd64/source/scripts 3.10-2-amd64/updates/dkms 3.10-3-amd64/build/arch 3.10-3-amd64/build/include 3.10-3-amd64/build/Makefile 3.10-3-amd64/build/Module.symvers 3.10-3-amd64/build/scripts 3.10-3-amd64/kernel/arch 3.10-3-amd64/kernel/crypto 3.10-3-amd64/kernel/drivers 3.10-3-amd64/kernel/fs 3.10-3-amd64/kernel/lib 3.10-3-amd64/kernel/mm 3.10-3-amd64/kernel/net 3.10-3-amd64/kernel/sound 3.10-3-amd64/source/arch 3.10-3-amd64/source/include 3.10-3-amd64/source/Makefile 3.10-3-amd64/source/scripts 3.10-3-amd64/updates/dkms UVC 3432
bash-4.2$ echo "`date`"
++ date
+ echo '?%? 33 */*/* UVC 3432'
?%? 33 */*/* UVC 3432

หากเอาต์พุตมีอักขระ NUL พฤติกรรมจะแตกต่างกันไปจากเชลล์หนึ่งไปยังเชลล์: บางส่วนถูกเอาออกบางส่วนจะตัดทอนผลลัพธ์ที่อักขระ NUL ตัวแรกzshรักษาไว้ แต่โปรดทราบว่าคำสั่งภายนอกไม่สามารถรับอาร์กิวเมนต์ที่มี NUL ได้


ไม่มีสิ่งเช่น "POSIX shell" ที่แท้จริง มีเชลล์ที่สามารถเป็นไปตามมาตรฐาน POSIX ต่างๆที่เกี่ยวข้องโดยใช้ชุดย่อยที่ จำกัด ของการทำงาน
fpmurphy

0

ด้วย `date 'คุณจะได้รับผลลัพธ์ของการแยกวันที่เป็นหลายคำเนื่องจากการแยกคำเสร็จหลังจากการแทนที่คำสั่ง

ด้วย "` date` "คุณจะได้ผลลัพธ์จาก date เป็นหนึ่งคำ / พารามิเตอร์เนื่องจากมีการทดแทนคำสั่งระหว่างเครื่องหมายคำพูดคู่ แต่เอาต์พุตไม่ได้ถูกวิเคราะห์คำเพิ่มเติม เช่นเดียวกับการขยายตัวแปรเช่น "$ i" ในตัวอย่างด้านล่าง

ด้วย '' date '' คุณจะได้รับ `date 'ตามตัวอักษรเนื่องจากไม่มีการทดแทนคำสั่งระหว่างอัญประกาศเดี่ยว

บางทีความแตกต่างของทั้ง 3 แบบนี้จะปรากฏให้เห็นได้มากกว่านี้:

> for i in `date`; do echo "$i"; done
Fr
1.
Nov
12:25:30
CET
2013

> for i in "`date`"; do echo "$i"; done
Fr 1. Nov 12:25:38 CET 2013

> for i in '`date`'; do echo "$i"; done
`date`
โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.