Universal Node.js shebang?


42

Node.js 는 요즘 매우 인기가 있으며 스크립트를 작성하고 있습니다. 불행히도 호환성은 문제입니다. 공식적으로 Node.js 인터프리터는이라고 불리지 node만 데비안과 우분투는 nodejs대신에 실행 파일을 제공 합니다.

Node.js가 가능한 한 많은 상황에서 작동 할 수있는 이식 가능한 스크립트를 원합니다. filename이이라고 가정하면 foo.js스크립트가 두 가지 방식으로 실행되기를 정말로 원합니다.

  1. ./foo.js스크립트를 실행하는 경우 중 하나 node또는 nodejs이다 $PATH.
  2. node foo.js또한 스크립트를 실행합니다 (통역사가라고 가정 node).

참고 : xavierm02와 본인의 답변은 폴리 글롯 스크립트의 두 가지 변형입니다. 나는 그것이 존재한다면 순수한 shebang 솔루션에 여전히 관심이 있습니다.


빌드 시스템에서 임의로 실행 파일 이름을 지정할 수 있기 때문에 이것에 대한 진정한 해결책은 없다고 생각합니다. 파이썬 인터프리터를 alphacentauri로 명명하는 것을 막는 것은 없으며, 규칙을 따르고 이름을 python으로 지정하면됩니다. node스크립트의 표준 이름 을 사용 하거나 shebang을 수정하는 일종의 make 스크립트를 사용하는 것이 좋습니다 .

@ G.Kayaalp 정치와 관습을 제외하고는 데비안 / 우분투 / 페도라 사용자가 많이 있으며, 그들에게 적합한 스크립트를 만들고 싶습니다. 이것을 위해 빌드 시스템을 설정하고 싶지 않습니다 (누가 쉘 스크립트를 실행하기 전에 빌드합니까?) alphacentauri. 이라는 실행 파일이 있으면 nodejsNode.js인지 99 % 확신 할 수 있습니다. 왜 모두 지원 nodejs과를 node?
dancek

nodejs-legacy 패키지를 설치하십시오. 이것이 필요한 이유는 이름이 너무 거만해서 다른 사람이 먼저 이름을 얻었 기 때문입니다. 그러나 다른 패키지는 그 이름을 기꺼이 공유했습니다.
user3710044

답변:


54

내가 생각해 낸 최선은 실제로 폴리 글롯 (Bourne shell / Node.js) 스크립트 인이 "2 줄 shebang"입니다.

#!/bin/sh
':' //; exec "$(command -v nodejs || command -v node)" "$0" "$@"

console.log('Hello world!');

첫 번째 줄은 분명히 Bourne shell shebang입니다. Node.js는 찾은 shebang을 우회하므로 Node.js에 관한 한 유효한 Javascript 파일입니다.

두 번째 줄은 쉘에는 조합 호출되지 :인수와를 //실행 한 후 및 nodejs또는 node매개 변수로이 파일의 이름으로. 이식성 command -v대신에 사용됩니다 which. 명령 대체 구문 $(...)은 엄격하게 Bourne이 아니므로 1980 년대에이를 실행하려면 백틱을 선택하십시오.

Node.js ':'는 no-op와 같은 문자열을 평가하고 나머지 줄은 주석으로 구문 분석합니다.

파일의 나머지 부분은 평범한 오래된 자바 스크립트입니다. exec두 번째 행이 완료된 후 서브 쉘이 종료되므로 쉘이 나머지 파일을 읽지 않습니다.

영감을 얻은 xavierm02와 추가 정보를 제공하는 모든 주석 자에게 감사드립니다!


1
훌륭한 솔루션. ':'접근 방식 의 대안은 다음과 같은 방법을 사용 // 2>/dev/null하는 것입니다 nvm. bash는 오류 ( bash: //: Is a directory)이며 리디렉션은 2>/dev/null조용히 무시합니다. JavaScript에서는 전체 줄이 주석이됩니다. 또한-이것이 문제가 될 것으로 기대하지 않습니다 command. IRL- -v실제로 호출하지는 않지만 쉘 함수와 별칭을보고하는 단점이 있습니다. 따라서 쉘 함수 나 별명 ( 또는 shopt -s expand_aliases)이라는 이름 을 내 보낸 경우에는 문제가 발생할 수 있습니다 . nodenodejs
mklement0

1
음, POSIX 쉬는 (솔라리스 / 빈 / sh를 제외하고 - 그러나 솔라리스는 POSIX 호환되는 상자 밖으로 KSH AT & T와 함께 않음) 요즘 유비 쿼터스, 그리고 마르쿠스 쿤 권장 그것을 떨어져 유지하기 위해 (칭의와 함께). 이럴 필요 없어요 . 그러나 예, 그것은을위한 충분 mksh, bash, dash현대 유닉스와 GNU 시스템 및 기타 포탄입니다.
mirabilos

