내 shebang으로 "#!/path/to/NAME" 대신 "#!/usr/bin/env NAME"을 사용하는 것이 더 나은 이유는 무엇입니까?

내 shebang으로 "#!/path/to/NAME" 대신 "#!/usr/bin/env NAME"을 사용하는 것이 더 나은 이유는 무엇입니까?

#!/path/to/NAME나는 다른 사람들로부터 얻은 일부 스크립트에 shebangs가 있고 다른 스크립트(동일한 도구 NAME 사용)에는 shebangs가 있다는 것을 알았습니다 #!/usr/bin/env NAME.

둘 다 잘 작동하는 것 같습니다. 튜토리얼(예: Python 튜토리얼)에서는 후자가 더 나은 것으로 제안되는 것 같습니다. 그러나 나는 왜 이런 일이 일어나는지 잘 이해하지 못합니다.

후자의 shebang을 사용하려면 NAME이 PATH에 있어야 하지만 첫 번째 shebang에는 이러한 제한이 없다는 것을 깨달았습니다.

또한 (나에게는) 첫 번째 것이 NAME의 위치를 ​​정확하게 지정하기 때문에 더 나은 Shebang인 것 같습니다. 따라서 이 경우 NAME의 여러 버전(예: /usr/bin/NAME, /usr/local/bin/NAME)이 있는 경우 첫 번째 사례는 사용되는 버전을 지정합니다.

내 질문은 첫 번째 shebang이 두 번째 shebang보다 나은 이유는 무엇입니까?

답변1

이것이 반드시 더 나은 것은 아닙니다.

장점 #!/usr/bin/env pythonpython사용자의 $PATH.

이것피해#!/usr/bin/env python이유는 python사용자의 $PATH.

이는 스크립트를 실행하는 사람에 따라 스크립트가 다르게 동작할 수 있음을 의미합니다. 사용자의 경우 /usr/bin/python운영 체제와 함께 설치된 것을 사용할 수 있습니다. 반면에 /home/phred/bin/python잘 작동하지 않는 실험을 사용할 수도 있습니다.

python에만 설치된 경우 /usr/local/binin /usr/local/bin이 없는 사용자는 $PATH스크립트를 실행할 수도 없습니다. (이것은 최신 시스템에서는 불가능할 수도 있지만 더 모호한 해석기에서는 쉽게 발생할 수 있습니다.)

지정하면 #!/usr/bin/python스크립트를 실행하는 데 사용할 인터프리터를 정확하게 지정할 수 있습니다.특정 시스템에서.

또 다른 잠재적인 문제는 이 #!/usr/bin/env트릭 입니다.인터프리터에 인수를 전달하는 것을 허용하지 않습니다.(암시적으로 전달된 스크립트 이름은 제외) 이것대개문제는 아니지만 문제가 될 수도 있습니다. 많은 Perl 스크립트가 로 작성되었지만 #!/usr/bin/perl -w이제는 use warnings;대신 권장됩니다. Csh 스크립트는 --을 사용해야 #!/bin/csh -f하지만 csh 스크립트는권장되지 않음첫 번째. 그러나 다른 예가 있을 수 있습니다.

새 시스템에 계정을 설정할 때 개인 소스 제어 시스템에 여러 Perl 스크립트를 설치했습니다. 나는 각 스크립트 를 #!$HOME/bin.#!/usr/bin/perl

작은 점: 이 #!/usr/bin/env트릭은 명령의 오용이라고 할 수 있습니다 env. 원래 목적은 (이름에서 알 수 있듯이) 변경된 환경에서 명령을 호출하는 것입니다. 또한 일부 오래된 시스템(제 기억이 맞다면 SunOS 4 포함) 은 아마도 심각한 문제가 아닐 것입니다 env. 이런 방식으로 작동하고 많은 스크립트가 이 트릭을 사용하며 운영 체제 공급자가 이를 깨기 위해 어떤 조치도 취하지 않을 것입니다. 그것/usr/binenv#!/usr/bin/env가능한매우 오래된 시스템에서 스크립트를 실행하려면 문제가 되지만 어쨌든 스크립트를 수정해야 할 수도 있습니다.

또 다른 가능한 문제(댓글에서 지적한 Sopalajo de Arrierez에게 감사드립니다)는 cron 작업이 제한된 환경에서 실행되고 있다는 것입니다. 특히 , 일반적 $PATH으로 /usr/bin:/bin. 정확한 경로를 지정하거나 crontab에 행을 추가하여 설정할 수 있습니다 ( 자세히 알아보기).$PATH/usr/bin/env$PATHman 5 crontab

Kevin의 의견 은 Python virtualenv$PATH. (나는 virtualenv를 직접 사용해본 적이 없다.)#!/usr/bin/env pythonpython3

답변2

/usr/bin/env가 스크립트를 해석할 수 있으므로 $PATH스크립트의 이식성이 향상됩니다 .

#!/usr/local/bin/python

Python이 /usr/local/bin에 설치된 경우에만 스크립트가 실행됩니다.

#!/usr/bin/env python

$PATH귀하의 및 에 설명하겠습니다 $PATH.

