यूनिवर्सल Node.js शेबंग?


42

Node.js इन दिनों बहुत लोकप्रिय है और मैं इस पर कुछ स्क्रिप्ट लिख रहा हूं। दुर्भाग्य से, संगतता एक समस्या है। आधिकारिक तौर पर, Node.js दुभाषिया को बुलाया जाना चाहिए node, लेकिन डेबियन और उबंटू एक निष्पादन योग्य जहाज को कहते nodejsहैं।

मैं पोर्टेबल स्क्रिप्ट चाहता हूं जो Node.js जितनी संभव हो उतनी स्थितियों में काम कर सके। मान लिया गया कि फ़ाइल नाम है foo.js, मैं वास्तव में स्क्रिप्ट को दो तरीकों से चलाना चाहता हूं:

  1. ./foo.jsस्क्रिप्ट चलाता है nodeया तो या nodejsमें है $PATH
  2. node foo.jsस्क्रिप्ट भी चलाता है (दुभाषिया कहा जाता है node)

नोट: xavierm02 और स्वयं के उत्तर बहुविकल्पी लिपि के दो रूप हैं। मैं अभी भी एक शुद्ध शेबंग समाधान में दिलचस्पी रखता हूं, अगर ऐसा मौजूद है।


मुझे लगता है कि इसका कोई वास्तविक समाधान नहीं है, क्योंकि किसी को निर्माण प्रणालियों द्वारा मनमाने ढंग से निष्पादन योग्य नाम देने की अनुमति है। ऐसा कुछ भी नहीं है जो आपको अजगर इंटरप्रेटर अल्‍पसेंटौरी का नाम रखने से रोकता है, आप बस परंपराओं का पालन करते हैं और इसे अजगर का नाम देते हैं। मैं nodeआपकी स्क्रिप्ट के लिए या तो मानक नाम का उपयोग करने का सुझाव दूंगा, या एक प्रकार की स्क्रिप्ट बनाऊंगा जो कि शबंग को संशोधित करता है।

@ G.Kalalp राजनीति और परंपराएँ एक तरफ, बहुत सारे डेबियन / उबंटू / फेडोरा उपयोगकर्ता हैं, और मैं उनके लिए काम करने वाली स्क्रिप्ट बनाना चाहता हूं। मैं इसके लिए एक बिल्ड सिस्टम सेटअप नहीं करना चाहता (जो भी उन्हें चलाने से पहले शेल स्क्रिप्ट बनाता है?), और न ही मैं alphacentauriइस तरह का समर्थन करना चाहता हूं । यदि कोई निष्पादन योग्य कहा जाता है nodejs, तो आप 99% सुनिश्चित हो सकते हैं कि यह Node.js. क्यों दोनों का समर्थन नहीं nodejsऔर node?
नृत्य

नोडज-लीगेसी पैकेज स्थापित करें। इसकी आवश्यकता यह है कि नाम बहुत ही सामान्य रूप से सामान्य है, किसी और को पहले नाम मिला है। हालांकि, अन्य पैकेज नाम साझा करने के लिए तैयार था।
user3710044

जवाबों:


54

सबसे अच्छी बात यह है कि यह "टू-लाइन शबंग" है जो वास्तव में एक पॉलीग्लॉट (बॉर्न शेल / नोड.जेएस) स्क्रिप्ट है:

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

console.log('Hello world!');

पहली पंक्ति, जाहिर है, एक बॉर्न शेल शेबंग है। Node.js किसी भी शेबबैन को बायपास कर देता है जो उसे मिल जाता है, इसलिए यह एक वैध जावास्क्रिप्ट फ़ाइल है जहाँ तक Node.js का संबंध है।

