เหตุใดฉันจึงไม่สามารถไปที่เครื่องหมายตัวหนอน ('~') ได้?


32

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

cd ~
cd bin
cd ~/bin
cd 'bin'

แต่ไม่

cd '~'
cd '~/bin'

ฉันต้องไปcdยังเส้นทางไดเรกทอรีที่มีช่องว่างในหนึ่งในชื่อไดเรกทอรีดังนั้นฉันต้องการคำพูด (มันเป็น Windows Program Filesภายใต้ไวน์) ฉันสามารถแก้ไขได้ด้วยสองcdคำสั่ง แต่ทำไมฉันไม่สามารถใส่~เครื่องหมายคำพูดได้?

ถ้าฉันพิมพ์cd '~'(หรือcd "~") ฉันจะได้รับ:

bash: cd: ~: No such file or directory

29
ถามตัวคุณเองว่า: หากไม่ได้ผลคุณจะcdเข้าไปในไดเรคทอรีได้~อย่างไร?
Jörg W Mittag

2
ในฐานะที่เป็น sidenote หากคุณกำลังเขียนสคริปต์คุณควรใช้เส้นทางที่สมบูรณ์และหลีกเลี่ยงcdทั้งหมด ใช้ตัวแปรเพื่อจัดเก็บชื่อพา ธ ที่คุณไม่ต้องการพิมพ์หลายครั้งเช่นpf=~/.wine/drive_c/Program\ Files/; cp /path/to/file "$pf"
ของหวาน

8
@jamesqf: ทำไมระบบที่เหมาะสมจะเข้าใจดีกว่าฉันว่าฉันต้องการตั้งชื่อไฟล์และไดเรกทอรีของฉันอย่างไร นอกจากนี้ฉันไม่เคยเข้าใจว่าทำไม Unix จึงส่งสัญญาณเวทมนตร์แบบ in-band ของตัวแยกองค์ประกอบเส้นทางและตัวยุติเส้นทาง เกิดอะไรขึ้นกับไฟล์ / ไดเรกทอรีชื่อ/หรือNUL?
Jörg W Mittag

3
@ JörgWMittagน่าจะเป็นcd ./~
k_g

2
@jamesqf เพียงเพื่อให้ทราบว่าในอดีตระบบไฟล์ Unix อนุญาตให้ใช้ตัวอักษรตัวใดตัวหนึ่งในชื่อไฟล์ยกเว้น '/' (ตัวคั่นเส้นทาง) และ '\ 0' (NUL - ตัวคั่นสตริง -) เป็นบันทึก Jorg ไม่มีข้อ จำกัด อื่น ๆ มีการใช้งานระบบไฟล์ Unix จำนวนมากดังนั้นการแนะนำข้อ จำกัด ในหนึ่งในนั้นจะทำให้เสียความเข้ากันได้และเพิ่มความซับซ้อน - และถูกมองว่า "แปลก"! และการขยายตัว '~' ถูกนำมาใช้เปรียบเทียบใน csh และแพร่หลายใน bash, ไฟล์ / dirs ที่มีตัวอักษร '~' ในไม่เป็นที่รู้จัก (เช่น myfile ~ เป็นไฟล์สำรองสำหรับ myfile)
SusanW

คำตอบ:


78

ดังที่ @ karel ระบุไว้ในคำตอบของเขา~เป็นตัวละครพิเศษและขยายตัวโดย Bash ในไดเรกทอรีบ้านของผู้ใช้ปัจจุบัน ดูคู่มือของ Bash ใน "Tilde Expansion"หรือค้นหาหัวข้อ "Tilde Expansion" ในหน้า man ( man bash)

ใบเสนอราคาทุกชนิดรอบ ๆ ตัว~ป้องกันการขยายตัวหนอน