따라서 스크립트는 이식성이 더 뛰어나고 Python이 로 설치된 시스템 /usr/bin/python이나 /usr/local/bin/python심지어 에 추가된 사용자 정의 디렉터리 $PATH(예: ) 에서 수정 없이 실행할 수 있습니다 /opt/local/bin/python.

env이식성은 하드 코딩된 경로보다 더 나은 경로를 사용하는 유일한 이유입니다.

답변3

목표 표준/요구사항:

사용 여부 결정순수한 또는 논리적( /usr/bin/env) shebang의 통역사 경로에는 두 가지 주요 고려 사항이 있습니다.

ㅏ)이것통역사대상 시스템에서 찾을 수 있습니다

비)이것올바른 버전~의 통역사 대상 시스템에서 찾을 수 있습니다

만약 우리가동의하다저것"비)"바람직하다.우리도 동의한다:

c) 바람직하게는 우리의 스크립트실패하다잘못된 인터프리터 버전으로 실행하여 잠재적으로 일관되지 않은 결과를 얻는 대신.

만약 우리가동의하지 않는다저것"비)"중요하다면 어떤 번역이라도 발견되면 충분할 것입니다.

시험:

사용으로 인해논리적Shebang의 인터프리터에 대한 경로는 /usr/bin/env가장 확장성이 뛰어난 솔루션으로, 동일한 인터프리터에 대한 서로 다른 경로가 있는 대상 호스트에서 동일한 스크립트가 성공적으로 실행될 수 있도록 합니다. 인기가 높기 때문에 Python을 사용하여 테스트할 것입니다. 우리의 기준을 충족합니다.

  1. /usr/bin/env예측 가능하고 일관된 위치에 거주인기 있는(아니요"모든") 운영 체제? :

    • RHEL 7.5
    • 우분투18.04
    • 라즈비안 10("버스터")
    • OSX 10.15.02
  2. 다음 Python 스크립트는 가상 봉투 내부 및 외부에서 실행됩니다(피펜프사용) 테스트 중:

    #!/usr/bin/env pythonX.x
    import sys
    print(sys.version)
    print('Hello, world!')
    
  3. 스크립트의 shebang은 필요한 Python 버전 번호(모두 동일한 호스트에 설치됨)에 따라 변경됩니다.

    • #!/usr/bin/env python2
    • #!/usr/bin/env python2.7
    • #!/usr/bin/env python3
    • #!/usr/bin/env python3.5
    • #!/usr/bin/env python3.6
    • #!/usr/bin/env python3.7
  4. 예상 결과: 즉 print(sys.version)= 입니다. 설치된 다른 Python 버전으로 실행될 때마다 shebang에 지정된 올바른 버전이 인쇄됩니다.env pythonX.x./test1.py

  5. 테스트 참고사항:

    • 테스트는 Python으로 제한됩니다.
    • 펄은 파이썬과 마찬가지로 ~ 해야 하다/usr/binFHS 거주
    • 가능한 모든 Linux/Unixy 운영 체제와 모든 운영 체제 버전에서 가능한 모든 조합을 테스트하지는 않았습니다.

결론적으로:

#!/usr/bin/env python 사용자 경로에서 일치하는 첫 번째 Python 버전이 사용되는 것은 사실이지만 버전 번호를 지정할 수 있습니다(예: 실제로 개발자는 어떤 인터프리터가 발견되는지 신경 쓰지 않습니다."#!/usr/bin/env pythonX.x첫 번째"; 그들이 관심을 갖는 것은 코드가 코드와 호환 가능하다고 알고 있는 지정된 인터프리터를 사용하여 실행되어 일관된 결과를 보장한다는 것입니다. 파일 시스템의 어느 곳에서나...

이식성/유연성 측면에서논리적- /usr/bin/env- 대신에순수한여러 버전에 대한 테스트에 따르면 해당 경로는 a), b) 및 c)의 요구 사항을 충족할 뿐만 아니라파이썬, 그러나 다른 운영 체제의 다른 경로에 있더라도 동일한 버전의 인터프리터를 찾는 퍼지 논리의 이점도 있습니다.  하지만최대배포판은 FHS를 존중하지만 모두가 그렇지는 않습니다..

그럼 스크립트는 어디에 있을까요?실패하다바이너리가 다른 위치에 있는 경우순수한동일한 스크립트를 사용하여 shebang에 지정된 경로보다논리적성공 일치하는 항목을 찾을 때까지 계속되므로 플랫폼 간 안정성과 확장성이 향상됩니다.

답변4

특히 Perl의 경우 이를 사용하는 것은 #!/usr/bin/env두 가지 이유로 나쁜 생각입니다.

첫째, 휴대성이 좋지 않습니다. 일부 모호한 플랫폼에서는 env가 /usr/bin에 없습니다. 둘째, 만일키스 톰슨Shebang 라인에서 매개변수를 전달할 때 문제가 발생할 수 있다는 점에 주목했습니다. 최대 이식성을 위한 솔루션은 다음과 같습니다.

#!/bin/sh
exec perl -x "$0" "$@"
#!perl

이것이 어떻게 작동하는지에 대한 자세한 내용은 "perldoc perlrun" 및 -x 매개변수에 대한 설명을 참조하세요.

관련 정보