`which` 명령이`cd`에서 작동하지 않는 이유는 무엇입니까? `cd`의 실행 파일도 찾을 수 없습니다!


30

나는 시도했지만 which cd경로를주지 않고 대신 종료 코드 1을 반환했습니다 (로 확인 echo $?). coreutil cd자체가 작동하므로 실행 파일이 있어야합니까? 또한 findfor를 cd실행했지만 실행 파일이 표시되지 않았습니다. 그러면 어떻게 구현됩니까?

최신 정보:

다른 게시물 에서이 질문을 해야하는지 모르겠지만 여기에서 좋은 것으로 생각하기 때문에 게시물을 확장하고 있습니까 (?) ... 그래서 대답은 실제로 매우 간단했습니다. 그에 대한 실행 파일은 없습니다. 내장 —하지만 일부 내장 (Fedora의 bash 쉘)에 실행 파일이있는 것을 발견했습니다! 그래서 내장-> 실행 파일이 올바르지 않다고 생각합니까? 어쩌면 내장에 실제로 초점을 맞추기보다는 실제로 내장 된 명령 (내장 명령?)을 설명하는 대답 cd이 있습니다. 그들은 어떻게 작동합니까? 그것들은 단지 쉘의 기능이나 스레드입니까?


1
답변을 읽으십시오 . type명령 을 사용하는 것이 좋습니다
c0rp

7
cd내장이 필요한 이유에 대한이 Q & A를 참조하십시오 . cd는 왜 프로그램이 아닌가? 그리고 왜 이것 type보다 더 낫습니다 which: "어떤"을 사용하지 않습니까? 그렇다면 무엇을 사용해야합니까?
terdon

비슷한 질문이 있습니다 : askubuntu.com/q/613470/178596
Wilf

답변:


46

명령 cd은 실행 파일이 될 수 없습니다

쉘에서는 cd"다른 디렉토리로 이동"하거나보다 공식적으로 현재 작업 디렉토리 (CWD)를 변경하는 데 사용됩니다. 이를 외부 명령으로 구현하는 것은 불가능합니다.

디렉토리는 프로세스에 속합니다

현재 작업 디렉토리는 파일을 액세스하는 데 사용할 수있는 전체 경로를 얻기 위해 상대 경로를 해석하는 데 사용되는 디렉토리입니다. 상대 경로는 여러 곳에서 사용되며 한 프로세스의 해석이 다른 프로세스에 영향을 미치지 않아야합니다.
이러한 이유로 모든 프로세스에는 고유 한 현재 작업 디렉토리가 있습니다.

cd예를 들어 쉘 프로세스의 현재 작업 디렉토리를 변경하는 것 bash입니다.

경로에서 실행 파일 인 외부 명령 인 경우 해당 실행 파일을 실행하면 현재 쉘의 영향을받지 않고 자체 작업 디렉토리가있는 프로세스가 작성됩니다. 외부 명령이 디렉토리를 변경하더라도 외부 프로세스가 종료되면 해당 변경이 사라집니다.

쉘 내장 명령

따라서의 작업에 대한 외부 명령을 실행하는 것은 의미가 없습니다 cd. 명령 cd은 현재 실행중인 쉘 프로세스에 변경 사항을 적용해야합니다.

이를 위해 쉘의 "내장 명령"입니다.

내장 명령은 외부 명령과 유사하게 작동하지만 셸에서 구현되는 명령입니다 ( cdcoreutils의 일부는 아님). 이를 통해 명령이 쉘 자체의 상태를 변경할 수 있습니다 (이 경우 chdir()see 참조 man 2 chdir).

which

제목 질문에 대한 대답은 간단합니다.
실행 명령 which은 내장 명령에 대해 아무것도 모르기 때문에 cd가 내장 명령임을 알 수 없습니다.

대안 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

cdA는 POSIX 위임 쉘 내부 명령 :

간단한 명령으로 명령 이름과 선택적인 인수 목록이 발생하면 다음 작업을 수행해야합니다.

  1. 명령 이름에 슬래시가 포함되어 있지 않으면 다음 순서의 첫 번째 성공 단계가 발생합니다.
    ...
    • 명령 이름이 다음 표에 나열된 유틸리티 이름과 일치하면 해당 유틸리티가 호출됩니다.
      ...
      cd
      ...
    • 그렇지 않으면 PATH를 사용하여 명령을 검색해야합니다.

명시 적으로 내장되어야한다고 말하지는 않지만 사양은 다음과 같은 설명에서 계속됩니다cd .

cd는 현재 쉘 실행 환경에 영향을주기 때문에 항상 쉘 일반 내장으로 제공됩니다.

로부터 bash수동 :

다음 쉘 내장 명령은 Bourne 쉘에서 상속됩니다. 이러한 명령은 POSIX 표준에 지정된대로 구현됩니다.
...

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

나는 당신이 cd내장 될 필요가없는 아키텍처를 생각할 수 있다고 생각 합니다. 그러나 내장 된 의미를 확인해야합니다. 일부 명령을 수행하기 위해 쉘에 특수 코드를 작성하면 내장 기능에 가까워지고 있습니다. 많이할수록 단순히 빌트인하는 것이 좋습니다.

예를 들어, 셸에 하위 프로세스와 통신하기위한 IPC가있을 수 있으며 cd디렉토리의 존재 여부와 액세스 권한이 있는지 여부를 확인한 다음 셸과 통신하여 변경을 지시하는 프로그램이 있습니다. 예배 규칙서. 그러나, 당신과 통신하는 프로세스가 자식인지 (또는 특별한 파일 디스크립터, 공유 메모리 등과 같은 자식들과의 특별한 통신 수단을 만드는지) 그리고 프로세스가 실제로 있는지 확인해야합니다. 신뢰할 수있는 cd프로그램이나 다른 것을 실행하십시오 . 그것은 벌레의 전체 캔입니다.