ในการตอบคำถามของคุณเกี่ยวกับวิธีที่คุณยังสามารถใช้มันcdในไดเรกทอรีที่มีช่องว่างในชื่อของมัน

  • ละเว้นเครื่องหมายคำพูดและยกเว้นช่องว่างด้วยแบ็กสแลชแทน:

    cd ~/foo/spaces\ are\ cool/bar
  • อ้างอิงส่วนที่เหลือของเส้นทาง แต่เว้นรอบตัวหนอนและเครื่องหมายทับแรก:

    cd ~/"foo/spaces are cool/bar"

    ตามที่คุณเห็นคุณสามารถเชื่อมต่อสตริงที่ยกมาและไม่ยกมาใน Bash เพียงแค่เขียนพวกเขาถัดจากแต่ละอื่น ๆ โดยไม่มีช่องว่างในระหว่าง

  • ใช้ตัวแปรสภาพแวดล้อม$HOMEแทนเครื่องหมายตัวหนอนซึ่งยังคงถูกขยายใน "เครื่องหมายคำพูดคู่" (แต่ไม่ใช่ 'เครื่องหมายคำพูดเดี่ยว'):

    cd "$HOME/foo/spaces are cool/bar"

3
@rexkogitans ~'/...'ไม่ทำงานและไม่ใช่สิ่งที่คำตอบนี้มี ~/'...'หรือ~/"..."จะทำงาน
hvd

tld; dr: เพราะนั่นคือไวยากรณ์ของเชลล์
Sergiy Kolodyazhnyy

@hvd ขอบคุณ แก้ไขข้อผิดพลาด นี่เป็นคำตอบที่สมบูรณ์ที่สุดและอธิบายถึงวิธีการแก้ไขสิ่งที่ OP ต้องการทำ ~/'path'เป็นวิธีที่จะไป
rexkogitans

1
@hvd ความอยากรู้เล็ก ๆ น้อย ๆ ทำไมไม่~'/...'ทำงาน? เครื่องหมายทับไม่ใช่อักขระพิเศษดังนั้นจึงควรใช้ทั้งในและนอกเครื่องหมายคำพูด
Kodos Johnson

6
@KodosJohnson ดูที่ส่วนของ Bash manpage เกี่ยวกับ "Tilde Expansion" ย่อหน้าที่เกี่ยวข้องซึ่งอ้างถึงในคำตอบของหวานด้านล่าง TL; DR: การขยายตัวของตัวหนอนจะเกิดขึ้นถ้าตัวอักษรตัวแรกในคำนั้นเป็นตัวหนอนที่ไม่ได้กล่าวถึงดังนั้นทุกอย่างระหว่างตัวหนอนตัวนั้นและตัวต่อที่ไม่ต้องยกถัดไปจะถือเป็น "ตัวหนอนตัวหนอน" หากคำนำหน้านี้ไม่ใช่สิ่งที่ถูกต้องเช่น +, -, ตัวเลขหรือชื่อผู้ใช้ (ไม่อนุญาตให้ใส่เครื่องหมายคำพูดในนั้น) การขยายตัวจะล้มเหลวและคุณจะได้ตัวอักษร ~
ผู้บัญชาการ Byte

17

~ เป็นอักขระพิเศษที่เชลล์ตีความเป็นไดเรกทอรีหลักของผู้ใช้ที่ล็อกอิน '~' ถูกตีความโดยเชลล์ในฐานะตัวอักษร ~ ตัวอักษรไม่ใช่เป็นไดเรกทอรีภายในบ้านของผู้ใช้เนื่องจากการล้อมรอบสตริงภายในอักขระเครื่องหมายคำพูดเดี่ยวสองตัวส่งผลให้สตริงนั้นถูกตีความเป็นสตริงข้อความตามตัวอักษร


~ไม่ใช่นามแฝงในความbashหมายตีความ: นามแฝงอนุญาตให้ใช้สตริงแทนคำได้เมื่อใช้เป็นคำแรกของคำสั่งแบบง่าย . ตามที่ฉันอธิบายในคำตอบของฉันด้านล่างมันเป็นการขยายตัว
ของหวาน

15

มันคือ bashคุณสมบัติที่เรียกว่าการขยายตัวหนอน อ้างถึงman bash:

หากคำขึ้นต้นด้วยอักขระเครื่องหมายตัวหนอนที่ไม่มีเครื่องหมาย (`~ ') อักขระทั้งหมดที่อยู่หน้าเครื่องหมายทับแรกที่ไม่ได้ใส่เครื่องหมายอัญประกาศ (หรือตัวอักษรทั้งหมดหากไม่มีเครื่องหมายทับ) จะถือว่าเป็นคำนำหน้าตัวหนอน หากไม่มีการอ้างถึงอักขระในเครื่องหมายคำนำหน้าตัวหนอนตัวอักษรในเครื่องหมายคำนำหน้าตัวหนอนหลังตัวหนอนจะถือว่าเป็นชื่อล็อกอินที่เป็นไปได้ หากชื่อล็อกอินนี้คือสตริง null ตัวหนอนจะถูกแทนที่ด้วยค่าของพารามิเตอร์เชลล์ HOME หาก HOME ไม่ได้ตั้งค่าโฮมไดเรกทอรีของผู้ใช้ที่ดำเนินการเชลล์จะถูกแทนที่แทน

สำหรับการขยายเพื่อให้ทำงานอักขระ tilde ~จำเป็นต้องถูกยกเลิกการอ้างอิงอักขระอื่นจะถูกนำมาใช้อย่างแท้จริงและcdล้มเหลวหากไม่มีไดเรกทอรีชื่อ~อยู่ในไดเรกทอรีปัจจุบัน ดูคำตอบ entensive นี้bashสำหรับคำอธิบายข้อความใน หากคุณต้องการอ้างถึงส่วนหนึ่งของเส้นทางคุณสามารถ:

  1. พูดอย่างน้อยตัวละครที่ต้องมีการอ้างอิงด้วยคำพูดเดียวเช่น

    ~/dir' 'with' 'spaces/

    หรือ

    ~/'dir with spaces/'
  2. อ้างอย่างน้อยตัวละครที่ต้องมีการอ้างอิงด้วยเครื่องหมายคำพูดคู่เช่น

    ~/dir" "with" "spaces/

    หรือ

    ~/"dir with spaces/"
  3. พูดเฉพาะอักขระที่จำเป็นต้องมีเครื่องหมายคำพูดด้วยแบ็กสแลชเช่น

    ~/dir\ with\ spaces/

Tilde Expansion มีคุณสมบัติที่น่าสนใจเช่น:

  • ~+ ขยายเป็นค่าของ PWDเช่นไดเรกทอรีการทำงานปัจจุบัน
  • ~- ขยายเป็นค่าของ OLDPWDเช่นไดเรกทอรีทำงานก่อนหน้า
  • ~john ขยายไปยังโฮมไดเร็กตอรี่ที่เชื่อมโยงกับชื่อล็อกอิน“ john”

บังเอิญมันก็โอเคที่จะ 'overquote' ด้วยแบ็กสแลชเช่นกัน เช่น$ touch a; cd \a. (ฉันคิดว่านี่อาจมีปัญหาcd \nแต่การทดลองอย่างน้อยในเวอร์ชันที่bashแนะนำของฉันมันใช้งานได้ดี)
LSpice

1

สำรวจโดยใช้echoคำสั่ง

วิธีที่ง่ายที่สุดในการสำรวจว่าสิ่งต่าง ๆ ทำงานอย่างไรในการทุบตีคือการใช้echoคำสั่ง ในกรณีที่~ใช้สิ่งนี้:

$ echo ~
/home/rick
$ echo '~'
~
$ echo "~"
~
$ echo `~`
bash: /home/rick: Is a directory

อย่างที่คุณเห็นเมื่อคุณอ้างคำพูดเดี่ยวหรือใช้เครื่องหมายคำพูดคู่ล้อมรอบ~มันจะตีความตามตัวอักษรว่าเป็นสตริงและไม่ขยายเป็นตัวแปร เมื่อคุณใช้ backticks (`) มันจะถูกดำเนินการเป็นคำสั่งและสร้างข้อความแสดงข้อผิดพลาด

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