ทำไมคำสั่ง "ซึ่ง" ทำงานไม่ได้สำหรับ `cd ' ฉันไม่สามารถหาไฟล์ executable สำหรับ `cd` ได้เช่นกัน!


30

ฉันพยายามwhich cdและมันไม่ได้ให้เส้นทาง แต่กลับคืนรหัสทางออก 1 (ตรวจสอบด้วยecho $?) แทน Coreutil cdทำงานอยู่ดังนั้นไฟล์ปฏิบัติการควรจะอยู่ตรงนั้นใช่ไหม ฉันก็วิ่งfindหาcdแต่ไม่มีไฟล์ที่ปฏิบัติการได้ปรากฏขึ้น มันจะนำไปใช้อย่างไร

ปรับปรุง:

ฉันไม่รู้ว่าฉันควรถามคำถามนี้ในโพสต์อื่นหรือไม่ แต่เนื่องจากฉันคิดว่ามันดีที่นี่ฉันกำลังขยาย (?) โพสต์ ... ดังนั้นคำตอบนั้นง่ายมากจริง ๆ ไม่มีการปฏิบัติการใด ๆ - เพราะมัน ตัวบิวอิน - แต่ฉันพบบิวอินบางตัว (bash shell ใน Fedora) มีไฟล์ปฏิบัติการ! ดังนั้นในตัว -> ไม่มีการปฏิบัติการไม่ถูกต้องฉันคิดว่า? อาจเป็นคำตอบที่อธิบายว่า builtins คืออะไร (builtin command?) ซึ่งจริงๆแล้วเป็นเรื่องที่นี่แทนที่จะมุ่งเน้นไปที่cd... ลิงค์ที่ดีบางแห่งที่โพสต์ก่อนหน้านี้ระบุว่า builtins ไม่ใช่โปรแกรม ... แล้วมันคืออะไร พวกเขาทำงานอย่างไร พวกมันเป็นแค่ฟังก์ชั่นหรือเธรดของเชลล์หรือไม่?


1
อ่านนี้คำตอบ ขอแนะนำให้ใช้typeคำสั่ง
c0rp

7
ดูคำถามและคำตอบเกี่ยวกับสาเหตุcdที่ต้องสร้างในตัว: ทำไมซีดีไม่ได้เป็นโปรแกรม และอันนี้ทำไมtypeดีกว่าwhich: ทำไมไม่ใช้ "อัน"? จะใช้อะไรดี?
terdon

คำถามที่คล้ายกันที่นี่: askubuntu.com/q/613470/178596
Wilf

คำตอบ:


46

คำสั่งcdไม่สามารถเรียกใช้งานได้

ในเชลล์cdใช้เพื่อ "เข้าไปในไดเรกทอรีอื่น" หรือมากกว่านั้นอย่างเป็นทางการเพื่อเปลี่ยนไดเรกทอรีการทำงานที่ Curent (CWD) เป็นไปไม่ได้ที่จะใช้สิ่งนั้นเป็นคำสั่งภายนอก:

ไดเรกทอรีเป็นของกระบวนการ

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

cdbashเป็นเรื่องเกี่ยวกับการเปลี่ยนไดเรกทอรีการทำงานปัจจุบันของกระบวนการเปลือกเช่น

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

คำสั่งของเชลล์ในตัว

cdดังนั้นจึงทำให้รู้สึกไม่ให้เรียกใช้คำสั่งภายนอกสำหรับงานของ คำสั่งcdต้องใช้การเปลี่ยนแปลงกับกระบวนการเชลล์ที่รันอยู่ในปัจจุบัน

ในการทำเช่นนั้นมันเป็น "คำสั่ง builtin" ของเชลล์

คำสั่ง Builtin เป็นคำสั่งที่ทำงานคล้ายกับคำสั่งภายนอก แต่ถูกนำไปใช้ในเชลล์ (ดังนั้นจึงcdไม่ได้เป็นส่วนหนึ่งของ coreutils) สิ่งนี้อนุญาตให้คำสั่งเปลี่ยนสถานะของเชลล์เองในกรณีนี้ให้เรียกchdir()ดู (ดูman 2 chdir);

เกี่ยวกับ which

ตอนนี้คำตอบสำหรับคำถามไตเติ้ลนั้นง่าย:
คำสั่งที่ปฏิบัติการwhichไม่สามารถบอกเราได้ว่า cd เป็นคำสั่ง builtin เพราะคำสั่งปฏิบัติการไม่ทราบอะไรเกี่ยวกับ builtins

ทางเลือก type -a

เป็นทางเลือกให้whichคุณสามารถใช้type -a; มันสามารถดูคำสั่งที่ปฏิบัติการได้และบิวด์อิน; นอกจากนี้มันจะเห็นชื่อแทนและฟังก์ชั่น - ยังนำมาใช้ในเปลือก:

$ type -a cd
cd is a shell builtin
$ type -a type
type is a shell builtin
$ type -a which
which is /usr/bin/which
which is /bin/which

1
คำอธิบายที่ดี!
SaltyNuts

3
ดีกว่าคำตอบที่ได้รับการยอมรับในปัจจุบัน - นี่อธิบายว่าทำไม cdเชลล์ในตัว
Lily Chung

28

cdเป็นเชลล์ในตัวของPOSIX :

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

  1. หากชื่อคำสั่งไม่มีเครื่องหมายทับใด ๆ ขั้นตอนแรกที่สำเร็จในลำดับต่อไปนี้จะเกิดขึ้น:
    ...
    • หากชื่อคำสั่งตรงกับชื่อของยูทิลิตี้ที่แสดงในตารางต่อไปนี้ยูทิลิตีนั้นจะถูกเรียกใช้
      ...
      cd
      ...
    • มิฉะนั้นคำสั่งจะถูกค้นหาเพื่อใช้เส้นทาง ...

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

เนื่องจาก cd ส่งผลกระทบต่อสภาพแวดล้อมการประมวลผลเชลล์ในปัจจุบันจึงมีการจัดให้เป็นเชลล์ในตัวปกติเสมอ

จากbashคู่มือ :

คำสั่ง buildin ของเชลล์ต่อไปนี้สืบทอดมาจาก Bourne Shell คำสั่งเหล่านี้ถูกนำไปใช้ตามที่ระบุโดยมาตรฐาน POSIX
...

cd
       cd [-L|[-P [-e]]] [directory]

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

ตัวอย่างเช่นคุณอาจมีเชลล์ที่มี IPC เพื่อสื่อสารกับกระบวนการย่อยและจะมีcdโปรแกรมที่จะตรวจสอบว่ามีไดเรกทอรีอยู่หรือไม่และคุณมีสิทธิ์ในการเข้าถึงหรือไม่จากนั้นสื่อสารกับเชลล์เพื่อบอกให้เปลี่ยน ไดเรกทอรี อย่างไรก็ตามคุณจะต้องตรวจสอบว่ากระบวนการสื่อสารกับคุณเป็นเด็กหรือไม่ (หรือใช้วิธีการสื่อสารพิเศษกับเด็ก ๆ เท่านั้นเช่นตัวอธิบายไฟล์พิเศษหน่วยความจำที่แชร์ ฯลฯ ) และหากเป็นกระบวนการจริง เรียกใช้cdโปรแกรมที่เชื่อถือได้หรืออย่างอื่น นั่นคือความสามารถทั้งหมดของเวิร์ม

หรือคุณอาจมีcdโปรแกรมที่ทำให้การchdirเรียกของระบบและเริ่มเชลล์ใหม่ด้วยตัวแปรสภาพแวดล้อมปัจจุบันทั้งหมดที่ใช้กับเชลล์ใหม่แล้วฆ่า parent parent (อย่างใด) เมื่อเสร็จแล้ว 1

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

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


สิ่งที่เป็นไฟล์ปฏิบัติการไม่ได้ป้องกันไม่ให้มันเป็นบิวอิน กรณีในจุด:

echo และ test

echoและtestเป็นโปรแกรมอรรถประโยชน์ที่ได้รับคำสั่ง POSIX ( /bin/echoและ/bin/test) แต่เชลล์ยอดนิยมเกือบทุกตัวมีตัวต่อechoและtestภายใน ในทำนองเดียวกันkillก็สร้างขึ้นในที่มีอยู่ในโปรแกรม อื่น ๆ ได้แก่ :

  • sleep (ไม่เหมือนกัน)
  • time
  • false
  • true
  • printf

อย่างไรก็ตามมีบางกรณีที่คำสั่งไม่สามารถเป็นอะไรได้นอกจากบิลด์อิน cdหนึ่งในนั้นคือ โดยทั่วไปหากไม่ระบุพา ธ เต็มและชื่อคำสั่งตรงกับของบิวด์อินฟังก์ชันที่เหมาะสมกับคำสั่งนั้นจะถูกเรียกใช้ ขึ้นอยู่กับเชลล์พฤติกรรมของ builtin และของ executable อาจแตกต่างกัน (นี่เป็นปัญหาechoโดยเฉพาะอย่างยิ่งซึ่งมีพฤติกรรมที่แตกต่างกันอย่างดุเดือดหากคุณต้องการให้แน่ใจถึงพฤติกรรมบางอย่าง เส้นทางแบบเต็มและตั้งค่าตัวแปรเช่นPOSIXLY_CORRECT(แม้ว่าจะไม่มีการรับประกันจริง)

ในทางเทคนิคไม่มีอะไรที่ขัดขวางไม่ให้คุณจัดหาระบบปฏิบัติการที่เป็นเชลล์และมีทุกคำสั่งในตัว ใกล้ถึงจุดสิ้นสุดที่รุนแรงนี้เป็นเสาหินBusyBox BusyBox เป็นไบนารีเดียวที่ (ขึ้นอยู่กับชื่อที่ใช้เรียก) สามารถทำงานได้เหมือนโปรแกรมใด ๆมากกว่า 240 โปรแกรมรวมถึง Almquist Shell ( ash) หากคุณล้างค่าPATHในขณะที่การทำงานของ BusyBox ashโปรแกรมที่มีอยู่ใน BusyBox PATHยังสามารถเข้าถึงได้ให้กับคุณโดยไม่ได้ระบุ พวกเขาเข้ามาใกล้กับเชลล์บิวด์อินยกเว้นว่าเชลล์นั้นเป็นบิวด์บิวด์ใน BusyBox


กรณีศึกษา: เชลล์ Debian Almquist ( dash)

หากคุณดูที่dashแหล่งข้อมูลเธรดการเรียกใช้งานจะมีลักษณะดังนี้ (แน่นอนพร้อมฟังก์ชันเพิ่มเติมที่เกี่ยวข้องเมื่อใช้ไพพ์และสิ่งอื่น ๆ ):

main→การcmdloop→การevaltree→การevalcommand

evalcommandจากนั้นใช้findcommandเพื่อกำหนดว่าคำสั่งคืออะไร ถ้ามันเป็น builtin แล้ว :

 case CMDBUILTIN:
     if (spclbltin > 0 || argc == 0) {
         poplocalvars(1);
         if (execcmd && argc > 1)
             listsetvar(varlist.list, VEXPORT);
     }
     if (evalbltin(cmdentry.u.cmd, argc, argv, flags)) {
         if (exception == EXERROR && spclbltin <= 0) {
             FORCEINTON;
             break;

cmdentry.u.cmdเป็นstruct( struct builtincmd) หนึ่งซึ่งมีสมาชิกเป็นตัวชี้ทำงานด้วยลายเซ็นตามแบบฉบับของ:main เรียกฟังก์ชัน (ขึ้นอยู่กับว่า builtin เป็นคำสั่งหรือไม่) อย่างใดอย่างหนึ่งหรือตัวชี้ฟังก์ชั่นนี้ ฟังก์ชั่นที่แท้จริงถูกกำหนดไว้ในไฟล์ต้นฉบับต่างๆ ตัวอย่างเช่นคือ :(int, char **)evalbltinevalevalcmdecho

int
echocmd(int argc, char **argv)
{
    int nonl;

    nonl = *++argv ? equal(*argv, "-n") : 0;
    argv += nonl;

    do {
        int c;

        if (likely(*argv))
            nonl += print_escape_str("%s", NULL, NULL, *argv++);
        if (nonl > 0)
            break;

        c = *argv ? ' ' : '\n';
        out1c(c);
    } while (*argv);
    return 0;
}

ลิงก์ไปยังซอร์สโค้ดทั้งหมดในส่วนนี้ขึ้นอยู่กับจำนวนบรรทัดดังนั้นจึงอาจมีการเปลี่ยนแปลงโดยไม่ต้องแจ้งให้ทราบล่วงหน้า


1ระบบ POSIX มีcdไฟล์เรียกทำงานได้


หมายเหตุด้านข้าง:

มีโพสต์ที่ยอดเยี่ยมมากมายบน Unix & Linux ที่จัดการกับพฤติกรรมของเชลล์ โดยเฉพาะอย่างยิ่ง:

หากคุณไม่ได้สังเกตเห็นรูปแบบในคำถามที่ระบุไว้เพื่อให้ห่างไกลเกือบทั้งหมดของพวกเขาเกี่ยวข้องกับStéphane Chazelas


4
โปรดทราบว่าคุณจะได้รับcdข้อความความช่วยเหลือเกี่ยวกับhelp cd(สิ่งเดียวกันสำหรับคำสั่งเชลล์ builtin ทั้งหมด)
ซิลแว็ง Pineau

@SylvainPineau แม้ว่าฉันจะเชื่อมโยงกับคู่มือทุบตีแล้วคำแนะนำนั้นไม่สามารถใช้ได้กับกระสุนอื่น ๆ เช่น zsh
muru

อันที่จริงhelpเป็น builtin ทุบตี (สำหรับ zsh มันrun-help cd)
ซิลแว็ง Pineau

คำอธิบายที่เชื่อมโยงจากข้อมูลจำเพาะ POSIX ไม่ได้บอกอย่างชัดเจนว่าcdต้องเป็นแบบในตัวของเชลล์ ... แต่ขึ้นอยู่กับว่าคุณสมบัติกระบวนการและการถ่ายโอนงานใน UNIX cdเป็นแบบในตัวเป็นเพียงการดำเนินการที่ตรงไปตรงมา ดูการตอบกลับของโวลเคอซีเกล
pabouk

@pabouk แน่นอน (มันเรียกว่ายูทิลิตี) จากนั้นกล่าวต่อไปว่า: "เนื่องจาก cd มีผลต่อสภาพแวดล้อมการเรียกใช้เชลล์ในปัจจุบันจึงมีการจัดให้เป็นเชลล์ปกติในตัว"
muru

8

คุณไม่สามารถค้นหาไฟล์ที่เรียกใช้งานได้cdเพราะไม่มี

cdเป็นคำสั่งภายในของเชลล์ของคุณ (เช่นbash)


7

จากman which:

ซึ่งส่งคืนชื่อพา ธ ของไฟล์ (หรือลิงก์) ซึ่งจะถูกดำเนินการในสภาพแวดล้อมปัจจุบันได้รับข้อโต้แย้งของมันเป็นคำสั่งในเปลือกอย่างสอดคล้อง POSIX ทำได้โดยค้นหา PATH สำหรับไฟล์ที่สามารถเรียกใช้งานได้ซึ่งตรงกับชื่อของอาร์กิวเมนต์ มันไม่ได้ติดตามลิงก์สัญลักษณ์

ในฐานะที่เราสามารถดูได้จากรายละเอียดของมันเป็นเพียงการตรวจสอบwhich PATHดังนั้นหากคุณใช้งานบางอย่างbash functionมันจะไม่แสดงอะไรเลย มันจะดีกว่าที่จะใช้typewhichคำสั่งพร้อมกับ

ยกตัวอย่างเช่นในอูบุนตูคำสั่งนามแฝงlsls --color=auto

$ type ls
ls is aliased to `ls --color=auto'

$ which ls
/bin/ls

และถ้าคุณใช้ฟังก์ชั่นทดสอบhello:

$ function hello() { for i in {1,2,3}; do echo Hello $i;done }
$ which hello

whichไม่แสดงอะไรเลย แต่type:

$ type hello
hello is a function
hello () 
{ 
    for i in {1,2,3};
    do
        echo Hello $i;
    done
}

ในกรณีของคุณ:

$ type cd
cd is a shell builtin

ซึ่งหมายความว่าcdเป็นbuiltin เปลือกbashมันอยู่ภายใน ทั้งหมดทุบตี builtins อธิบายไว้ในman bashในส่วนคำสั่งเปลือกอาคาร

SHELL BUILTIN COMMANDS
       Unless otherwise noted, each builtin command documented in this section
       as accepting options preceded by - accepts -- to signify the end of the
       options.   The  :, true, false, and test builtins do not accept options
       and do not treat -- specially.  The exit, logout, break, continue, let,
       and  shift builtins accept and process arguments beginning with - with‐
       out requiring --.  Other builtins that accept  arguments  but  are  not
       specified  as accepting options interpret arguments beginning with - as
       invalid options and require -- to prevent this interpretation.


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