Patrice ระบุที่มาของปัญหาในคำตอบของเขาแต่ถ้าคุณต้องการทราบวิธีการได้รับจากที่นั่นกับสาเหตุที่คุณได้รับนั่นคือเรื่องราวที่ยาวนาน
ไดเรกทอรีทำงานปัจจุบันของกระบวนการคือสิ่งที่คุณคิดว่าซับซ้อนเกินไป มันเป็นคุณสมบัติของกระบวนการซึ่งเป็นที่จับไปยังไฟล์ของไดเรกทอรีประเภทที่เส้นทางสัมพัทธ์ (ในการเรียกระบบโดยกระบวนการ) เริ่มต้นจาก เมื่อแก้ไขพา ธ สัมพัทธ์เคอร์เนลไม่จำเป็นต้องรู้ว่า (ก) พา ธ เต็มไปยังไดเรกทอรีปัจจุบันนั้นเพียงแค่อ่านรายการไดเรกทอรีในไฟล์ไดเรกทอรีนั้นเพื่อค้นหาองค์ประกอบแรกของเส้นทางสัมพัทธ์ (และ..เหมือนกับที่อื่น ๆ ยื่นเรื่องนั้น) และดำเนินการต่อจากที่นั่น
ตอนนี้ในฐานะผู้ใช้บางครั้งคุณอยากรู้ว่าไดเรกทอรีนั้นอยู่ที่ใดในโครงสร้างไดเรกทอรี ด้วย Unices ส่วนใหญ่แผนผังไดเรกทอรีจะเป็นแผนผังโดยไม่มีลูป นั่นคือมีเพียงเส้นทางเดียวจากรากของต้นไม้ ( /) ไปยังไฟล์ที่กำหนด เส้นทางนั้นโดยทั่วไปเรียกว่าเส้นทางแบบบัญญัติ
เพื่อให้ได้เส้นทางของไดเรกทอรีการทำงานปัจจุบันสิ่งที่กระบวนการที่มีการทำคือเพียงแค่เดินขึ้น (ดีลงถ้าคุณต้องการที่จะเห็นต้นไม้ที่มีรากที่ด้านล่าง) ต้นไม้กลับไปที่รากหาชื่อของโหนด ระหว่างทาง
ตัวอย่างเช่นกระบวนการที่พยายามค้นหาว่าไดเรกทอรีปัจจุบันคือ/a/b/cจะเปิด..ไดเรกทอรี (เส้นทางสัมพัทธ์ดังนั้นจึง..เป็นรายการในไดเรกทอรีปัจจุบัน) และค้นหาไฟล์ของไดเรกทอรีประเภทที่มีหมายเลข inode เดียวกัน.พบว่าcแมตช์ที่แล้วเปิด../..ไปเรื่อย ๆ /จนกว่าจะพบ ไม่มีความกำกวมอยู่ที่นั่น
นั่นคือสิ่งที่ฟังก์ชั่นgetwd()หรือgetcwd()C ทำหรืออย่างน้อยก็เคยทำ
ในบางระบบเช่น Linux รุ่นใหม่มีการเรียกระบบเพื่อส่งเส้นทาง canonical ไปยังไดเรกทอรีปัจจุบันซึ่งทำการค้นหาในพื้นที่เคอร์เนล (และอนุญาตให้คุณค้นหาไดเรกทอรีปัจจุบันของคุณแม้ว่าคุณจะไม่ได้อ่านการเข้าถึงส่วนประกอบทั้งหมดของมัน) และนั่นคือสิ่งที่getcwd()เรียกว่า บนลินุกซ์ที่ทันสมัยนอกจากนี้คุณยังสามารถหาเส้นทางไปยังไดเรกทอรีปัจจุบันผ่าน readlink (ที่) /proc/self/cwdบน
นั่นคือสิ่งที่ภาษาและเปลือกต้นส่วนใหญ่ทำเมื่อส่งคืนพา ธ ไปยังไดเรกทอรีปัจจุบัน
ในกรณีของคุณคุณสามารถโทรหาcd aที่อาจครั้งตามที่คุณต้องการเพราะมันเป็น symlink ไป.ที่ไดเรกทอรีปัจจุบันไม่เปลี่ยนแปลงดังนั้นทั้งหมดgetcwd(), pwd -P, python -c 'import os; print os.getcwd()', จะกลับมาของคุณperl -MPOSIX -le 'print getcwd'${HOME}
ตอนนี้การเชื่อมโยงระบบเชื่อมโยงกันซับซ้อนขึ้น
symlinksอนุญาตให้ข้ามในไดเรกทอรีต้นไม้ ใน/a/b/cถ้า/aหรือ/a/bหรือ/a/b/cเป็น symlink แล้วเส้นทางบัญญัติของ/a/b/cจะเป็นสิ่งที่แตกต่างอย่างสิ้นเชิง โดยเฉพาะอย่างยิ่ง..ในรายการไม่จำเป็นต้องเป็น/a/b/c/a/b
ในเชลล์เป้าหมายถ้าคุณทำ:
cd /a/b/c
cd ..
หรือแม้กระทั่ง:
cd /a/b/c/..
/a/bมีการรับประกันคุณจะจบลงในไม่ได้
เหมือนกับ:
vi /a/b/c/../d
ไม่จำเป็นต้องเหมือนกับ:
vi /a/b/d
kshแนะนำแนวคิดของไดเร็กตอรี่ปัจจุบันที่ใช้ในการทำงานเพื่อแก้ไขสิ่งนั้น. ผู้คนเคยชินกับมันและ POSIX ก็จบลงด้วยการระบุพฤติกรรมซึ่งหมายความว่าเชลล์ส่วนใหญ่ทุกวันนี้ก็ทำได้เช่นกัน:
สำหรับคำสั่งcdและpwdbuiltin ( และสำหรับคำสั่งเหล่านั้นเท่านั้น (แม้ว่าจะใช้กับpopd/ pushdบนเชลล์ที่มี)) เชลล์จะเก็บรักษาแนวคิดของตนเองเกี่ยวกับไดเร็กทอรีการทำงานปัจจุบัน มันถูกเก็บไว้ใน$PWDตัวแปรพิเศษ
เมื่อคุณทำ:
cd c/d
แม้ว่าcหรือc/dมี symlinks ขณะ$PWDcontaines /a/bมันผนวกc/dไปยังจุดสิ้นสุดเพื่อให้กลายเป็น$PWD /a/b/c/dและเมื่อคุณ:
cd ../e
แทนการทำก็ไม่chdir("../e")chdir("/a/b/c/e")
และpwdคำสั่งจะส่งคืนเนื้อหาของ$PWDตัวแปรเท่านั้น
สิ่งนี้มีประโยชน์ในเชลล์แบบโต้ตอบเนื่องจากpwdเอาต์พุตเส้นทางไปยังไดเร็กทอรีปัจจุบันที่ให้ข้อมูลว่าคุณไปถึงที่นั่นได้อย่างไรและตราบใดที่คุณใช้เฉพาะ..ในอาร์กิวเมนต์เพื่อcdและไม่ใช่คำสั่งอื่น ๆ มีโอกาสน้อยที่จะทำให้คุณประหลาดใจเพราะcd a; cd ..หรือcd a/..โดยทั่วไปแล้ว ไปยังที่ที่คุณอยู่
ตอนนี้ไม่ได้แก้ไขจนกว่าคุณจะทำ$PWD cdจนกว่าจะถึงครั้งต่อไปที่คุณโทรcdหรือpwdอาจมีสิ่งต่าง ๆ เกิดขึ้นมากมายส่วนประกอบของ$PWDสามารถเปลี่ยนชื่อได้ ไดเรกทอรีปัจจุบันจะไม่เปลี่ยนแปลง (เป็น inode เดียวกันเสมอแม้ว่าจะสามารถลบได้) แต่เส้นทางในไดเรกทอรีต้นไม้อาจเปลี่ยนแปลงได้อย่างสมบูรณ์ getcwd()คำนวณไดเรกทอรีปัจจุบันทุกครั้งที่เรียกใช้โดยการเดินทรีไดเรกทอรีเพื่อให้ข้อมูลมีความถูกต้องอยู่เสมอ แต่สำหรับโลจิคัลไดเร็กทอรีที่นำมาใช้โดยเชลล์ POSIX ข้อมูลใน$PWDอาจไม่เสถียร ดังนั้นเมื่อวิ่งcdหรือpwdกระสุนบางนัดอาจต้องการป้องกันสิ่งนั้น
ในตัวอย่างนั้นคุณจะเห็นพฤติกรรมที่แตกต่างกับกระสุนที่แตกต่างกัน
บางคนชอบksh93เพิกเฉยปัญหาทั้งหมดดังนั้นจะส่งคืนข้อมูลที่ไม่ถูกต้องแม้หลังจากที่คุณโทรcd (และคุณจะไม่เห็นพฤติกรรมที่คุณเห็นด้วยbash)
บางคนชอบbashหรือzshไม่ตรวจสอบว่า$PWDยังคงเป็นเส้นทางไปยังไดเรกทอรีปัจจุบันเมื่อแต่ไม่เมื่อcdpwd
pdksh ตรวจสอบทั้งpwdและcd(แต่pwdไม่อัปเดต$PWD)
ash(อย่างน้อยหนึ่งที่พบใน Debian) ไม่ได้ตรวจสอบและเมื่อคุณทำcd aมันจริง ๆ แล้วcd "$PWD/a"ดังนั้นหากไดเรกทอรีปัจจุบันมีการเปลี่ยนแปลงและ$PWDไม่ชี้ไปที่ไดเรกทอรีปัจจุบันจริง ๆ แล้วจะไม่เปลี่ยนเป็นaไดเรกทอรีในไดเรกทอรีปัจจุบัน แต่มีหนึ่งใน$PWD(และส่งคืนข้อผิดพลาดหากไม่มีอยู่)
หากคุณต้องการเล่นกับมันคุณสามารถทำได้:
cd
mkdir -p a/b
cd a
pwd
mv ~/a ~/b
pwd
echo "$PWD"
cd b
pwd; echo "$PWD"; pwd -P # (and notice the bug in ksh93)
ในเปลือกหอยต่างๆ
ในกรณีของคุณเนื่องจากคุณกำลังใช้bashหลังจากที่cd a, bashการตรวจสอบว่า$PWDยังคงชี้ไปที่ไดเรกทอรีปัจจุบัน ในการทำเช่นนั้นมันจะเรียกstat()ค่าของ$PWDการตรวจสอบหมายเลขไอโหนดและเปรียบเทียบกับของ.การตรวจสอบหมายเลขไอโหนดและเปรียบเทียบกับที่ของ
แต่เมื่อค้นหา$PWDเส้นทางที่เกี่ยวข้องกับการแก้ไข symlink มากเกินไปที่stat()กลับมาพร้อมกับข้อผิดพลาดดังนั้นเชลล์ไม่สามารถตรวจสอบว่า$PWDยังสอดคล้องกับไดเรกทอรีปัจจุบันดังนั้นจึงคำนวณมันอีกครั้งด้วยgetcwd()และการปรับปรุง$PWDตาม
ตอนนี้เพื่อชี้แจงคำตอบของ Patrice การตรวจสอบจำนวน symlink ที่พบในขณะที่ค้นหาเส้นทางคือการป้องกันลูป symlink การวนซ้ำที่ง่ายที่สุดสามารถทำได้ด้วย
rm -f a b
ln -s a b
ln -s b a
หากไม่มีพนักงานรักษาความปลอดภัยนั้นcd a/xระบบจะต้องค้นหาตำแหน่งที่aเชื่อมโยงไปหาbและเป็น symlink ที่เชื่อมโยงไปยังaและมันจะดำเนินต่อไปเรื่อย ๆ วิธีที่ง่ายที่สุดในการป้องกันคือการยอมแพ้หลังจากการแก้ไขมากกว่าจำนวน symlink ที่กำหนดเอง
ตอนนี้กลับไปยังไดเรกทอรีการทำงานแบบลอจิคัลปัจจุบันและทำไมคุณลักษณะไม่ดีนัก สิ่งสำคัญคือต้องตระหนักว่ามันมีไว้สำหรับcdเชลล์เท่านั้นและไม่ใช่คำสั่งอื่น ๆ
ตัวอย่างเช่น
cd -- "$dir" && vi -- "$file"
ไม่เหมือนกับ:
vi -- "$dir/$file"
นั่นเป็นเหตุผลที่บางครั้งคุณจะพบว่าผู้คนแนะนำให้ใช้cd -Pในสคริปต์เสมอเพื่อหลีกเลี่ยงความสับสน (คุณไม่ต้องการให้ซอฟต์แวร์ของคุณจัดการกับข้อโต้แย้งที่../xแตกต่างจากคำสั่งอื่น ๆ เพียงเพราะเขียนในเชลล์แทนภาษาอื่น)
-Pตัวเลือกคือการปิดการใช้งานไดเรกทอรีตรรกะจัดการเพื่อให้cd -P -- "$var"จริงไม่เรียกchdir()กับเนื้อหาของ$var(ยกเว้นเมื่อ$varเป็น-แต่ที่เรื่องอื่น) และหลังจากcd -Pนั้น$PWDจะมีเส้นทางแบบบัญญัติ