노드 파일의 시작 부분에서“/ usr / bin / env node”는 정확히 무엇을합니까?


109

나는 #!/usr/bin/env node몇 가지 예의 시작 부분 에서이 줄 을 보았고 그 줄 nodejs의 이유에 대한 답을 찾을 수있는 주제를 찾지 않고 검색했습니다.

단어의 특성상 검색이 쉽지 않습니다.

나는 최근에 몇몇 책 javascriptnodejs책을 읽었고 그 책에서 그것을 본 기억이 없었습니다.

예제가 필요하면 RabbitMQ공식 튜토리얼 을 볼 수 있습니다. 거의 모든 예제에 포함되어 있습니다. 여기에 그중 하나가 있습니다.

#!/usr/bin/env node

var amqp = require('amqplib/callback_api');

amqp.connect('amqp://localhost', function(err, conn) {
  conn.createChannel(function(err, ch) {
    var ex = 'logs';
    var msg = process.argv.slice(2).join(' ') || 'Hello World!';

    ch.assertExchange(ex, 'fanout', {durable: false});
    ch.publish(ex, '', new Buffer(msg));
    console.log(" [x] Sent %s", msg);
  });

  setTimeout(function() { conn.close(); process.exit(0) }, 500);
});

누군가이 줄의 의미가 무엇인지 설명해 주시겠습니까?

이 줄을 넣거나 제거하면 어떤 차이가 있습니까? 어떤 경우에 필요합니까?


3
기본적으로 호출하는 셸의 환경을 가져와 지정된 앱에 해당 환경을 채 웁니다. 이 경우node
Marc B

실제로 아니요, Windows에서 온 것이 아닙니다. 답변을 업데이트 해 주셔서 감사합니다. 나는 다른 사람이 다른 의견을 가지고 왔는지 기다리고 있습니다. 대답에 언급하지 않은 것이 하나 있습니다. 몇 시간 전에 찾았습니다. 그들이 여기에서 언급하는 것은 다소 중요해 보이지만 아직 저에게는 명확하지 않습니다. stackoverflow.com/questions/14517535/… (원하는 경우 업데이트 할 수 있습니다. 실제로이를 높이겠습니다.하지만 의무라고 생각하지는 않습니다. 귀하의 답변은 지금 충분합니다.)
Gepser 2015

@Gepser : 알겠습니다. 그것의 짧은이다 : 당신이 원하는 경우에 npmA (잠재적으로 전 세계적으로 사용 가능)와 같은 Node.js를 소스 스크립트를 설치하는 CLI , 당신이 해야한다 오두막 줄을 사용 - 그리고 npm심지어 윈도우에 그 일을 할 것입니다; 다시 한 번 업데이트 된 답변을 참조하십시오.
mklement0

"단어의 특성으로 인해 검색이 쉽지 않습니다." – 특정 검색 사용 사례에 대해 duckduckgo.com 을 사용해 볼 수 있습니다.
Ricardo

답변:


146

#!/usr/bin/env node이다 의 인스턴스 오두막 라인이 다음 에 실행 일반 텍스트 파일의 첫 번째 라인 유닉스 플랫폼 실행을 위해 해당 파일을 전달하는 것을 통역 시스템을 말한다 마법의 다음 명령 줄을 통해, #!접두사 (라고 오두막 ) .

참고 : Windows 는 shebang 줄을 지원 하지 않으므로 실제로 무시 됩니다. Windows에서는 파일을 해석 할 실행 파일을 결정 하는 지정된 파일의 파일 이름 확장자 입니다. 그러나의 컨텍스트에서는 여전히 필요합니다npm . [1]

shebang 라인에 대한 다음의 일반적인 논의는 Unix 계열 플랫폼으로 제한됩니다.

