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


109

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

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

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

예제가 필요하면 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당신에 $PATH의 env명령을 호출합니다 /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를 사용하지 않았습니다. 내 희망은 이 답변을 처음 게시 한 이후 몇 년 동안 nodejs대 node문제가 해결 되기를 바랍니다 . 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.