दूसरी पंक्ति :तर्क के साथ शेल को op नहीं कहती है //और फिर पैरामीटर के रूप में इस फ़ाइल के नाम के साथ nodejsया निष्पादित करती है node। पोर्टेबिलिटी command -vके whichलिए उपयोग किया जाता है। कमांड प्रतिस्थापन सिंटैक्स $(...)सख्ती से बॉर्न नहीं है, इसलिए यदि आप इसे 1980 के दशक में चलाते हैं तो बैकटिक्स का विकल्प चुनें।

Node.js केवल स्ट्रिंग का मूल्यांकन करता है ':', जो एक नो-ऑप की तरह है, और शेष पंक्ति को टिप्पणी के रूप में पार्स किया गया है।

फ़ाइल का बाकी हिस्सा सिर्फ पुरानी पुरानी जावास्क्रिप्ट है। execदूसरी पंक्ति पूरी होने के बाद सबस्क्रिप्शन क्विट हो जाता है, इसलिए शेष फ़ाइल शेल द्वारा कभी नहीं पढ़ी जाती है।

अतिरिक्त जानकारी के लिए प्रेरणा और सभी टिप्पणीकारों के लिए xavierm02 का धन्यवाद!


1
महान समाधान। ':'दृष्टिकोण का एक विकल्प का उपयोग करना है // 2>/dev/null(जो कि क्या nvmकरता है): बैश करने के लिए, यह एक त्रुटि ( bash: //: Is a directory) है, जिसे पुनर्निर्देशन 2>/dev/nullचुपचाप अनदेखा करता है; जावास्क्रिप्ट के लिए, पूरी लाइन एक टिप्पणी बन जाती है। इसके अलावा - और मुझे यह उम्मीद नहीं है कि यह एक समस्या है IRL - commandमें एक विचित्रता है जहां यह शेल फ़ंक्शन और उपनाम के साथ भी रिपोर्ट करता है -v- भले ही यह वास्तव में उन्हें आमंत्रित नहीं करेगा। इस प्रकार, यदि आप निर्यात खोल कार्यों या यहाँ तक कि उपनाम (यह मानते हुए हैं तो आप shopt -s expand_aliases) का नाम nodeया nodejs, चीजों को तोड़ सकते थे।
mklement0

1
वैसे, इन दिनों POSIX sh सर्वव्यापी है (Solaris / bin / sh को छोड़कर) लेकिन Solaris AT & T ksh बॉक्स से बाहर आता है, जो POSIX संगत है), और Markus Kuhn इसे बंद रखने के लिए (औचित्य के साथ) अनुशंसा करते हैं। IMHO आपको इसकी कभी आवश्यकता नहीं है। लेकिन हाँ, इसके लिए काफी है mksh, bash, dashआधुनिक यूनिक्स और GNU प्रणालियों में और अन्य गोले।
मीराबिलोस

1
महान समाधान; हालांकि और भी अधिक पोर्टेबल उपयोग करने के लिए किया जाएगा #!/usr/bin/env shके बजाय #!/bin/sh(प्रति en.wikipedia.org/wiki/Shebang_%28Unix%29#Portability )
user7089

2
मैं #!/usr/bin/env sh"अधिक पोर्टेबल" के रूप में विज्ञापन के बारे में सावधान रहूंगा। वही विकिपीडिया लेख कहता है "यह ज्यादातर इसलिए काम करता है क्योंकि पथ / usr / bin / env का उपयोग आमतौर पर env यूटिलिटी के लिए किया जाता है ..." यह एक अद्भुत समर्थन नहीं है, और मेरा अनुमान है कि आप सिस्टम में /usr/bin/envअधिक से अधिक बार बिना भाग लेंगे /bin/shअगर आप फ्रीक्वेंसी में कोई अंतर रखते हैं तो आप बिना सिस्टम के चलते हैं ।
शेल्डन

1
2018 से @dancek हाय, //bin/sh -c :; exec ...दूसरी पंक्ति का क्लीनर संस्करण नहीं होगा ?
हर-वादीम

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

