programing

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

codeshow 2023. 9. 4. 20:51
반응형

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

나는 이 대사를 본 적이 있습니다.#!/usr/bin/env node 가지예시때에작할의 몇 가지 에.nodejs저는 그 대사의 이유에 맞는 어떤 주제도 찾지 못한 채 구글을 검색했습니다.

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

▁some를 읽었습니다.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);
});

이 선이 무슨 뜻인지 누가 설명해 주시겠어요?

이 선을 넣거나 빼면 어떤 차이가 있습니까?어떤 경우에 그것이 필요합니까?

#!/usr/bin/env node셰방 라인의 인스턴스입니다. 유닉스 계열 플랫폼에서 실행 가능한 일반 텍스트 파일의 첫 번째 줄은 마법에 따른 명령줄을 통해 실행을 위해 파일을 전달할 인터프리터를 시스템에 알려줍니다.#!접두사(쉐방이라고 함)

참고: Windows(윈도우)에서는 셰방 라인을 지원하지 않으므로 셰방 라인은 사실상 무시됩니다. Windows(윈도우)에서는 파일의 파일 이름 확장자만 해당 파일을 해석할 실행 파일을 결정합니다.그러나[1]경우에도 여전히 필요합니다.

다음과 같은 셰방 라인에 대한 일반적인 논의는 유닉스 계열 플랫폼으로 제한됩니다.

에서는 Node "Node.js"로 file.

  • Node.js 소스 파일을 직접 실행 파일로 호출하려면 다음과 같은 명령으로 파일이 실행 파일로 표시되었다고 가정합니다.chmod +x ./file그러면 파일을 호출할 수 있습니다. 예를 들어,./file또는목있디는중경있하우는에 있는 중 $PATH 가적인말, 히해서단간변▁variable,서▁as▁simply말해.file.

    • 특히 npm 패키지의 일부로 Node.js 소스 파일을 기반으로 CLI를 생성하려면 셰방 라인이 필요합니다. CLI는 다음에 의해 설치됩니다.npm패키지의 파일에 있는 키 값을 기준으로 합니다. 또한 전역적으로 설치된 패키지에서 작동하는 방법에 대해서도 이 답변을 참조하십시오.각주 [1]은 Windows에서 이 작업을 처리하는 방법을 보여줍니다.
  • 파일을 통해 명시적으로 호출하려면 이 줄이 필요하지 않습니다.node 통사역, 예:):node ./file


선택적 배경 정보:

#!/usr/bin/env <executableName>는 인터프리터를 쉽게 지정하는 방법입니다. 간단히 말해서, 다음과 같이 말합니다.<executableName>목록에 있는 디렉토리 중에서 (처음에) 찾을 수 있는 곳.$PATHvariable(그리고 암시적으로 해당 파일의 경로를 전달).

이것은 주어진 인터프리터가 플랫폼에 따라 다른 위치에 설치될 수 있다는 사실을 설명합니다. 이것은 확실히 그렇습니다.nodeNode.js 이진 파일입니다.

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

유틸리티 POSIX를 하십시오.env파일 이름으로 찾고 실행 파일을 실행하기 위해 여기서 용도 변경 중입니다.$PATH.
의 진정한 .env명령에 대한 환경 관리 - 의 POSIX 사양 및 Keith Thompson의 유용한 답변을 참조하십시오.


또한 Node.js가 유효한 자바스크립트 코드가 아니라는 점을 고려할 때 셰방 라인에 대해 구문 예외를 만들고 있다는 점에 주목할 필요가 있습니다.#는 POSIX와 같은 셸 및 기타 인터프리터와 달리 JavaScript의 주석 문자가 아닙니다.


교차 플랫폼 일관성을 위해 패키지에 지정된 실행 파일을 설치할 때 Windows에 래퍼 파일(배치 파일)만듭니다.package.jsonfile 이름)을 합니다."bin"재산).기본적으로 이러한 래퍼 배치 파일은 유닉스 셰방 기능을 모방합니다. 즉, 셰방 라인에 지정된 실행 파일로 대상 파일을 명시적으로 호출합니다. 따라서 스크립트는 윈도우에서만 실행할 의도가 있더라도 셰방 라인포함해야 합니다. 자세한 내용은 제 답변을 참조하십시오.
때부터*.cmd은 호을출수있다 없이 할 수 ..cmd기능은 환경을 합니다. 모두에서 확, 이, 원, 장을 할 수 .npm- 확장자가 없는 원래 이름으로 CLI를 설치합니다.