다음 토론에서는 Node.js에서 실행할 소스 코드가 포함 된 파일의 이름이 단순히 .js라고 가정합니다 file.

  • 당신은 이 회선이 필요한 당신은 Node.js를 소스 파일을 호출 할 경우, 직접 자신의 오른쪽에있는 실행 파일 -이 파일이 같은 명령을 실행으로 표시되어 있다고 가정 chmod +x ./file한 후 파일을 호출 할 수있는, 예를 들어, ./file또는 $PATH변수에 나열된 디렉토리 중 하나에있는 경우 간단히 file.

    • 특히 npm 패키지의 일부로 Node.js 소스 파일을 기반으로 CLI 를 만들려면 shebang 라인이 필요 하며 패키지 파일 값 에 따라 CLI를 설치해야 합니다 . 전역 설치된 패키지에서 작동하는 방법에 대해서는 이 답변 을 참조하십시오 . 각주 [1]은 Windows에서 이것이 어떻게 처리되는지 보여줍니다.npm"bin"package.json
  • 당신은 필요가 없습니다 명시 적으로 통해 파일을 호출 할이 줄을 node, 예를 들어, 통역node ./file


선택적 배경 정보 :

#!/usr/bin/env <executableName>은 인터프리터 를 이식 가능하게 지정 하는 방법입니다 . 간단히 말해서, 변수에 <executableName>나열된 디렉토리 중에서 (처음) 찾을 때마다 실행 합니다 ( $PATH암시 적으로 파일 경로로 전달).

이는 주어진 인터프리터가 플랫폼 전반에 걸쳐 서로 다른 위치에 설치 될 수 있다는 사실을 설명합니다 node. 이는 Node.js 바이너리 의 경우 에 해당합니다.

반대로 env유틸리티 자체 의 위치는 플랫폼간에 동일한 위치에있을 수 있습니다. 즉 , 실행 파일 /usr/bin/env전체 경로를 shebang 라인에 지정 해야합니다 .

POSIX 유틸리티가 있습니다 env되고 용도 변경 파일 이름으로 찾은에서 실행 파일을 실행하려면 여기를 $PATH.
의 진정한 목적은 env명령에 대한 환경을 관리하는 것입니다. env의 POSIX 사양Keith Thompson의 유용한 답변을 참조하십시오 .


