ทำไม cd ไม่ใช่โปรแกรม?


128

ฉันสงสัยอยู่เสมอว่าทำไมcdไม่ใช่โปรแกรม แต่ไม่สามารถหาคำตอบได้

ใครรู้ว่าทำไมเป็นกรณีนี้



1
ฉันจำได้ว่าอ่าน (ฉันหาไม่พบ) ว่าcdคำสั่งunix ดั้งเดิมเป็นโปรแกรมแยกต่างหาก เชลล์จัดการมันเป็นพิเศษโดยที่มันไม่ได้forkเป็นเช่นexecนั้น และเมื่อcdเสร็จแล้วก็จะshดำเนินการ ฉันไม่รู้ว่านี่เป็นเรื่องจริงหรือไม่
camh

ประเด็นคืออะไร? ถ้ามันจะเพิ่มการจัดการพิเศษมันก็อาจจะเรียกchdirsyscall แหล่งที่มา: v1 v5 v7 (รุ่นแรกที่มีเชลล์เป้าหมาย)
มิเคล

2
@camh มันเป็นเรื่องจริง ฉันได้อ่านแล้วในบทความที่เขียนโดย Dennis M. Ritchie, "วิวัฒนาการของระบบการแบ่งปันเวลา Unix", AT&T Bell Laboratories วารสารเทคนิค 63 (6), ส่วนที่ 2, ตุลาคม 2527
jlliagre

@ Mikel: ฉันเห็นว่ามันไร้ประโยชน์ แต่ฉันก็แค่ถ่ายทอดเรื่องราวเกี่ยวกับcdสิ่งที่ฉันได้อ่าน ฉันผิดอย่างชัดเจนเกี่ยวกับแง่มุมของมันตอนนี้ @jlliagre ได้กรอกรายละเอียดแล้ว
camh

คำตอบ:


171

cdคำสั่งปรับเปลี่ยน "ไดเรกทอรีการทำงานปัจจุบัน" ใช่มั้ย?

"ไดเรกทอรีการทำงานปัจจุบัน" เป็นคุณสมบัติที่ไม่ซ้ำกันในแต่ละกระบวนการ

ดังนั้นถ้าcdเป็นโปรแกรมมันจะทำงานเช่นนี้:

  1. cd foo
  2. cdกระบวนการเริ่มต้น
  3. cdกระบวนการเปลี่ยนแปลงไดเรกทอรีสำหรับกระบวนการซีดี
  4. cdออกจากกระบวนการ
  5. เชลล์ของคุณยังคงมีสถานะเหมือนเดิมรวมถึงไดเร็กตอรี่ปัจจุบันที่ทำงานก่อนที่คุณจะเริ่มต้น

8
ห้าขั้นตอนของคุณถูกต้อง แต่ "ถ้าcdเป็นโปรแกรมมันจะทำงานเช่นนี้" ควรจะ "เมื่อcdใช้ในการใช้งานโปรแกรมภายนอกมันจะทำงานเช่นนี้"
jlliagre

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

108

cdนอกจากจะเป็น shell builtin แล้วจริงๆแล้วก็เป็นโปรแกรมบนระบบปฏิบัติการที่รองรับ POSIX พวกเขาจะต้องให้อิสระ executables cdสาธารณูปโภคปกติเช่น นี่คือตัวอย่างเช่นกรณีที่มีSolaris , AIX , HP-UX และOS X

เห็นได้ชัดว่า builtin cdยังคงมีผลบังคับใช้เนื่องจากการใช้งานภายนอกไม่เปลี่ยนแปลงไดเรกทอรีเชลล์ปัจจุบัน อย่างไรก็ตามหลังยังคงมีประโยชน์ นี่คือตัวอย่างที่แสดงให้เห็นว่า POSIX มองเห็นวิธีการใช้cdคำสั่งนี้ได้อย่างไร:

find . -type d -exec cd {} \;

ในระบบ POSIX oneliner นี้จะรายงานข้อผิดพลาดสำหรับไดเรกทอรีทั้งหมดที่คุณไม่ได้รับอนุญาตcdในการแจกจ่าย Gnu / Linux ส่วนใหญ่จะล้มเหลวพร้อมกับข้อความแสดงข้อผิดพลาดว่า:

find: `cd': No such file or directory

และนี่คือคำตอบสำหรับคำถามของคุณ " เหตุใดซีดีจึงไม่ใช่โปรแกรม " โดยหนึ่งในผู้เขียนร่วม Unix ดั้งเดิม ในการดำเนินการ Unix ต้นcd(สะกดคำchdirในเวลานั้น) เป็นโปรแกรมภายนอก มันเพิ่งหยุดทำงานโดยไม่คาดคิดหลังจากforkมีการใช้งานครั้งแรก

การอ้างอิงเดนนิสริตชี่ :

ท่ามกลางความปีติยินดีของเราพบว่าคำสั่ง chdir (เปลี่ยนไดเรกทอรีปัจจุบัน) หยุดทำงาน มีการอ่านรหัสมากและวิปัสสนากังวลเกี่ยวกับวิธีการเพิ่มของส้อมอาจทำให้สาย chdir แตกได้ ในที่สุดความจริงก็เริ่มขึ้น: ในระบบเก่า chdir เป็นคำสั่งธรรมดา; ปรับไดเรกทอรีปัจจุบันของกระบวนการ (เฉพาะ) ที่แนบกับเทอร์มินัล ภายใต้ระบบใหม่คำสั่ง chdir เปลี่ยนไดเรกทอรีปัจจุบันของกระบวนการที่สร้างขึ้นเพื่อดำเนินการอย่างถูกต้อง แต่กระบวนการนี้สิ้นสุดลงทันทีและไม่มีผลใด ๆ บนเปลือกหลักของมัน! มันจำเป็นที่จะต้องทำให้ chdir เป็นคำสั่งพิเศษ, ดำเนินการภายในเชลล์ ปรากฎว่าฟังก์ชั่นคล้ายคำสั่งหลายอย่างมีคุณสมบัติเหมือนกันตัวอย่างเช่นการเข้าสู่ระบบ

ที่มา: Dennis M. Ritchie,“ วิวัฒนาการของระบบการแบ่งปันเวลา Unix ”, AT&T Bell Laboratories วารสารเทคนิค 63 (6), ส่วนที่ 2, ตุลาคม 2527, pp.1577-93

สถานะหน้าคู่มือ chdir ของ Unix รุ่น 1 (มีนาคม 1971) :

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


10
... ดังนั้นเห็นได้ชัดว่า POSIX ได้รับคำสั่งว่าจะต้องมีการcdปฏิบัติการที่เป็นอิสระแต่มันจะไม่ทำอะไร (ยกเว้นอาจปล่อยข้อความผิดพลาดถ้าเรียกว่ามีข้อโต้แย้งที่ผิด) แปลก.
Ilmari Karonen

4
โอ้ถ้าเป็นจริงมันคงไม่ใช่สิ่งที่โง่ที่สุดใน POSIX
Kaz

5
หน้า cd POSIXยังกล่าวว่า "นับตั้งแต่ cd ส่งผลกระทบต่อสภาพแวดล้อมในการดำเนินเปลือกปัจจุบันก็มีให้เสมอเป็นเปลือกปกติในตัว."
มิเคล

6
@Kaz พวกเขาไม่ได้ต่างอย่างสิ้นเชิง พวกเขาทำสิ่งเดียวกัน แต่มีเพียงในตัวเท่านั้นที่มีผลต่อเชลล์ปัจจุบัน
jlliagre

13
@Kaz: โปรดอย่าเรียกฉันว่างี่เง่าในขณะที่ฉันเพิ่งรายงานข้อเท็จจริง คุณอาจเห็นด้วยหรือไม่เห็นด้วยกับ POSIX แต่อย่ายิงผู้ส่งสาร
jlliagre

47

จากการแนะนำ Bash ( เชลล์คืออะไร ):

Shells ยังมีชุดคำสั่งในตัว (builtins) ขนาดเล็กที่ใช้งานฟังก์ชั่นที่เป็นไปไม่ได้หรือไม่สะดวกในการขอรับผ่านยูทิลิตี้แยกต่างหาก ตัวอย่างเช่นcd, break, continueและ exec) ไม่สามารถดำเนินการนอกของเปลือกเพราะพวกเขาโดยตรงจัดการเปลือกตัวเอง history, getopts, killหรือpwdbuiltins หมู่คนอื่น ๆ สามารถดำเนินการได้ในสาธารณูปโภคที่แยกจากกัน แต่พวกเขามีความสะดวกมากขึ้นในการใช้คำสั่งเป็น builtin ตัวบิวด์เชลล์ทั้งหมดอธิบายไว้ในส่วนถัดไป


29

สำหรับ April Fool 's ปีนี้ผมเขียนรุ่นสแตนด์อโลนcd

ไม่มีใครตลกเลย ถอนหายใจ

ทุกคนที่ไม่แน่ใจว่าcdจะต้องสร้างไว้ในเชลล์ควรดาวน์โหลดสร้างและทดลองใช้

อ่าน man page ของมันด้วย :)


รหัสที่มีประโยชน์จริงๆ! :-)
dschulz

6
ดีที่คุณเห็นคนที่ทำงานเพื่อทำให้ Gnu / Linux สอดคล้องกับ POSIX การดำเนินงานของคุณไม่ได้เป็นเพียงเรื่องตลกดี แต่จริง ๆ แล้วสิ่งที่ขาดหายไปจากลินุกซ์ ...
jlliagre

8
ฉันคิดว่าฉันจะลองอีกครั้งในปีหน้าโดยอ้างถึงปัญหา POSIX ;)
Warren Young

6 ปีต่อมา: คุณสบายดีไหม?
Peter A. Schneider

@ PeterA.Schneider: ฉันคิดว่ามันชัดเจนว่าฉันล้อเล่นเพื่อที่จะชัดเจนไม่มีฉันจริง ๆ แล้วจะไม่ใช้ความพยายามที่พยายามได้รับสิ่งนี้ใน OSes และ OS-like project เช่น Cygwin ที่ปัจจุบัน /bin/cdไม่มี หากคุณต้องการที่จะใช้รหัสของฉันและทำให้การแสวงหาส่วนบุคคลของคุณเองคุณยินดีที่จะทำ
Warren Young

4

cdคำสั่งในเปลือกไม่สามารถจะเป็นกระบวนการที่แยกจากกันเพราะในยูนิกซ์มีกลไกในการเปลี่ยนไดเรกทอรีการทำงานปัจจุบันของกระบวนการที่แตกต่างกัน (ไม่ได้การปกครอง) ไม่มี

หากcdเป็นกระบวนการที่แตกต่างกันก็จะต้องเปลี่ยนไดเรกทอรีการทำงานปัจจุบันของผู้ปกครอง (เปลือก) ซึ่งเป็นไปไม่ได้ใน Unix แทนที่จะcdเป็นคำสั่งในตัวพิเศษ เชลล์เรียกใช้ฟังก์ชันเช่นchdir()และfchdir() เปลี่ยนไดเร็กทอรีการทำงานปัจจุบันของตนเอง

หมายเหตุ: เคอร์เนลจะเก็บหมายเลขไอโหนดของไดเร็กทอรีการทำงานปัจจุบันสำหรับทุกกระบวนการ กระบวนการลูกสืบทอดcwdมาจากแม่ของมัน


0

cd เป็นคำสั่งในตัวเชลล์ ง่ายเหมือนที่เป็นอยู่ ซีดีของผู้ชายบอกทุกอย่าง คำสั่ง cd เปลี่ยนไดเร็กทอรีการทำงานสำหรับล่ามทั้งหมดและ (ในสภาพแวดล้อมแบบเธรด) เธรดทั้งหมด


เนื่องจากเชลล์คือสภาพแวดล้อมที่ดูแลเกี่ยวกับ dirs ที่ทำงานในปัจจุบันของคุณ ($ PDW ... ) หรือ cdable_vars บิวด์อินนี้เป็นวิธีที่คำสั่งที่ผู้ใช้มองเห็นได้ทั้งหมดควรเปลี่ยนไดเรกทอรีการทำงานปัจจุบัน คุณสามารถทดสอบด้วยวิธีนี้ได้: รวบรวม bash โดยไม่ใช้ cd.c และลองเขียนสคริปต์ cd ของคุณเองซึ่งพยายามดูแลสภาพแวดล้อม cdable_vars ทั้งหมด คำถามนี้เป็นคำถามที่เกี่ยวข้องกับนักพัฒนามากกว่า ฉันพนันได้ว่าพวกเขาสามารถตอบคำถามคุณในรายละเอียดที่ลึกซึ้งยิ่งขึ้น

2
มีเหตุผลทางเทคนิคที่ดีมากที่cdมีในตัว ฉันขอแนะนำให้คุณอ่านคำตอบที่มีอันดับสูงสุดและพิจารณาว่าคำตอบของคุณจะได้รับการปรับปรุงอย่างไร
Thorbjørn Ravn Andersen

คำตอบอันดับสูงสุดคือที่เลวร้ายที่สุดที่ฉันเคยอ่าน! แต่เหรอ ฉันเป็นใคร!

3
แต่มันก็สามารถตอบคำถามได้ว่าทำไม
Thorbjørn Ravn Andersen

-1

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

declare -x PWD="/home/erfan"

ในผลลัพธ์ของคุณ ดังนั้นโดยคำสั่ง 'cd' เราแค่ต้องการแก้ไขตัวแปรภายในนี้ ฉันคิดว่าถ้าเราลองเราสามารถเปลี่ยนตัวแปร PWD ของ pty ใด ๆ ในเชลล์ได้แน่นอน ชอบ:

cder    #change current PTY $PWD variable

แต่ฉันคิดว่าไม่จำเป็นในกรณีปกติ กล่าวอีกนัยหนึ่งเรารับความช่วยเหลือจาก bash (หรือเชลล์ใด ๆ ) เพื่อแก้ไขตัวแปรภายในที่กำหนดไว้


3
แม้ว่าเชลล์บอร์นจะเปิดเผยไดเรกทอรีการทำงานปัจจุบัน (CWD) เป็น $ PWD ซึ่งไม่ใช่ตำแหน่งที่เก็บข้อมูลหลัก ตำแหน่งที่แท้จริงอยู่ในโครงสร้างต่อกระบวนการของเคอร์เนล ดังนั้นจึงไม่ถูกต้องที่จะบอกว่า CWD "เป็นตัวแปรสภาพแวดล้อม" ถ้ามันทำงานในแบบที่คุณแนะนำนี้ C สองซับจะพิมพ์..เส้นทางไม่ได้เส้นทางที่คุณเริ่มต้นมันมาจาก: #include <stdlib.h> int main(void) { chdir(".."); puts(getenv("PWD")); }(C เปลือกหอยเปิดเผย CWD เป็น% CWD แทนโดยวิธีการ.)
วอร์เรนหนุ่ม

ให้เพิ่มอีกบรรทัดในแอปของคุณ #include <stdlib.h> int main (void) {chdir (".. "); ทำให้ (getenv ( "PWD")); setenv (P "PWD", "/", 1); ทำให้ (getenv ( "PWD")); } เราจะได้อะไรเป็นผลลัพธ์?
Erfankam

3
นั่นจะเป็นการเขียนทับค่าของตัวแปรโดยไม่มีผลข้างเคียงกับ CWD นี่คือการทดสอบที่ดีที่จะแสดงให้เห็นว่า: มันจะแสดงไดเรกทอรีที่คุณเริ่มต้นโปรแกรมจากไม่#include <unistd.h> int main(void) { char ac[99]; setenv("PWD", "/", 1); puts(getcwd(ac, sizeof(ac))); } /
Warren Young

ฉันคิดว่าทุกกระบวนการมีไดเรกทอรีการทำงานและตัวแปรเส้นทางด้วย ดังนั้นคุณโดย chdir เพียงเปลี่ยนคุณลักษณะของกระบวนการนี้ Shell มีคุณลักษณะนี้เช่นกันและโดย cd เราจะทำการแก้ไข attribure นี้
Erfankam

4
ไม่ฉันกำลังบอกคุณว่า$PWDมีความหมายกับเชลล์เป้าหมายเท่านั้น มันเป็นเพียงวิธีที่เชลล์จะสื่อสารสิ่งที่มันรู้กับเชลล์สคริปดังนั้นพวกเขาไม่จำเป็นต้องเรียกpwdหามัน โปรแกรมแบบสแตนด์อโลนใด ๆ ขึ้นอยู่กับค่าของ$PWDจะไม่น่าเชื่อถือ
Warren Young
โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.