인터프리터가 실행할 스크립트는 일반적으로 상단에 셰방 라인이 있어 OS에 실행 방법을 알려줍니다.

이름이 지정된 스크립트가 있는 경우foo첫 번째 줄은 누구의 것입니까?#!/bin/sh시스템은 첫 번째 줄을 읽고 동등한 것을 실행합니다./bin/sh foo이 때문에 대부분의 인터프리터는 스크립트 파일의 이름을 명령줄 인수로 사용하도록 설정됩니다.

다에오인터이름리터프 뒤에 #!. 전체경합니로를 . OS가 검색하지 않습니다.$PATH통역사를 찾기 위해서요.

실행할 가 있는 node 줄을 방법은 줄을쓰는명백방한법다같은다습니음첫과:다같▁the니첫습▁to▁the다음.

#!/usr/bin/node

하지만 그것은 효과가 없습니다.node명이설않다니에 ./usr/bin.

은 일인해방을 입니다.env명령(이 목적을 위해 의도되지 않은 명령):

#!/usr/bin/env node

스크립트가 호출된 경우foo운영 체제는 다음과 같은 작업을 수행합니다.

/usr/bin/env node foo

env명령은 명령줄에 이름이 지정된 다른 명령을 실행하여 해당 명령에 다음 인수를 전달합니다.여기에 사용되는 이유는env검색할 것입니다.$PATH명령을 위해.그래서 만약에node는 설치위에 됩니다./usr/local/bin/node,그리고 당신은 그렇게 했어요./usr/local/bin당신의$PATH,그env명령이 호출됩니다./usr/local/bin/node foo.

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

이 접근 방식에는 몇 가지 단점이 있습니다.대부분의 현대적인 유닉스 계열 시스템은 다음과 같습니다./usr/bin/env하지만 저는 오래된 시스템에서 일했습니다.env명령이 다른 디렉터리에 설치되었습니다.이 메커니즘을 사용하여 전달할 수 있는 추가 인수에는 제한이 있을 수 있습니다.사용자가 다음을 포함하는 디렉토리를 가지고 있지 않은 경우node에 대한 지휘권.$PATH또는 다른 명령을 사용합니다.node잘못된 명령을 호출하거나 전혀 작동하지 않을 수 있습니다.

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

  • 사용#!에 대한 전체 경로를 지정하는 선node명령 자체, 다양한 시스템에 필요한 스크립트 업데이트
  • 를 호출합니다.node스크립트를 인수로 사용하여 명령합니다.

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

덧붙여서, 내 시스템(리눅스 민트 17.2)에는 다음과 같이 설치되어 있습니다./usr/bin/nodejs내 메모에 따르면, 그것은 에서 바뀌었습니다./usr/bin/node로./usr/bin/nodejsUbuntu 12.04와 12.10 사이.#!/usr/bin/env(심링크나 유사한 것을 설정하지 않는 한) 트릭은 도움이 되지 않습니다.

업데이트: mtraceur의 코멘트는 다음과 같습니다(재포맷됨).

nodejs vs node 문제에 대한 해결 방법은 다음 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제공한 패키지node에 대한 상징으로서nodejs제가 모든 세부 사항을 정확하게 알고 있다는 보장은 없습니다.