1
훌륭한 솔루션; ( en.wikipedia.org/wiki/Shebang_%28Unix%29#Portability ) #!/usr/bin/env sh대신에 더 이식성이 #!/bin/sh
뛰어나지 만

2
나는 #!/usr/bin/env sh"더 휴대하기 쉬운" 광고 를 조심할 것 입니다. 같은 위키 백과 문서의하지 멋진 승인 그건, 내 생각 엔 당신이없는 시스템으로 실행하는 것이 오 "... 경로는 / usr / 빈은 / ENV 일반적으로 ENV 유틸리티에 사용되기 때문에이 대부분 작동합니다"라고 /usr/bin/env더 자주 이상 /bin/sh주파수에 전혀 차이가 없다면 , 없이 시스템을 실행 합니다.
sheldonh

1
@dancek 2018 년부터 안녕하세요 //bin/sh -c :; exec ..., 두 번째 줄의 깔끔한 버전 이 아니 겠습니까?
har-wradim

10
#!/bin/sh
//bin/false || `which node || which nodejs` << `tail -n +2 $0`
console.log('ok');

//bin/false/bin/false두 번째 슬래시가 노드에 대한 주석으로 변환한다는 점을 제외 하면 마찬가지 입니다. 이것이 바로 여기에 있습니다. 그런 다음 첫 번째의 오른쪽 ||이 평가됩니다. 'which node || which nodejs'따옴표 대신 역 따옴표를 사용하면 노드가 시작 <<되고 오른쪽에있는 모든 것을 피드합니다. 나는 //dancek처럼 시작하여 구분 기호를 사용할 수 있었지만 효과가 있었지만 처음에는 두 줄만있는 것이 더 깨끗하므로 tail -n +2 $0처음 두 줄을 제외하고 파일 자체를 읽었습니다.

그리고 노드에서 실행하면 첫 번째 줄은 shebang으로 인식되고 무시되고 두 번째 줄은 한 줄 주석입니다.

(분명히 sed 는 첫 번째와 마지막 줄없이 꼬리 인쇄 파일 내용 을 대체하는 데 사용될 수 있습니다 )


편집 전 답변 :

#!/bin/sh
`which node || which nodejs` <<__HERE__
console.log('ok');
__HERE__

원하는 것을 할 수 없으므로 대신 쉘 스크립트를 실행하십시오 #!/bin/sh. 해당 쉘 스크립트는 노드를 실행하는 데 필요한 파일의 경로를 가져옵니다 which node || which nodejs. 백 쿼트는 여기에 실행되도록 'which node || which nodejs'따옴표 대신 백 따옴표로 노드를 호출합니다. 그런 다음을 사용하여 스크립트를 제공합니다 <<. 은 __HERE__당신의 스크립트의 구분 기호입니다. 그리고 이것은 console.log('ok');스크립트로 바꿔야하는 스크립트의 예입니다.


설명은 좋을 것입니다
0xC0000022L

실행하기 전에 JavaScript 코드에서 매개 변수 확장, 명령 대체 및 산술 확장을 수행하지 않으려면 여기 문서 분리 문자를 더 잘 인용하십시오 <<'__HERE__'.
manatwork

재미 있어요! 하지만이 //bin/false내 MSYS 환경에서 작동하지 않습니다, 그리고 내와 역 따옴표 따옴표 필요 node에 상주 C:\Program Files\.... 예, 저는 끔찍한 환경에서 일합니다 ...
dancek

1
//bin/falseMac OS X에서도 작동하지 않습니다. 죄송하지만 더 이상 휴대하기가 쉽지 않습니다.
dancek

2
which명령은 이식성이 없습니다.
jordanm

9

이는 정책이 의미가있는 데비안 기반 시스템에서만 발생하는 문제입니다.

Fedora가 언제 nodejs라는 바이너리를 제공했는지 모르지만 그것을 보지 못했습니다. 패키지는 nodejs라고하며 node라는 바이너리를 설치합니다.

데비안 기반 시스템에 상식을 적용하기 위해 심볼릭 링크를 사용하면 제정신을 사용할 수 있습니다. 다른 사람들은 어쨌든 제정신 세방을 사용하게 될 것이므로, 그 심볼릭 링크가 필요할 것입니다.

#!/usr/bin/env node

console.log("Spread the love.");

죄송하지만이 질문에 대한 답변은 아닙니다. 나는 정치적 관점을 이해하지만, 여기서는 그렇지 않습니다.
dancek

기록을 위해 일부 Fedora 시스템에는 nodejs실행 파일 이 있지만 이는 Fedora의 결함이 아닙니다. 사실을 잘못 알려서 죄송합니다.
dancek

8
사과 할 필요가 없습니다. 당신 말이 맞아요 응답이 귀하의 질문에 답변하지 않습니다. 귀하의 질문에 답변하여 질문 범위가 사용 가능한 것보다 덜 유용한 솔루션으로 제한됨을 제안합니다. 나는 역사에 의해 실질적인 조언을 제공하고 있습니다. 노드는 여기에서 처음으로 해석하는 것이 아닙니다. Larry Wall이 펄 셰 방이 반드시 있어야한다고 선언 한 동요를 보았을 것 #!/usr/bin/perl입니다. 즉, 당신은 내 제안을 좋아하거나 적용 할 의무가 없습니다. 평화.
sheldonh

3

작은 .sh파일을 만드는 것이 마음에 들지 않으면 약간의 해결책이 있습니다. 사용할 쉘 실행 파일을 판별하기 위해 작은 쉘 스크립트를 작성하고 shebang에서이 스크립트를 사용할 수 있습니다.

shebang.sh :

#!/bin/sh
`which node || which nodejs` $@

script.js :

#!./shebang.sh
console.log('hello');

실행 파일을 모두 표시하고를 실행하십시오 ./script.js.

이 방법으로 폴리 글로 팅 스크립팅을 피할 수 있습니다. 나는 그것이 좋은 생각처럼 보이지만 여러 shebang 라인을 사용할 수 있다고 생각하지 않습니다.

이렇게하면 원하는 방식으로 문제가 해결되지만 아무도 신경 쓰지 않는 것 같습니다. 예를 들어, uglifyjscoffeescript 는을 사용하고 #!/usr/bin/env node, npm 은 쉘 스크립트를 시작점으로 사용하며, 다시 name으로 실행 파일을 명시 적으로 호출합니다 node. 나는 우분투 사용자이며 항상 노드를 컴파일 할 때 이것을 알지 못했습니다. 나는 이것을 버그로보고하려고합니다.


최소한 사용자에게 chmod +xsh 스크립트 를 요청해야한다고 확신합니다 ... 따라서 노드 실행 파일에 위치를 제공하는 변수를 설정하도록 요청할 수도 있습니다 ...
xavierm02

@ xavierm02 스크립트 chmod +x'd를 해제 할 수 있습니다 . 그리고 NODE 변수가보다 낫습니다 which node || which nodejs. 그러나 많은 주요 노드 프로젝트가 단지 사용하지만, 지망생은 즉시 사용 가능한 경험을 제공하려고합니다 #!/usr/bin/env node.

1

완전성을 위해 두 번째 줄을 수행하는 다른 두 가지 방법이 있습니다.

// 2>/dev/null || echo yes
false //|| echo yes

그러나 선택한 답변보다 이점이 없습니다.

':' //; || echo yes

또한 둘 중 하나 node또는 nodejs둘 다를 찾을 수 있음 을 알고 있으면 다음과 같이 작동합니다.

exec `command -v node nodejs` "$0" "$@"

그러나 그것은 큰 "만약"이므로, 선택된 답변이 가장 좋은 답변이라고 생각합니다.


또한, 당신은 어떤 실행할 수 foobar // 2>/dev/null대로만큼을 foobar명령하지 않습니다. 그리고 POSIX 시스템에있는 많은 유틸리티//인수 와 함께 실행할 수 있습니다 .
dancek

1

나는 이것이 그 질문에 대한 답이 아니라는 것을 이해하지만, 그 질문에 잘못된 전제가 있다고 확신한다.

우분투가 잘못되었습니다. 자체 스크립트를 위해 범용 shebang을 작성해도 사실상의 표준을 사용하는 제어 권한이없는 다른 패키지는 변경되지 않습니다 #!/usr/bin/env node. nodejs를 대상으로하는 스크립트가 실행되도록 하려면 시스템 node에서 제공 해야PATH 합니다.

예를 들어, Ubuntu 제공 npm패키지 조차 패키지에서 shebang을 다시 쓰지 않습니다.

$ cd
$ rm -rf test_npm
$ mkdir test_npm
$ cd test_npm
$ npm install mkdirp 2>&1 | grep -ve home
`-- mkdirp@0.5.1
  `-- minimist@0.0.8

npm WARN test_npm No description
npm WARN test_npm No repository field.
npm WARN test_npm No README data
npm WARN test_npm No license field.
$ node_modules/.bin/mkdirp testdir
/usr/bin/env: 'node': No such file or directory
$ head -n1 node_modules/.bin/mkdirp
#!/usr/bin/env node
$ npm --version
3.5.2
$ cat /etc/lsb-release
DISTRIB_ID=Ubuntu
DISTRIB_RELEASE=16.04
DISTRIB_CODENAME=xenial
DISTRIB_DESCRIPTION="Ubuntu 16.04.2 LTS"
당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.