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.