//bin/falseएक ही बात है कि /bin/falseसिवाय इसके कि दूसरा स्लैश इसे नोड के लिए एक टिप्पणी में बदल देता है, और यही कारण है कि यह यहाँ है। फिर, पहले के दाहिने हिस्से का ||मूल्यांकन किया जाता है। 'which node || which nodejs'उद्धरण के बजाय backquotes के साथ नोड लॉन्च करता है और <<जो कुछ भी दाईं ओर है उसे फ़ीड करता है। मैं एक सीमांकक का उपयोग कर सकता //था जैसे कि डांसक ने शुरू किया, यह काम करेगा लेकिन मुझे लगता है कि शुरुआत में केवल दो पंक्तियाँ थीं, इसलिए मैंने tail -n +2 $0पहले दो पंक्तियों को छोड़कर फ़ाइल को स्वयं पढ़ा था।

और यदि आप इसे नोड में चलाते हैं, तो पहली पंक्ति को एक शबंग के रूप में पहचाना जाता है और अनदेखा किया जाता है और दूसरा एक-पंक्ति टिप्पणी है।

(जाहिरा तौर पर, पहली और आखिरी लाइनों के बिना पूंछ प्रिंट फ़ाइल सामग्री को बदलने के लिए 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

बेहतर है कि पैरामीटर-विस्तार, कमांड प्रतिस्थापन और अंकगणितीय विस्तार से बचने के लिए जावास्क्रिप्ट-कोड पर निष्पादन से पहले दस्तावेज़-दस्तावेज़ परिसीमन <<'__HERE__':।
मैनटवर्क

यह दिलचस्प हो रहा है! यद्यपि //bin/falseमेरे MSYS वातावरण में काम नहीं करता है, और मुझे अपने nodeनिवास स्थान पर बैकटिक्स के आसपास उद्धरणों की आवश्यकता है C:\Program Files\...। हाँ, मैं एक भयानक माहौल में काम करता हूँ ...
नृत्य

1
//bin/falseमैक ओएस एक्स पर काम नहीं करता है, या तो। मुझे क्षमा करें, लेकिन यह अब बहुत पोर्टेबल नहीं लगता है।
नृत्य

2
whichआदेश भी पोर्टेबल नहीं है।
जोर्डन

9

यह केवल डेबियन-आधारित प्रणालियों पर एक समस्या है, जहां नीति समझदारी से अधिक है।

मुझे नहीं पता कि फेडोरा ने नोडज नामक बाइनरी कब प्रदान की, लेकिन मैंने इसे कभी नहीं देखा। पैकेज को नोडज कहा जाता है और यह बाइनरी नामक नोड स्थापित करता है।

बस अपने डेबियन-आधारित सिस्टम में सामान्य ज्ञान को लागू करने के लिए एक सिमलिंक का उपयोग करें, और फिर आप एक सने शबंग का उपयोग कर सकते हैं। अन्य लोग वैसे भी सगे शबंग का उपयोग कर रहे होंगे, इसलिए आपको उस सिम्बलिन की आवश्यकता होगी।

#!/usr/bin/env node

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

मुझे क्षमा करें, लेकिन यह प्रश्न का उत्तर नहीं देता है। मैं राजनीतिक दृष्टिकोण को समझता हूं, लेकिन यहां वह बात नहीं है।
8

रिकॉर्ड के लिए, कुछ फेडोरा सिस्टम में एक nodejsनिष्पादन योग्य है , लेकिन यह फेडोरा की गलती नहीं है। तथ्य को गलत तरीके से पेश करने के लिए क्षमा करें।
नृत्य

8
माफी मांगने की जरूरत नहीं है। आप बिल्कुल सही हैं। मेरी प्रतिक्रिया आपके प्रश्न का उत्तर नहीं देती है। यह आपके प्रश्न को बोलता है, यह सुझाव देता है कि प्रश्न उपलब्ध होने की तुलना में कम उपयोगी समाधानों की गुंजाइश है। मैं इतिहास द्वारा सूचित व्यावहारिक सलाह दे रहा हूं। नोड खुद को यहां खोजने वाला पहला दुभाषिया नहीं है। आपने लैरी वॉल को यह घोषणा करते हुए देखा होगा कि पर्ल शेबंग मस्ट होना चाहिए #!/usr/bin/perl। उस ने कहा, आप मेरे सुझावों को पसंद या लागू करने के लिए बाध्य नहीं हैं। शांति।
शेल्डन

3

यदि आप एक छोटी .shफ़ाइल बनाने में कोई आपत्ति नहीं करेंगे , तो मैं आपके लिए एक छोटा सा उपाय है। आप यह निर्धारित करने के लिए कि किस नोड का उपयोग करने के लिए निष्पादन योग्य थोड़ा शेल स्क्रिप्ट बना सकते हैं, और इस स्क्रिप्ट को अपने शेलबैंग में उपयोग कर सकते हैं:

shebang.sh :

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

script.js :

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

दोनों निष्पादन योग्य को चिह्नित करें, और चलाएं ./script.js

इस तरह, आप पॉलीग्लॉट स्क्रिप्टिंग से बच जाते हैं। मुझे नहीं लगता कि कई शेबंग लाइनों का उपयोग करना संभव है, हालांकि यह एक अच्छा विचार है।

यद्यपि यह समस्या को आपके इच्छित तरीके से हल करता है, लेकिन ऐसा लगता है कि कोई भी इस बारे में परवाह नहीं करता है। उदाहरण के लिए, uglifyjs और coffeescript का उपयोग करता है #!/usr/bin/env node, NPM एक प्रवेश बिंदु है, जो फिर से नाम के साथ स्पष्ट रूप से निष्पादन योग्य कॉल के रूप में एक खोल स्क्रिप्ट का उपयोग करता है node। मैं एक उबंटू उपयोगकर्ता हूं, और मुझे यह नहीं पता था कि मैं हमेशा नोड संकलन करता हूं। मैं इसे बग के रूप में रिपोर्ट करने पर विचार कर रहा हूं।


मुझे पूरा यकीन है कि आपको कम से कम उपयोगकर्ता को chmod +xsh स्क्रिप्ट पर पूछना होगा ... इसलिए आप उन्हें अपने नोड को निष्पादित करने के लिए स्थान देने वाला एक चर सेट करने के लिए कह सकते हैं ...
xavierm02

@ xavierm02 कोई भी स्क्रिप्ट जारी कर सकता है chmod +xd। और मैं एक 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 सिस्टम पर पाई जाने वाली उपयोगिताओं में से कई को //तर्क के साथ चलाया जा सकता है।
11

1

मैं समझता हूं कि यह प्रश्न का उत्तर नहीं देता है, लेकिन मैं आश्वस्त हूं कि प्रश्न को झूठे आधार के साथ पूछा गया है।

उबंटू यहां गलत है। अपनी खुद की स्क्रिप्ट के लिए एक सार्वभौमिक शेबंग लिखना अन्य संकुल को नहीं बदलेगा, जिस पर आपका कोई नियंत्रण नहीं है, जिसके वास्तविक मानक का उपयोग करें #!/usr/bin/env node। आपका सिस्टम चाहिए प्रदान nodeमें PATHअगर यह लक्षित कर NodeJS उस पर चलाने के लिए किसी भी स्क्रिप्ट के लिए चाहता है।

उदाहरण के लिए, उबंटू-प्रदान किए गए npmपैकेज पैकेजों में शेलबैंग को भी नहीं लिखते हैं:

$ 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"
हमारी साइट का प्रयोग करके, आप स्वीकार करते हैं कि आपने हमारी Cookie Policy और निजता नीति को पढ़ और समझा लिया है।
Licensed under cc by-sa 3.0 with attribution required.