Node.js가 유효한 JavaScript 코드가 아니기 때문에 shebang 줄에 대한 구문 예외 를 만들고 있다는 점도 주목할 가치가 있습니다 ( #POSIX와 유사한 쉘 및 기타 인터프리터와 달리 JavaScript의 주석 문자가 아닙니다).


[1] 플랫폼 간 일관성 을 위해 패키지의 파일에 지정된 실행 파일을 설치할 때 ( 속성을 통해 ) Windows에 래퍼 파일 (배치 파일)을 npm만듭니다 *.cmd . 기본적으로,이 래퍼 배치 파일을 모방 유닉스 오두막 기능을 : 그들은 명시 적으로 오두막 라인에 지정된 실행 파일과 대상 파일 된 invoke - 따라서, 당신은 오직 Windows에서이를 실행하려는 경우에도 스크립트가 당면한 라인을 포함해야합니다 참조 - 이 답변 자세한 내용은 내. 파일은없이 호출 할 수 있기 때문에package.json"bin"
*.cmd.cmd이는 원활한 크로스 플랫폼 경험을 제공합니다. Windows와 Unix 모두 npm에서 확장이없는 원래 이름으로 설치된 CLI를 효과적으로 호출 할 수 있습니다 .


나와 같은 인형에 대한 설명이나 요약을 제공 할 수 있습니까?
Andrew Lam

4
@AndrewLam :에 윈도우와 같은 파일 이름 확장자 .cmd.py같은 파일을 실행하는 데 사용됩니다 어떤 프로그램을 결정합니다. Unix에서는 shebang 라인이 해당 기능을 수행합니다. npm지원되는 모든 플랫폼에서 작업 하려면 Windows에서도 shebang 라인이 필요합니다.
mklement0 2017

28

인터프리터가 실행하는 스크립트는 일반적으로 OS에 실행 방법을 알려주는 shebang 줄 이 맨 위에 있습니다.

foo첫 번째 줄이 인 스크립트가있는 경우 #!/bin/sh시스템은 해당 첫 번째 줄을 읽고 /bin/sh foo. 이 때문에 대부분의 인터프리터는 스크립트 파일의 이름을 명령 줄 인수로 받아들이도록 설정됩니다.

다음에 오는 인터프리터 이름 #!은 전체 경로 여야합니다. OS는 $PATH통역사를 찾기 위해 검색하지 않습니다 .

에서 실행할 스크립트가있는 node경우 첫 번째 줄을 작성하는 확실한 방법은 다음과 같습니다.

#!/usr/bin/node

하지만 node명령이 .NET에 설치되어 있지 않으면 작동하지 않습니다 /usr/bin.

일반적인 해결 방법은 다음 env명령 을 사용하는 것입니다 ( 실제로이 목적을위한 것이 아님).

#!/usr/bin/env node

스크립트가 호출 foo되면 OS는 다음과 같은 작업을 수행합니다.

/usr/bin/env node foo

env명령은 명령 줄에 이름이 지정된 다른 명령을 실행하여 다음 인수를 해당 명령에 전달합니다. 여기서 사용되는 이유 는 명령 env을 검색 $PATH하기 때문입니다. 그래서 경우가 node에 설치 /usr/local/bin/node하고, 당신이 /usr/local/bin당신에 $PATHenv명령을 호출합니다 /usr/local/bin/node foo.

env명령 의 주요 목적은 수정 된 환경으로 다른 명령을 실행하여 명령을 실행하기 전에 지정된 환경 변수를 추가하거나 제거하는 것입니다. 그러나 추가 인수없이 변경되지 않은 환경에서 명령을 실행하기 만하면이 경우에 필요한 전부입니다.

이 접근 방식에는 몇 가지 단점이 있습니다. 대부분의 최신 Unix 계열 시스템에는 /usr/bin/env.이 있지만 env명령이 다른 디렉토리에 설치된 이전 시스템에서 작업했습니다 . 이 메커니즘을 사용하여 전달할 수있는 추가 인수에 제한이있을 수 있습니다. 사용자가 경우 하지 않습니다 포함하는 디렉토리가 node에 명령을 $PATH하거나이라는 일부 다른 명령을 가지고 node, 그것은 전혀 잘못된 명령이나하지 작업을 호출 할 수있다.

다른 접근 방식은 다음과 같습니다.

  • 명령 자체에 #!대한 전체 경로를 지정 하는 행을 사용하여 node다른 시스템에 필요한대로 스크립트를 업데이트하십시오. 또는
  • node스크립트를 인수로 사용하여 명령을 호출하십시오 .

트릭에 대한 자세한 내용은 이 질문 (및 내 대답 )을 참조하십시오 #!/usr/bin/env.

덧붙여서, 내 시스템 (Linux Mint 17.2)에는 /usr/bin/nodejs. 내 노트에 따르면, 변경 /usr/bin/node/usr/bin/nodejs우분투 12.04과 12.10 사이. #!/usr/bin/env트릭이하지 도움이 될 것입니다 (당신은 심볼릭 링크 또는 뭔가 비슷한을 설정하지 않은 경우).

업데이트 : mtraceur의 의견은 다음과 같이 말합니다.

nodejs 대 노드 문제에 대한 해결 방법은 다음 6 줄로 파일을 시작하는 것입니다.

#!/bin/sh -
':' /*-
test1=$(nodejs --version 2>&1) && exec nodejs "$0" "$@"
test2=$(node --version 2>&1) && exec node "$0" "$@"
exec printf '%s\n' "$test1" "$test2" 1>&2
*/

이것은 먼저 시도한 nodejs다음 시도 node하고 둘 다 찾을 수없는 경우에만 오류 메시지를 인쇄합니다. 설명은이 의견의 범위를 벗어납니다.이 답변이 문제를 제기했기 때문에 누군가가 문제를 처리하는 데 도움이 될 수 있도록 여기에 남겨 두겠습니다.

최근 NodeJS를 사용하지 않았습니다. 내 희망은 이 답변을 처음 게시 한 이후 몇 년 동안 nodejsnode문제가 해결 되기를 바랍니다 . Ubuntu 18.04에서 nodejs패키지는 /usr/bin/nodejs에 대한 심볼릭 링크로 설치 됩니다 /usr/bin/node. 일부 이전 OS (Ubuntu 또는 Linux Mint, 어느 것이 확실하지 않음)에는에 대한 심볼릭 링크로 nodejs-legacy제공 되는 패키지 가있었습니다 . 내가 모든 세부 사항을 올바르게 가지고 있다는 보장은 없습니다.nodenodejs


이유를 제공하는 매우 철저한 답변.
Suraj Jain

1
nodejsvs node문제에 대한 해결 방법은 1) #!/bin/sh -, 2) ':' /*-3) test1=$(nodejs --version 2>&1) && exec nodejs "$0" "$@"4) test2=$(node --version 2>&1) && exec node "$0" "$@", 5) exec printf '%s\n' "$test1" "$test2" 1>&26) 여섯 줄로 파일을 시작하는 것 */입니다. 이것은 먼저 시도한 nodejs다음 시도 node하고 둘 다 찾을 수없는 경우에만 오류 메시지를 인쇄합니다. 설명은이 의견의 범위를 벗어납니다.이 답변이 문제를 제기했기 때문에 누군가가 문제를 처리하는 데 도움이 될 수 있도록 여기에 남겨 두겠습니다.
mtraceur 19

