실행 파일의 경로를 찾거나 Unix 셸에 명령 이름을 입력하면 어떤 일이 발생하는지 확인할 때 다양한 유틸리티( which
, type
, command
, whence
, where
, 등 whereis
) 가 있습니다 .whatis
hash
which
우리는 이것을 피해야 한다는 말을 자주 듣습니다 . 왜? 대신 무엇을 사용해야 할까요?
답변1
당신이 알고 싶지 않다고 생각한 모든 것은 다음과 같습니다.
일반화하다
Bourne과 유사한 쉘 스크립트에서 실행 파일의 경로 이름을 얻으려면(몇 가지 주의 사항이 있음, 아래 참조):
ls=$(command -v ls)
특정 명령이 존재하는지 확인하려면 다음을 수행하십시오.
if command -v given-command > /dev/null; then
echo given-command is available
else
echo given-command is not available
fi
Bourne과 같은 대화형 쉘의 프롬프트에서:
type ls
이 which
명령은 C-Shell의 파괴적인 유산이며 Bourne과 같은 쉘에 단독으로 두는 것이 가장 좋습니다.
예
이 정보를 스크립트의 일부로 찾는 것과 쉘 프롬프트에서 대화형으로 찾는 것에는 차이가 있습니다.
쉘 프롬프트에서 일반적인 사용 사례는 다음과 같습니다.이 명령은 이상하게 작동합니다. 올바른 명령을 사용하고 있습니까? 내가 이것을 입력하고 있는 동안 도대체 무슨 일이 일어나고 있는 걸까 mycmd
? 어떤 내용인지 좀 더 자세히 살펴봐도 될까요?
이 경우 실제로 명령을 호출하는 것보다 명령이 호출될 때 쉘이 수행하는 작업을 알고 싶습니다.
쉘 스크립트에서는 상당히 다른 경향이 있습니다. 쉘 스크립트에서 단순히 명령을 실행하려는 경우 명령이 어디에 있는지, 무엇인지 알고 싶을 이유가 없습니다. 일반적으로 알고 싶은 것은 실행 파일의 경로이므로 해당 파일에서 더 많은 정보를 얻을 수 있습니다(예: 해당 파일과 관련된 다른 파일의 경로 또는 해당 경로 정보에서 실행 파일의 내용을 읽을 수 있음).
대화형 방식으로 다음 사항을 알고 싶을 수도 있습니다.모두my-cmd
이와 같이 시스템(스크립트)에서 사용할 수 있는 명령은 거의 없습니다.
사용 가능한 대부분의 도구(종종 그러한 경우임)는 대화형으로 사용하도록 설계되었습니다.
역사
첫째, 약간의 역사입니다.
1970년대 후반까지 초기 Unix 셸에는 기능이나 별칭이 없었습니다. 별칭은 1978년경 에야 도입되었습니다(처음으로 소개되었지만 $PATH
) .csh
csh
해방됨, 1979 년 2BSD
5월) .cshrc
사용자 정의 쉘에 대해서도 처리됩니다(예를 들어 각 쉘은 csh
스크립트 .cshrc
와 같이 대화형이 아닐 때도 읽습니다).
rc
Bourne 쉘은 1979년 초 Unix V7에서 처음 출시되었지만 기능 지원은 훨씬 나중에 추가되었으며(1984년 SVR2에서) 어떤 경우에도 일부 파일이 없었습니다 ( .profile
쉘이 아닌 환경 구성을 위해)그 자체).
csh
대화식 사용에 더 편리하고 더 나은 많은 기능을 추가하기 때문에 Bourne 쉘보다 더 인기가 있습니다(구문은 Bourne 쉘보다 훨씬 나쁩니다).
3BSD
(1980) 에서는which
csh 스크립트csh
사용자가 실행 파일을 식별하는 데 도움을 주기 위해 추가된 이 which
스크립트는 오늘날 많은 상용 Unices(Solaris, HP/UX, AIX 또는 Tru64 등)에서 찾을 수 있는 스크립트와 거의 다르지 않습니다.
스크립트는 사용자의 명령 ~/.cshrc
(호출을 사용하지 않는 한 모든 스크립트와 마찬가지로 )을 읽고 csh
별칭 목록 및 (유지되는 배열을 기반으로) csh -f
제공된 명령 이름을 찾습니다 .$path
csh
$PATH
여기 있습니다: which
첫 번째는 당시 가장 인기 있는 쉘이었고( csh
90년대 중반까지 여전히 인기가 있었습니다) 이것이 책에 기록되어 여전히 널리 사용되는 주된 이유입니다.
csh
사용자 의 경우에도 which
csh 스크립트가 반드시 올바른 정보를 제공하는 것은 아닙니다. ~/.cshrc
나중에 프롬프트에서 정의하거나 source
다른 파일을 지정 하여 별칭을 가져오는 것이 아니라 에 정의된 별칭을 가져오며 csh
(좋은 생각은 아니지만) PATH
에서 다시 정의될 수 있습니다 ~/.cshrc
.
which
Bourne 셸에서 명령을 실행하면 에 정의된 별칭을 계속 찾을 수 있지만 ~/.cshrc
, 별칭을 사용하지 않아 별칭이 없는 경우 csh
에도 올바른 답을 얻을 수 있습니다.
1984년이 되어서야 내장 명령을 통해 SVR2의 Bourne 쉘에 유사한 기능이 추가되었습니다 type
. (외부 스크립트가 아닌) 내장되어 있다는 사실은할 수 있는셸 내부에 액세스할 수 있으므로 올바른 정보(어느 정도)를 제공합니다.
초기 명령은 명령을 찾을 수 없는 경우 실패한 종료 상태를 반환하지 않는다는 점에서 type
스크립트와 비슷한 문제를 겪었습니다. 또한 실행 파일의 경우 그 대신에 이와 유사한 것을 출력하는 which
것과 달리 스크립트에서 사용하기가 덜 쉽습니다.which
ls is /bin/ls
/bin/ls
Unix 버전 8(대중에게 공개되지 않음)의 Bourne 쉘에 내장된 함수의 type
이름이 바뀌고 whatis
인수 및 인쇄 함수 정의도 보고하도록 확장되었습니다. 또한 type
이름을 찾을 수 없을 때 실패가 반환되지 않는 문제를 해결합니다 .
rc
, Plan9(일회성 Unix 후속) 쉘(및 akanga
및 같은 파생 제품 es
) whatis
도 사용할 수 있습니다.
sh
80년대 중반에 개발되었지만 1988년 이전에는 널리 사용되지 않은 Korn 셸( POSIX 정의의 기반이 되는 하위 집합) csh
은 Bourne 셸 위에 많은 기능(라인 편집기, 별칭...)을 추가했습니다. 여기에는 몇 가지 옵션( 유사하게 자세한 출력을 제공하고 실행 파일만 검색(별명/함수 대신...))을 사용하는 자체 whence
내장 함수( )가 추가됩니다.type
-v
type
-p
AT&T와 Berkeley 간의 저작권 분쟁과 동시에 일부무료 소프트웨어쉘 구현은 1980년대 후반과 1990년대 초반에 나타났습니다. Almquist 쉘(BSD의 Bourne 쉘을 대체함) ash
(FSF 후원)의 모든 공개 도메인 구현은 1989년에서 1991년 사이에 나왔습니다.ksh
pdksh
bash
zsh
Ash는 Bourne 쉘을 대체하도록 의도되었지만 type
훨씬 나중에(NetBSD 1.3 및 FreeBSD 2.3에서)까지 내장 기능이 없었습니다 hash -v
. 그러나 OSF/1에는 OSF까지 항상 0을 반환하는 내장 기능이 /bin/sh
있었습니다 . type
/1 v3.x. bash
아무것도 추가되지 않았지만 경로( like ) 및 보고서를 인쇄 하는 옵션이 whence
추가되었습니다.-p
type
type -p
whence -p
-a
모두일치하는 명령. s -like 명령이 tcsh
내장되어 which
추가되었습니다 . 모두.where
bash
type -a
zsh
Shell fish
(2005)에는 type
명령이 함수로 구현되어 있습니다.
동시에 csh 스크립트는 which
NetBSD에서 제거되었으며(tcsh에 내장되어 있었고 다른 쉘에서는 많이 사용되지 않았기 때문에) 기능이 추가되었습니다 ( 로 호출 whereis
될 때 ). OpenBSD와 FreeBSD에서는 이 역시 C로 작성되고 .which
whereis
which
$PATH
which
$PATH
구현하다
다양한 Unices에는 명령에 대한 수십 가지의 which
다양한 구문과 동작 구현이 있습니다.
tcsh
Linux에서는 ( 및 의 내장 구현 외에도 zsh
) 여러 구현을 찾을 수 있습니다. 예를 들어, 최근 Debian 시스템에서는 $PATH
.
busybox
명령이 하나 더 있습니다 which
.
하나는 GNU
which
아마도 가장 고급스러운 것일 것입니다. csh 스크립트의 기능을 which
다른 쉘로 확장하려고 시도합니다. 별칭과 기능이 무엇인지 알려 주어 더 나은 답변을 제공할 수 있습니다(일부 Linux 배포판에는 이에 대해 전역 별칭이 설정되어 있다고 생각합니다 bash
).
zsh
몇 개 있어요운영자실행 파일 경로로 확장됩니다.=
파일 이름 확장자연산자 및 :c
기록 확장 수정자(여기서는 다음에 적용됨)매개변수 확장):
$ print -r -- =ls
/bin/ls
$ cmd=ls; print -r -- $cmd:c
/bin/ls
zsh
, zsh/parameters
명령 해시 테이블은 commands
모듈에서 연관 배열로도 사용됩니다.
$ print -r -- $commands[ls]
/bin/ls
이 유틸리티( Unix V8 Bourne 셸 또는 Plan 9/에 있는 유틸리티 whatis
제외 )는 문서(greps Whatis 데이터베이스, 즉 매뉴얼 페이지 개요)에만 사용되므로 실제로 관련이 없습니다.rc
es
whereis
3BSD
실행 파일, 매뉴얼 페이지, 소스 코드를 동시에 찾는 데 사용되는 대신 현재 환경을 기반으로 하지 않고 마치 which
에 작성된 것처럼 동시에 추가됩니다 . 다시 말하지만, 이는 다른 요구 사항을 충족합니다.C
csh
이제 표준 측면에서 POSIX는 command -v
and -V
명령(POSIX.2008까지 선택 사항임)을 지정합니다. UNIX 지정 type
명령(옵션 없음) 그게 전부입니다 ( where
, which
, whence
는 어떤 표준에서도 지정되지 않습니다).
일부 버전까지는 type
및 command -v
Linux Standard Base 사양에서 선택 사항이었습니다. 이는 예를 들어 일부 이전 버전 posh
(두 가지 모두를 기반으로 함에도 불구하고 pdksh
)이 둘 중 하나도 갖지 않은 이유를 설명합니다. command -v
일부 Bourne 쉘 구현에도 추가되었습니다(예: Solaris).
오늘의 상태
현재 상황은 type
Bourne과 같은 모든 쉘에 공통적입니다. (@jarno가 지적했듯이 아래 설명의 "POSIX 모드가 아닐 때" 또는 Almquist의 일부 후손의 command -v
경고/오류에 유의하십시오. 껍데기 ). 사용하려는 유일한 쉘입니다(거기에 쉘이 없고 내장되어 있기 때문입니다).bash
tcsh
which
type
which
tcsh
쉘 외부의 쉘에서 zsh
쉘 which
시작 파일 중 하나 또는 일부에 동일한 이름을 가진 별칭이나 함수가 없고 이에 대해 정의된 별칭이나 함수가 없는 한 ~/.cshrc
, 이는 ~/.bashrc
사용자 에게 알려줄 수도 있고 그렇지 않을 수도 있습니다. 잘못된 것을 말해요.$PATH
~/.cshrc
특정 이름의 모든 명령을 알고 싶다면 이식 가능한 것은 없습니다. where
in tcsh
또는 in zsh
또는 in ksh93 및 기타 쉘을 사용할 수 있으며 이를 결합할 수 있습니다.type -a
bash
zsh
whence -a
type
which -a
제안
실행 파일의 경로 이름을 가져옵니다.
이제 스크립트에서 실행 파일의 경로 이름을 얻으려면 몇 가지 고려 사항이 있습니다.
ls=$(command -v ls)
표준 접근 방식이 될 것입니다.
그러나 몇 가지 문제가 있습니다.
- 실행 파일을 실행하지 않으면 해당 경로를 아는 것이 불가능합니다. 모두
type
,which
,command -v
... 경험적 방법을 사용하여 경로를 찾습니다. 구성 요소를 반복하여$PATH
실행 권한이 있는 디렉터리가 아닌 첫 번째 파일을 찾습니다. 그러나 셸에 따라 많은 명령(Bourne, AT&T ksh, zsh, ash...)은 시스템 호출이 오류를 반환하지 않을$PATH
때까지 순차적으로만 실행됩니다.execve
예를 들어,$PATH
포함되어/foo:/bar
있고 실행하려는 경우ls
먼저 실행을 시도하고,/foo/ls
그렇지 않으면 실패합니다/bar/ls
. 이제/foo/ls
실행 권한이 없기 때문에 실행이 실패할 수도 있지만 유효한 실행 파일이 아닌 등의 여러 가지 이유로 인해 실행이 실패할 수도 있습니다. 실행 권한이 있는지command -v ls
보고 하지만/foo/ls
유효한 실행 파일이 아닌 경우/foo/ls
실행이ls
실제로 실행될 수 있습니다 ./bar/ls
/foo/ls
foo
내장 함수, 함수 또는 별칭인지 여부를 반환command -v foo
합니다foo
. 또는ash
와 같은 일부 셸의pdksh
경우 빈 문자열이 포함되고 현재 디렉터리에 실행 파일이 있으면zsh
반환될 수도 있습니다 . 어떤 경우에는 이를 고려해야 할 수도 있습니다. 내장 함수 목록은 셸 구현(때때로 busybox의 내장 함수)에 따라 다르며, 예를 들어 환경에서 함수를 얻을 수 있다는 점을 기억하세요.foo
$PATH
foo
mount
sh
bash
$PATH
상대 경로 구성 요소가 포함된 경우 (일반적.
으로 또는 둘 다 현재 디렉터리를 참조하지만 무엇이든 될 수 있는 빈 문자열) 쉘에 따라command -v cmd
절대 경로가 출력되지 않을 수 있습니다. 따라서 달리는 동안 얻은 경로는command -v
다른 곳에 도달한 후에는 더 이상 유효하지 않습니다.cd
- 일화: ksh93 셸을 사용하는 경우
/opt/ast/bin
(정확한 경로는 시스템에 따라 다를 수 있다고 생각하지만)$PATH
ksh93은 추가 내장 기능(chmod
,cmp
,cat
...)을 제공하지만 해당 경로가 존재하지 않는 경우command -v chmod
에도 또한/opt/ast/bin/chmod
존재하지 않는 것을 반환합니다.
명령이 존재하는지 확인
특정 명령이 표준으로 존재하는지 확인하려면 다음을 수행할 수 있습니다.
if command -v given-command > /dev/null 2>&1; then
echo given-command is available
else
echo given-command is not available
fi
사람들이 사용하고 싶어할 만한 곳which
(t)csh
csh
및 에서는 tcsh
선택의 여지가 많지 않습니다. 에서는 이것이 내장되어 있기 tcsh
때문에 좋습니다 . which
이는 csh
시스템 which
명령이며 경우에 따라 원하는 작업을 수행하지 못할 수도 있습니다.
특정 쉘에서만 명령 찾기
이를 사용하는 것이 합리적일 수 있는 상황은 쉘 스크립트에서 잠재적인 쉘 내장 기능이나 함수를 무시 which
하고 명령의 경로를 알고 싶은 경우입니다 bash
. csh
즉 , ( 예 : 또는 ) , (예 : , ), ( , ) 또는 시스템에서 사용할 수 있고 스크립트가 아닌 내장 함수 (예: 또는 )입니다.tcsh
dash
Bourne
whence -p
ksh
zsh
command -ev
yash
whatis -p
rc
akanga
which
tcsh
zsh
which
csh
이러한 조건이 충족되면 다음이 수행됩니다.
echo=$(which echo)
echo
쉘 내장/별칭/함수인지 여부에 $PATH
관계없이 (극단적인 경우를 제외하고) 첫 번째 항목에 대한 경로를 제공합니다 .echo
다른 쉘에서는 다음을 선호합니다.
- 다루기 힘든:
echo==echo
또는echo=$commands[echo]
또는echo=${${:-echo}:c}
- 변화 많은,다루기 힘든:
echo=$(whence -p echo)
- 야쉬:
echo=$(command -ev echo)
- RC,아캉가:(
echo=`whatis -p echo`
공백이 있는 경로를 참고하세요) - 물고기:
set echo (type -fp echo)
당신이하고 싶은 모든 것이 있다면달리기이 echo
명령을 사용하면 경로를 가져올 필요 없이 다음과 같이 할 수 있습니다.
env echo this is not echoed by the builtin echo
tcsh
예를 들어 내장 함수 의 사용을 방지하려면 를 사용하십시오 .which
set Echo = "`env which echo`"
정말 외부 명령이 필요할 때
사용하고 싶을 수 있는 또 다른 상황 which
은 실제로필요외부 명령. POSIX에서는 모든 셸 내장 명령(예: )을 외부 명령으로도 사용할 수 있어야 하지만 불행하게도 많은 시스템에서는 command
그렇지 않습니다. 예를 들어, 이 명령은 Linux 기반 운영 체제에서는 거의 발견되지 않지만 command
대부분의 운영 체제에서는 사용할 수 있습니다(운영 체제마다 옵션과 동작이 다르지만).command
which
외부 명령이 필요할 수 있는 상황은 POSIX 셸을 호출하지 않고 명령을 실행하려는 경우입니다.
system("some command line")
C 또는 다양한 언어, ... 함수는 popen()
셸을 호출하여 명령줄을 구문 분석하므로 system("command -v my-cmd")
그 안에서 작업합니다. 한 가지 예외는 perl
쉘에 쉘 특수 문자(공백 제외)가 표시되지 않으면 쉘이 최적화된다는 것입니다. 이는 백틱 연산자와도 작동합니다.
$ perl -le 'print system "command -v emacs"'
-1
$ perl -le 'print system ":;command -v emacs"'
/usr/bin/emacs
0
$ perl -e 'print `command -v emacs`'
$ perl -e 'print `:;command -v emacs`'
/usr/bin/emacs
:;
위의 내용을 추가하면 perl
쉘이 강제로 호출됩니다. 를 사용하면 which
이 트릭을 사용할 필요가 없습니다.
답변2
사람들이 그것을 사용하고 싶어하지 않는 이유는 which
이미 설명되었지만 실제로 실패한 시스템의 몇 가지 예는 다음과 같습니다 which
.
Bourne과 같은 쉘에서는 which
출력과 출력을 비교합니다 type
( type
쉘 내장으로서 명령을 호출하는 방법을 알려주는 쉘이기 때문에 이것이 사실이어야 합니다).
많은 경우에 그것은모서리하지만 명심하세요 which
/ type
종종 극단적인 경우에 사용됩니다(예기치 않은 동작에 대한 답을 찾기 위해, 예:이 명령은 대체 왜 이렇게 작동하며 어떤 명령을 부르고 있습니까?).
대부분의 시스템, 대부분의 Bourne 유사 쉘: 기능
가장 확실한 경우는 함수입니다.
$ type ls
ls is a function
ls ()
{
[ -t 1 ] && set -- -F "$@";
command ls "$@"
}
$ which ls
/bin/ls
그 이유는 which
실행 파일과 때로는 별칭에 대한 정보만 보고되기 때문입니다(항상 그런 것은 아니지만).당신의쉘), 함수가 아닙니다.
GNU 매뉴얼 페이지에는 함수를 보고하는 데 사용하는 방법에 대한 깨진(인용을 잊어버렸기 때문에 $@
) 예제가 있지만 별칭과 마찬가지로 쉘 구문 분석기를 구현하지 않기 때문에 속이기 쉽습니다.
$ which() { (alias; declare -f) | /usr/bin/which --tty-only --read-alias --read-functions --show-tilde --show-dot "$@";}
$ f() { echo $'\n}\ng ()\n{ echo bar;\n}\n' >> ~/foo; }
$ type f
f is a function
f ()
{
echo '
}
g ()
{ echo bar;
}
' >> ~/foo
}
$ type g
bash: type: g: not found
$ which f
f ()
{
echo '
}
$ which g
g ()
{ echo bar;
}
대부분의 시스템, 대부분의 Bourne 유사 쉘: 내장
또 다른 명백한 사례는 내장 명령이나 키워드입니다. which
외부 명령으로는 쉘에 내장된 것이 무엇인지 알 수 있는 방법이 없기 때문입니다(일부 쉘은 zsh
내장 내장을 동적으로 로드할 수 있음) bash
.ksh
$ type echo . time
echo is a shell builtin
. is a shell builtin
time is a shell keyword
$ which echo . time
/bin/echo
which: no . in (/bin:/usr/bin)
/usr/bin/time
zsh
(이것은 내장된 곳에는 적용되지 않습니다 )which
Solaris 10, AIX 7.1, HP/UX 11i, Tru64 5.1 등:
$ csh
% which ls
ls: aliased to ls -F
% unalias ls
% which ls
ls: aliased to ls -F
% ksh
$ which ls
ls: aliased to ls -F
$ type ls
ls is a tracked alias for /usr/bin/ls
이는 대부분의 상용 Unices which
(3BSD의 원래 구현과 같은) 에서 csh
읽기 이기 때문입니다 ~/.cshrc
. 현재 정의하고 있는 별칭과 실제로 사용하는 쉘에 관계없이 보고할 별칭은 거기에 정의된 것입니다. 그렇죠.
HP/UX 또는 Tru64의 경우:
% echo 'setenv PATH /bin:/usr/bin' >> ~/.cshrc
% setenv PATH ~/bin:/bin:/usr/bin
% ln -s /bin/ls ~/bin/
% which ls
/bin/ls
$path
(Solaris 및 AIX 버전에서는 읽기 전에 저장 ~/.cshrc
하고 명령을 찾기 전에 복원하여 이 문제를 해결했습니다 .)
$ type 'a b'
a b is /home/stephane/bin/a b
$ which 'a b'
no a in /usr/sbin /usr/bin
no b in /usr/sbin /usr/bin
또는:
$ d="$HOME/my bin"
$ mkdir "$d"; PATH=$PATH:$d
$ ln -s /bin/ls "$d/myls"
$ type myls
myls is /home/stephane/my bin/myls
$ which myls
no myls in /usr/sbin /usr/bin /home/stephane/my bin
(물론, csh
스크립트로서 공백이 포함된 인수를 처리할 것이라고 기대할 수는 없습니다...)
CentOS 6.4, 배시
$ type which
which is aliased to `alias | /usr/bin/which --tty-only --read-alias --show-dot --show-tilde'
$ alias foo=': "|test|"'
$ which foo
alias foo=': "|test|"'
/usr/bin/test
$ alias $'foo=\nalias bar='
$ unalias bar
-bash: unalias: bar: not found
$ which bar
alias bar='
해당 시스템에서는 GNU 명령을 래핑하기 위해 시스템 전체에 별칭이 정의됩니다 which
.
가짜 출력은 s의 출력을 읽었 which
지만 올바르게 구문 분석하는 방법을 모르고 휴리스틱(한 줄에 하나의 별칭, , , ... 다음에 처음 발견된 명령 찾기)을 사용하기 때문입니다.bash
alias
|
;
&
CentOS의 가장 나쁜 점은 zsh
완벽하게 좋은 which
내장 명령이 있지만 CentOS는 이를 작동하지 않는 GNU 별칭으로 대체하여 이를 중단시킨다는 것입니다 which
.
데비안 7.0, ksh93:
(여러 개의 쉘이 있는 대부분의 시스템에 적용 가능하지만)
$ unset PATH
$ which which
/usr/local/bin/which
$ type which
which is a tracked alias for /bin/which
데비안에서는 스크립트 /bin/which
입니다 /bin/sh
. 내가 아는 한 sh
그것은 그렇지만 , dash
그럴 때도 마찬가지다 bash
.
설정을 해제해도 조회가 PATH
비활성화되지는 않습니다 PATH
. 이는 시스템의기본 경로불행하게도 데비안에서는 아무도 동의하지 않습니다( dash
그리고 bash
has /usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin
, zsh
has /bin:/usr/bin:/usr/ucb:/usr/local/bin
, ksh93
has /bin:/usr/bin
, mksh
has /usr/bin:/bin
( $(getconf PATH)
) , execvp()
(like env
) has :/bin:/usr/bin
(예, 먼저 현재 디렉터리를 살펴보세요!)).
그렇기 때문에 위의 경우와 다른 기본값을 which
사용하기 때문에 오류가 발생합니다 .dash
PATH
ksh93
GNU는 더 나은 서비스를 제공하지 않으며 which
다음과 같이 보고합니다.
which: no which in ((null))
/usr/local/bin/which
akanga
(흥미롭게도 내 시스템에는 실제로 스크립트와 함께 제공되는 스크립트가 있습니다 akanga
( rc
기본값은 셸 파생입니다 PATH
) /usr/ucb:/usr/bin:/bin:.
)
bash, 모든 시스템:
유일한 사람Chris는 그의 답변에서 언급했습니다.:
$ PATH=$HOME/bin:/bin
$ ls /dev/null
/dev/null
$ cp /bin/ls bin
$ type ls
ls is hashed (/bin/ls)
$ command -v ls
/bin/ls
$ which ls
/home/chazelas/bin/ls
또한 hash
수동으로 호출한 후:
$ type -a which
which is /usr/local/bin/which
which is /usr/bin/which
which is /bin/which
$ hash -p /bin/which which
$ which which
/usr/local/bin/which
$ type which
which is hashed (/bin/which)
which
이제 때때로 실패하는 부분은 다음과 같습니다 type
.
$ mkdir a b
$ echo '#!/bin/echo' > a/foo
$ echo '#!/' > b/foo
$ chmod +x a/foo b/foo
$ PATH=b:a:$PATH
$ which foo
b/foo
$ type foo
foo is b/foo
이제 일부 쉘을 사용하십시오.
$ foo
bash: ./b/foo: /: bad interpreter: Permission denied
다른 사람:
$ foo
a/foo
실행될 수 없다는 사실을 사전에 알 수도 없고 which
알 type
수도 없습니다 . b/foo
일부 쉘(예: bash
, ksh
또는 )은 yash
호출될 때 foo
실제로 실행을 시도 b/foo
하고 오류를 보고하는 반면, 다른 쉘(예 zsh
: , ash
, , csh
, Bourne
, )은 시스템 호출이 실패할 경우 실행됩니다 tcsh
.a/foo
execve()
b/foo
답변3
Stephane이 언급하지 않은 것 중 하나는 (내 빠른 보기에서) which
쉘의 경로 해시 테이블을 모른다는 것입니다. 그 결과 실제 실행 결과를 나타내지 않는 결과가 반환될 수 있어 디버깅에 쓸모가 없게 됩니다.
답변4
(이 질문에는 "이식성"이라는 태그가 붙어 있으므로 "대화형 사용" 및 "사용 중인 시스템에만 관심이 있습니다"를 포함하여 질문에 대한 다양한 해석이 제외됩니다. 따라서 이 답변에서는 다음 사항만 고려합니다.쉘 스크립트에서 이 작업을 수행하면 안되는 이유는 무엇입니까?)
Stéphane은 옵션에 대한 철저한 분석을 제공하고 각 옵션이 좋은지 나쁜지에 대한 이유를 제시합니다. 어떤 이유도 which
항상 틀린 답은 아닙니다. 대신에 작은 영향을 미치는 요소가 많이 있습니다. 그 중 하나 또는 몇 가지를 견딜 수는 있지만 함께 복용하면 마음이 바뀔 수 있습니다.
아직 언급되지 않은 것을 사용하지 않는 한 가지 이유는 which
다음과 같은 질문을 낳기 때문입니다.
which
애초에 왜 출력을 원하는가?
내가 의미하는 바는 때때로 목표는 드롭인 대체품을 찾는 것이 아니라 which
애초에 필요하지 않은 방식으로 코드를 리팩터링하는 것입니다.
일반적인 패턴은 다음과 같습니다.
CMD=$( which cmd )
# some time later...
$CMD --some --args
거의 항상 인용되지 않는다는 사실을 제쳐두고 $CMD
, 전체 패턴이 깨졌다고 생각합니다.
CMD=/my/path/to/cmd
종속성을 피하는 것이 목적인 경우 하드 코딩이 중요합니다 $PATH
.
그러나 어쨌든 검색하면 $PATH
거의 항상 의미가 없습니다. which
및를 완전히 제거 $CMD
하고 다음을 작성하십시오.
cmd --some --args
함수나 별칭에 경로를 포함시키려고 경로가 필요하다고 생각되면 command
해당 경로를 사용하세요.
function cmd {
command cmd --extra-arg "$@"
}
물론 예외도 있으며, 다른 것을 기반으로 해야 합니다 PATH
. 이 경우 다음을 사용하는 것이 좋습니다.
function cmd {
PATH=$OTHERPATH command cmd "$@"
}
전체적으로 요점은피하다"명령 경로를 얻는 방법"에 대한 정신적 지름길이 있지만 사례별로 생각해 보세요.이 길이 정말 필요한가요? 왜?
어떤 경우에는 which
허용될 수도 있지만 적어도 어느 정도는 더 나은 해결책이 있을 것입니다. 다른 사람들을 위한 튜토리얼을 작성하고 있다면 다른 옵션에 대해 더 자세히 생각해 보세요.
합리적 이라고 생각하더라도 CMD=$( which cmd ) ; ... $CMD args
피해야 할 다른 이유가 있습니다.which
이것은 보편적이지 않습니다
이것POSIX에 필요한 명령 목록을 포함 command
하지만 type
포함하지 않습니다 which
.
출력 형식이 지정되지 않았습니다.
which
의무만 있으면 돼보여주다설명 없이 그대로 명령을 제공하는 대신 명령 경로를 지정하십시오. 대부분의 버전이지만.
which foo
다음을 출력하는 것은 완벽하게 합법적입니다:
foo might be /opt/foobar/bin/foo (unverified)
;또는foo is in /bin
;또는~foo/bin/foo
(~foo
foo의 홈 디렉토리를 나타냄) 또는/proc/1234/root/bin/foo
(프로세스 1234 종료)
답변이 최신이 아닐 수 있습니다.
(이것은 기본적으로 모든 형식을 제외하며 CMD=$( something ) ; ... $CMD ...
에 국한되지 않습니다 which
.)
특정 명령 이름에 대한 실행 파일의 위치는 다양한 이유로 변경될 수 있습니다.
때로는 이전 위치를 원할 때도 있고 그렇지 않을 때도 있습니다.
명령에 대한 경로가 상대적인 경우도 있습니다(따라서 .
시작이 아님 /
). 이는 일반적으로 보안 위험으로 간주되므로 드물지만 단순히 실행하면 cd
프로그램 경로가 무효화될 수 있는 특별한 경우에는 여전히 적용될 수 있습니다.