PATH에서 프로그램의 전체 경로를 안정적으로 찾는 방법은 무엇입니까?


12

PATH쉘 스크립트를 사용하여 주어진 프로그램의 경로를 찾아야합니다 . 경로는 프로그램의 실제 전체 경로 여야하며, 나중에 자체를 exec*검색하지 않는 함수 중 하나로 전달 될 수 있습니다 ( PATH예 :) execv.

같은 프로그램이 있습니다 kill실제 프로그램 내장 동시에 쉘로 사용할 수 있습니다. 이 경우 실제 프로그램의 전체 경로가 필요합니다.

POSIX 표준의 2.9.1.1 절 명령 검색 및 실행에PATH 지정된대로 프로그램을 찾을 수있는 여러 유틸리티가 있습니다 .

which표준의 일부가 아닙니다. 일부 시스템에서는 일반 프로그램 일 수 있지만 일부 쉘은 기본 제공 프로그램입니다. 대부분의 시스템과 쉘에서 사용할 수 있지만 내장 버전의 쉘은 실행 파일 경로 대신 내장 이름을 반환합니다. 또한 어떤 식 으로든 표준화되지 않았으며 출력을 반환하고 다른 옵션을 사용할 수 있습니다.

bash# which kill
/usr/bin/kill
dash# which kill
/usr/bin/kill
fish# which kill
/usr/bin/kill
mksh# which kill
/usr/bin/kill
tcsh# which kill
kill: shell built-in command.
zsh# which kill
kill: shell built-in command

whence이는, 내장 된 몇 조개. 그러나 많은 쉘에서는 사용할 수 없습니다. 프로그램 경로 대신 내장 이름을 반환합니다. -p이 동작을 변경하기 위해 A 가 전달 될 수 있습니다.

bash# whence kill
bash: whence: command not found
dash# whence kill
dash: 1: whence: not found
fish# whence kill
fish: Unknown command 'whence'
mksh# whence kill
kill
mksh# whence -p kill
/usr/bin/kill
tcsh# whence kill
whence: Command not found.
zsh# whence kill
kill
zsh# whence -p kill
/usr/bin/kill

commandPOSIX : 2008에 의해 지정된 내장 이 있습니다 . 불행히도 일반 명령과 내장을 검색하고 동일한 이름의 내장으로 음영 처리 된 프로그램 경로 대신 내장 이름을 반환합니다. 일부 오래된 쉘은 아직 구현하지 않았습니다.

bash# command -v kill
kill
dash# command -v kill
kill
fish# command -v kill
/usr/bin/kill
mksh# command -v kill
kill
tcsh# command -v kill
command: Command not found.
zsh# command -v kill
kill

enablePOSIX에 지정되어 있는지 여부를 알 수 없지만 , 그렇다면 enable -n whichPOS 내장 기능을 비활성화하는 데 사용할 수 있습니다 which.
Muzer

및이realpath
Ipor Sircer

내가 배열 한 껍질에 @Muzer, enable단지에서 제공 bash하고zsh
세바스찬 슈 레이더

1
모든 쉘이 아니라 스크립트를 실행하는 특정 쉘에 대해 실현 가능한 방법이 필요합니다 . 스크립트는 임의의 쉘이 아니라 shebang 행에 지정된 쉘에 의해 실행됩니다. bash에서 그렇습니다 type -p. bash와 dash 모두 command같은 이름의 함수 나 내장 함수가 있어도 실제 실행 파일을 실행하라는 명령을 내릴 수 있습니다.
AlexP

1
commandQ가 올바르게 말한 것처럼 @AlexP 는 함수 및 별칭을 건너 뛰지 만 내장되지 않습니다. 그리고 모든 시스템에서 주어진 쉘 또는 일부 POSIX 쉘을 얻는 경로가 없기 때문에 항상 shebang을 사용할 수는 없습니다.
dave_thompson_085

답변:


11

직접 검색하십시오.

export IFS=":"
[ -z "${1}" ] && exit 1
for dir in $PATH
do if [ -x "${dir}/${1}" ]
   then echo "${dir}/${1}"
        exit 0
   fi
done
echo ${1} not found
exit 1

테스트 bash, dash, ksh, mksh,zsh

최신 정보

위의 내용은 독립 실행 형 스크립트에는 적합하지만이 스크립트를 더 큰 스크립트에 포함시키려는 경우 다음과 같은 것을 사용하는 것이 좋습니다.

function find_path() {
   IFS_SAVE="${IFS}"
   export IFS=":"
   [ -z "${1}" ] && exit 1
   for dir in $PATH
   do if [ -x "${dir}/${1}" ]
      then echo "${dir}/${1}"
           export IFS="${IFS_SAVE}"
           return 0
      fi
   done
   export IFS="${IFS_SAVE}"
   echo ${1} not found
   return 1
}

그 때문에입니다 IFS일치, 또한 스와핑 찾은 후 복원 exit의와 return의를


1
아마도 -f 대신에 -x?
Jeff Schaller

@JeffSchaller 좋은 지적, 실행 파일이 아닌 파일을 선택할 이유가 없습니다.
Zachary Brady

3
이 스크립트를 더 큰 쉘 스크립트에 통합하면 (아마도 의도 한대로 자체 스크립트로 작성하는 대신) 나중에 IFS의 이전 값을 복원 할 수 있습니다. 그렇지 않으면 많은 영향을 줄 수 있습니다 스크립트의 나머지 부분
psmears

IFS변수를 내보내는 이유는 무엇 입니까? 로컬 쉘에 이것을 설정하는 것으로 충분하지 않습니까? 현지에 대해 말하면 local IFS휴대용입니까? 다른 방법으로 IFS를 같은 방식으로 저장하면 위의 내용이 제대로 작동하지 않을 수 있습니다. 보면 SE에이 질문 , localPOSIX을없는에도 불구하고 대부분의 포탄을 위해 작동 할 수 있습니다. 원본 버전을 (…)서브 쉘 에 넣는 것도 효과적 일 수 있습니다.
MvG
당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.