@mtraceur : 귀하의 의견을 제 답변에 통합했습니다. 왜 -#!라인?
Keith Thompson 19

-에는 #!/bin/sh -바로 스크립트 이름 또는 상대 경로는 쉘이 시작을 볼 수 있다는 것을 상황의 매우 좁히고 가능성이 세트에 확인 쉘 동작합니다하게 바로 습관이다 -. (또한 예, 모든 주류 배포판이 node기본 이름으로 다시 수렴 된 것 같습니다 . 댓글을 작성할 때 확인하러 가지 않았습니다.하지만 내가 아는 한 데비안 배포판 패밀리 트리 만 사용 nodejs했습니다. 그들은 모두도 지원에 다시 복귀처럼 node데비안가 한 번).
mtraceur

기술적으로 첫 번째 인수로서의 단일 대시는 "옵션의 끝"을 의미하지 않았습니다. 원래는 "끄기 -x-v"를 의미 했지만 초기 Bourne-likes는 첫 번째 인수를 가능한 옵션으로 만 구문 분석하고 셸이 해당 옵션을 끄고 시작하기 때문에 , 원본 이후로 셸이 스크립트 이름을 구문 분석하지 않도록하는 것은 악용 가능했으며, 호환성을 위해 동작이 최신 Bourne-likes에서 유지되기 때문에 악용 가능한 상태로 남아 있습니다. Bourne의 모든 역사와 휴대 성 퀴즈를 기억한다면.
mtraceur 19

0

짧은 대답 : 통역사의 길입니다.

편집 (긴 답변) : "노드"앞에 슬래시가없는 이유는 항상 #! / bin /의 신뢰성을 보장 할 수 없기 때문입니다. "/ env"비트는 수정 된 환경에서 스크립트를 실행하고 더 안정적으로 인터프리터 프로그램을 찾을 수 있도록함으로써 프로그램을 크로스 플랫폼으로 만듭니다.

반드시 필요한 것은 아니지만 이식성 (및 전문성)을 보장하기 위해 사용하는 것이 좋습니다.


1
/usr/bin/env비트 환경을 수정하지 않습니다. 인수로 주어진 다른 명령을 호출하고이를 찾기 $PATH위해 검색하는 (대부분) 알려진 위치에있는 명령 일뿐 입니다. 요점은이 #!줄에 호출되는 명령의 전체 경로가 필요하며 node설치 위치를 알 필요는 없다는 것 입니다.
Keith Thompson

그것이 내가하려는 일이었습니다. 명확히 해주셔서 감사합니다!
Quantum
당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.