exec리눅스 커널의 시스템 호출은 셰뱅을 이해합니다 (#!본바닥에서

bash에 할 때:

./something

리눅스에서, 이것은 다음을 부릅니다.exec경로를 사용한 시스템 호출./something.

커널의 이 줄은 전달된 파일에서 호출됩니다.exec: https://github.com/torvalds/linux/blob/v4.8/fs/binfmt_script.c#L25

if ((bprm->buf[0] != '#') || (bprm->buf[1] != '!'))

를 파일첫 의 번 바 이 읽 비 다 합 교 과 음 고 를 트 째 합 니 다 ▁it 비 ▁them#!.

의 나머지 리눅스 에 의해 구문 분석되며, 는 또 다른 비가참줄나커의리구분것, 만다것듭니을다고른이되석은을 .exec통화 내용:

  • 파일: 실행파:/usr/bin/env
  • 번째 인수: 첫번째인:node
  • 두 번째 인수: 스크립트 경로

따라서 다음과 같습니다.

/usr/bin/env node /path/to/script.js

env는 검하는실파다니입을 검색하는 입니다.PATH예를 들어 찾기/usr/bin/node그리고 마지막으로 전화를 합니다.

/usr/bin/node /path/to/script.js

Node에는 Node.js 파일이 됩니다.#!파일의 라인, 하지만 그 라인을 무시하도록 프로그래밍되어야 합니다.#일반적으로 노드에서 유효한 주석 문자가 아닙니다. 참고 항목: 파운드 기호(#) JavaScript에서 주석 시작?

예, 다음을 통해 무한 루프를 만들 수 있습니다.

printf '#!/a\n' | sudo tee /a
sudo chmod +x /a
/a

Bash가 다음 오류를 인식합니다.

-bash: /a: /a: bad interpreter: Too many levels of symbolic links

#!우연히 인간이 읽을 수 있지만, 그것은 필요하지 않습니다.

했다면, 그 은 파이다바시작다면했로트이른일,,exec시스템 호출에 다른 핸들러가 사용됩니다.다른 가장 중요한 내장 핸들러는 ELF 실행 파일을 위한 것입니다: https://github.com/torvalds/linux/blob/v4.8/fs/binfmt_elf.c#L1305 은 바이트를 확인합니다.7f 45 4c 46 수 (이것은는 또있수 것입니 다을읽 인한간 이▁(다▁(니이..ELF)의 첫 의 첫 번째 4바이트를 읽어 확인합니다./bin/lsELF 실행 파일입니다.

head -c 4 "$(which ls)" | hd 

출력:

00000000  7f 45 4c 46                                       |.ELF|
00000004                                                                 

그래서 커널은 이러한 바이트를 볼 때 ELF 파일을 가져와서 메모리에 올바르게 넣고 새로운 프로세스를 시작합니다.참고 항목:커널은 어떻게 리눅스에서 실행되는 실행 가능한 이진 파일을 얻습니까?

마지막으로, 당신은 당신 자신의 쉐방 핸들러를 추가할 수 있습니다.binfmt_misc기계 장치예를 들어 파일에 대한 사용자 정의 처리기를 추가할 수 있습니다.이 메커니즘은 파일 확장명별 핸들러도 지원합니다.또 다른 애플리케이션은 QEMU를 사용하여 다른 아키텍처의 실행 파일을 투명하게 실행하는 것입니다.

는 POSIX가 셰뱅을 명시하지 않았다고 생각합니다. https://unix.stackexchange.com/a/346214/32558 은 이론적인 섹션과 "시스템에서 실행 가능한 스크립트가 지원되면 어떤 일이 발생할 수 있습니다."라는 형식으로 언급하고 있지만 macOS와 FreeBSD도 이를 구현하는 것으로 보입니다.

PATH 동기

아마도, shebangs의 존재에 대한 한가지 큰 동기는 리눅스에서 우리가 종종 명령을 실행하기를 원한다는 사실입니다.PATH다음과 같이:

basename-of-command

다음 대신:

/full/path/to/basename-of-command

하지만 셰방 메커니즘이 없다면 리눅스가 각 유형의 파일을 실행하는 방법을 어떻게 알 수 있을까요?

다음 명령에서 확장을 하드코딩합니다.

 basename-of-command.js

또는 모든 인터프리터에서 PATH 검색 구현:

node basename-of-command

가능성이 있겠지만, 이것은 우리가 명령을 다른 언어로 재팩터링하기로 결정하면 모든 것이 깨지는 주요 문제를 가지고 있습니다.

그녀는 이 문제를 멋지게 해결합니다.

단답:그것은 통역사로 가는 길입니다.

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

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

언급URL : https://stackoverflow.com/questions/33509816/what-exactly-does-usr-bin-env-node-do-at-the-beginning-of-node-files

반응형