또는 시스템을 호출 하는 cd프로그램을 가질 수 있으며, chdir새로운 쉘에 적용된 모든 현재 환경 변수를 사용하여 새로운 쉘을 시작한 다음 완료되면 부모 쉘을 죽입니다. 1

더 나쁜 것은 프로세스 다른 프로세스의 환경을 변경할 있는 시스템을 가질 수도 있다는 것입니다 (기술적으로는 디버거 로이 작업을 수행 할 수 있다고 생각합니다). 그러나 이러한 시스템은 매우 취약합니다.

그러한 메소드를 보호하기 위해 점점 더 많은 코드를 추가하는 것을 알게 될 것이며,이를 단순히 내장형으로 만드는 것이 훨씬 간단합니다.


실행 파일이라는 것이 내장 기능을 방해하지는 않습니다. 지목 사항:

echotest

echotest유틸리티 POSIX 위임 (된다 /bin/echo/bin/test). 그러나 거의 모든 인기있는 쉘은 내장을 가지고 echotest. 마찬가지로, kill프로그램으로 사용 가능한 내장 기능도 있습니다. 다른 것들은 다음을 포함합니다 :

  • sleep (공통이 아님)
  • time
  • false
  • true
  • printf

그러나 명령이 내장 이외의 것이 될 수없는 경우가 있습니다. 그 중 하나는입니다 cd. 일반적으로 전체 경로를 지정하지 않고 명령 이름이 내장 경로와 일치하면 해당 명령에 적합한 함수가 호출됩니다. 셸에 따라 내장 동작과 실행 파일의 동작이 다를 수 있습니다 (특히 문제가되며echo , 동작크게 다릅니다 . 동작 을 확실하게하려면을 사용하여 실행 파일을 호출하는 것이 좋습니다. 전체 경로를 설정하고 변수를 설정하십시오 POSIXLY_CORRECT(그렇더라도 실제 보장은 없습니다).

기술적으로 쉘이기도하고 모든 명령을 내장 한 OS를 제공하는 데 방해가되지 않습니다. 이 극한의 끝에는 모 놀리 식 BusyBox가 있습니다. BusyBox는 단일 바이너리이며, (이 파일 이름에 따라) Almquist Shell ( )을 포함하여 240 개가 넘는 프로그램 중 하나로 작동 할 수 있습니다 ash. PATHBusyBox를 실행하는 동안 설정 을 해제 ash해도 BusyBox에서 사용 가능한 프로그램은 여전히을 지정하지 않고도 액세스 할 수 있습니다 PATH. 그들은 쉘 자체가 BusyBox에 내장되어 있다는 것을 제외하고는 쉘 내장에 가깝습니다.


사례 연구 : Debian Almquist Shell ( dash)

당신이 보면 dash소스, 실행 스레드 (파이프 및 다른 것들을 사용하는 경우 관련 추가 기능을 물론,)이 같은 수 있습니다 :

maincmdloopevaltreeevalcommand

evalcommand그런 다음 findcommand명령이 무엇인지 확인하는 데 사용 합니다. 그것은 내장 인 경우, 다음은 :

 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.cmdstruct( struct builtincmd)이며, 그 중 하나의 멤버는 함수 포인터이며 일반적인 서명은 main다음 과 같습니다 (int, char **). evalbltin함수 호출 (내장이 있는지 여부에 따라 eval두 명령 여부) evalcmd, 또는이 함수 포인터. 실제 기능은 다양한 소스 파일에 정의되어 있습니다. echo예를 들면 :

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실행 파일이 있습니다.


사이드 노트 :

쉘 동작을 다루는 유닉스와 리눅스에는 훌륭한 글이 많이 있습니다. 특히:

지금까지 나열된 질문에서 패턴을 발견하지 못한 경우 거의 모든 질문에 Stéphane Chazelas가 포함됩니다 .


4
참고는 얻을 수 cd에 대한 도움말 텍스트 help cd(모든 쉘 내장 명령에 대한 같은 것)
실뱅 피노

@SylvainPineau는 bash 매뉴얼에 링크되었지만 zsh와 같은 다른 쉘에는 일반적으로 해당 조언이 적용되지 않습니다.
muru

사실 helpbash는 내장이 (zsh을 위해, 그건 run-help cd)
실뱅 피노

POSIX 스펙의 링크 된 설명은 cd쉘 내장이어야 한다고 명시 적으로 말하지는 않지만 프로세스 특성과 전송이 UNIX cd에서 쉘 내장으로서 작동하는 방식을 기반으로하는 유일한 방법입니다. Volker Siegel답변을 참조하십시오 .
pabouk

@pabouk (실제로 유틸리티라고 함)은 "cd는 현재 셸 실행 환경에 영향을주기 때문에 항상 셸 일반 내장으로 제공됩니다."라고 말합니다.
muru


7

부터 man which:

이는 현재 환경에서 실행될 파일 (또는 링크)의 경로 이름을 리턴합니다. 인수는 엄격하게 POSIX 호환 쉘에서 명령으로 제공되었습니다. PATH에서 인수 이름과 일치하는 실행 파일을 검색하여이를 수행합니다. 기호 링크를 따르지 않습니다.

에 대한 설명에서 볼 수 있듯이 which확인 중 PATH입니다. 따라서 일부를 구현 bash function하면 아무것도 표시되지 않습니다. 와 함께 command 를 사용하는 것이 좋습니다 .typewhich

예를 들어 Ubuntu ls명령의 별칭은 ls --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

이 방법 cdA는 쉘 내부 명령은 , 그 내부에있다 bash. man bashSHELL BUILTIN COMMANDS 섹션에 설명 된 모든 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.