नोड.जेएस शेल कमांड निष्पादन


113

मैं अभी भी महीन बिंदुओं को समझने की कोशिश कर रहा हूं कि मैं एक लिनक्स या विंडोज शेल कमांड कैसे चला सकता हूं और नोड.जेएस के भीतर आउटपुट कैप्चर कर सकता हूं; आखिरकार, मैं ऐसा कुछ करना चाहता हूं ...

//pseudocode
output = run_command(cmd, args)

महत्वपूर्ण टुकड़ा यह है कि outputएक वैश्विक रूप से स्कूप्ड वैरिएबल (या ऑब्जेक्ट) के लिए उपलब्ध होना चाहिए। मैंने निम्नलिखित फ़ंक्शन की कोशिश की, लेकिन किसी कारण से, मैं undefinedकंसोल पर मुद्रित हो जाता हूं ...

function run_cmd(cmd, args, cb) {
  var spawn = require('child_process').spawn
  var child = spawn(cmd, args);
  var me = this;
  child.stdout.on('data', function(me, data) {
    cb(me, data);
  });
}
foo = new run_cmd('dir', ['/B'], function (me, data){me.stdout=data;});
console.log(foo.stdout);  // yields "undefined" <------

मुझे यह समझने में परेशानी हो रही है कि कोड ऊपर कहाँ टूटता है ... उस मॉडल का एक बहुत ही सरल प्रोटोटाइप काम करता है ...

function try_this(cmd, cb) {
  var me = this;
  cb(me, cmd)
}
bar = new try_this('guacamole', function (me, cmd){me.output=cmd;})
console.log(bar.output); // yields "guacamole" <----

क्या कोई मुझे यह समझने में मदद कर सकता है कि try_this()काम क्यों करता है, और run_cmd()क्या नहीं? FWIW, मुझे उपयोग करने की आवश्यकता है child_process.spawn, क्योंकि child_process.execइसमें 200KB बफर सीमा है।

अंतिम संकल्प

मैं जेम्स व्हाइट का जवाब स्वीकार कर रहा हूं, लेकिन यह सटीक कोड है जिसने मेरे लिए काम किया है ...

function cmd_exec(cmd, args, cb_stdout, cb_end) {
  var spawn = require('child_process').spawn,
    child = spawn(cmd, args),
    me = this;
  me.exit = 0;  // Send a cb to set 1 when cmd exits
  me.stdout = "";
  child.stdout.on('data', function (data) { cb_stdout(me, data) });
  child.stdout.on('end', function () { cb_end(me) });
}
foo = new cmd_exec('netstat', ['-rn'], 
  function (me, data) {me.stdout += data.toString();},
  function (me) {me.exit = 1;}
);
function log_console() {
  console.log(foo.stdout);
}
setTimeout(
  // wait 0.25 seconds and print the output
  log_console,
250);

2
अंतिम संकल्प में आप स्थापित करना चाहिए me.stdout = "";में cmd_exec()श्रृंखलाबद्ध को रोकने के लिए undefinedपरिणाम की शुरुआत करने के लिए।
aorcsik

अरे, वह अंतिम रिज़ॉल्यूशन कोड पूरी तरह से भयानक है, क्या होगा अगर आपके नेटस्टैट को निष्पादित करने में 0.25 सेकंड से अधिक समय लगे?
स्टीवन लू

उम्म्म ... शायद उन जवाबों में से एक का उपयोग करें जिन्हें मैंने बोनस दिया था ?????
माइक पेनिंगटन

जवाबों:


89

यहां तीन मुद्दे हैं जिन्हें ठीक करने की आवश्यकता है:

पहला यह है कि आप असमान रूप से stdout का उपयोग करते हुए तुल्यकालिक व्यवहार की उम्मीद कर रहे हैं। आपके run_cmdफ़ंक्शन में सभी कॉल अतुल्यकालिक हैं, इसलिए यह चाइल्ड प्रोसेस को स्पॉन करेगा और तुरंत डेटा वापस लौटाएगा चाहे कुछ, सभी या कोई भी डेटा स्टडआउट से पढ़ा नहीं गया हो। जैसे, जब आप दौड़ते हैं

console.log(foo.stdout);

आपको इस समय foo.stdout में संग्रहित किया जाना है और जो भी हो सकता है इसकी कोई गारंटी नहीं है क्योंकि आपके बच्चे की प्रक्रिया अभी भी चल रही होगी।

दूसरा यह है कि स्टडआउट एक पठनीय स्ट्रीम है , इसलिए 1) डेटा इवेंट को कई बार कहा जा सकता है, और 2) कॉलबैक को एक बफर दिया जाता है, न कि एक स्ट्रिंग। उपाय करने में आसान; बस बदल दो

foo = new run_cmd(
    'netstat.exe', ['-an'], function (me, data){me.stdout=data;}
);

में

foo = new run_cmd(
    'netstat.exe', ['-an'], function (me, buffer){me.stdout+=buffer.toString();}
);

ताकि हम अपने बफर को एक स्ट्रिंग में परिवर्तित कर सकें और उस स्ट्रिंग को अपने स्टडआउट वेरिएबल में जोड़ सकें।

तीसरा यह है कि आप केवल 'अंतिम' ईवेंट प्राप्त करने के बाद ही सभी आउटपुट प्राप्त कर सकते हैं, जिसका अर्थ है कि हमें दूसरे श्रोता और कॉलबैक की आवश्यकता है:

function run_cmd(cmd, args, cb, end) {
    // ...
    child.stdout.on('end', end);
}

तो, आपका अंतिम परिणाम यह है:

function run_cmd(cmd, args, cb, end) {
    var spawn = require('child_process').spawn,
        child = spawn(cmd, args),
        me = this;
    child.stdout.on('data', function (buffer) { cb(me, buffer) });
    child.stdout.on('end', end);
}

// Run C:\Windows\System32\netstat.exe -an
var foo = new run_cmd(
    'netstat.exe', ['-an'],
    function (me, buffer) { me.stdout += buffer.toString() },
    function () { console.log(foo.stdout) }
);

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

4
यह एक बहुत ही महत्वपूर्ण जेएस अवधारणाओं के महान स्पष्टीकरण के साथ एक उत्कृष्ट उत्तर है। अच्छा!
L0j1k

1
आप फंक्शन के this.stdout = "";अंदर करना चाहते हैं run(), अन्यथा आपके console.log(foo.sdtout);साथ प्रीफ़िक्स किया जाएगा undefined
f1lt3r

78

स्वीकृत उत्तर (तीसरा बिंदु) का एक सरलीकृत संस्करण, बस मेरे लिए काम किया।

function run_cmd(cmd, args, callBack ) {
    var spawn = require('child_process').spawn;
    var child = spawn(cmd, args);
    var resp = "";

    child.stdout.on('data', function (buffer) { resp += buffer.toString() });
    child.stdout.on('end', function() { callBack (resp) });
} // ()

उपयोग:

run_cmd( "ls", ["-l"], function(text) { console.log (text) });

run_cmd( "hostname", [], function(text) { console.log (text) });

1
वापसी मूल्य के बारे में क्या, जब प्रक्रिया एक शून्य शून्य लौटाती है, तो मैं इसे कैसे प्राप्त कर सकता हूं?
विटिम.स

2
child.stdout.on('close', (errCode) => { console.log(errCode) } )
तुषार गौतम

52

मैंने इसे और अधिक संक्षेप में उपयोग किया:

var sys = require('sys')
var exec = require('child_process').exec;
function puts(error, stdout, stderr) { sys.puts(stdout) }
exec("ls -la", puts);

यह पूरी तरह से काम करता है। :)


1
यह अच्छी तरह से काम करता है, और किसी भी अतिरिक्त नोड मॉड्यूल की आवश्यकता नहीं होती है। मुझें यह पसंद है!
बेवेरिन

9
sys.puts()2011 में पदावनत किया गया था (Node.js v0.2.3 के साथ)। आपको console.log()इसके बजाय उपयोग करना चाहिए ।
tfmontague

1
यह वास्तव में काम करता है ... तो मैं सोच रहा हूँ, यह जवाब क्यों नहीं है? यह इतना सरल है
एककिस

वाह!! यह उत्तर एकदम सही और सुरुचिपूर्ण है। धन्यवाद।
एमएम मधु

43

सबसे आसान तरीका सिर्फ शेलजेएस लिब का उपयोग करना है ...

$ npm install [-g] shelljs

EXEC उदाहरण:

require('shelljs/global');

// Sync call to exec()
var version = exec('node --version', {silent:true}).output;

// Async call to exec()
exec('netstat.exe -an', function(status, output) {
  console.log('Exit status:', status);
  console.log('Program output:', output);
});

ShellJs.org NodeJS फ़ंक्शन के रूप में मैप की गई कई सामान्य शेल कमांड का समर्थन करता है:

  • बिल्ली
  • सीडी
  • chmod
  • cp
  • dirs
  • गूंज
  • कार्यकारी
  • बाहर जाएं
  • खोज
  • ग्रेप
  • ln
  • ls
  • mkdir
  • mv
  • popd
  • pushd
  • लोक निर्माण विभाग
  • rm
  • sed
  • परीक्षा
  • कौन कौन से

शेल स्क्रिप्ट के लिए एक पैरामीटर कैसे जोड़ें जिसे शेल.एक्सईसी ("foo.sh") कहा जाता है?
छद्मोजाच

1
आप केवल अपने तर्कों को स्ट्रिंग के ऊपर जोड़ सकते हैं shell.exec("foo.sh arg1 arg2 ... "):। आपकी foo.shलिपि इनका उपयोग करके संदर्भ दे सकती है $1, $2... आदि
टोनी ओ'हागन

यदि आप जिस कमांड को निष्पादित करने का प्रयास कर रहे हैं, उसे उपयोगकर्ता से इनपुट की आवश्यकता है, तो शेलजेएस निष्पादन का उपयोग न करें ()। यह फ़ंक्शन प्रकृति में इंटरएक्टिव नहीं है, क्योंकि यह केवल कमांड और प्रिंट आउटपुट लेगा, बीच में इनपुट स्वीकार नहीं कर सकता। इसके बजाय child_process में निर्मित का उपयोग करें। जैसे https://stackoverflow.com/a/31104898/9749509
MPatel1

4

मुझे इसी तरह की समस्या थी और मैंने इसके लिए एक नोड एक्सटेंशन लिखना शुरू किया। आप गिट रिपॉजिटरी देख सकते हैं। यह खुला स्रोत और मुफ्त है और यह सब अच्छा सामान है!

https://github.com/aponxi/npm-execxi

ExecXI एक नोड एक्सटेंशन है जो C ++ में एक-एक करके शेल कमांड को निष्पादित करने के लिए लिखा गया है, जो कमांड के आउटपुट को रियल-टाइम में कंसोल में आउटपुट करता है। वैकल्पिक जंजीर, और अप्रकाशित तरीके मौजूद हैं; इसका अर्थ है कि आप कमांड के विफल होने (जंजीर) होने के बाद स्क्रिप्ट को रोकना चुन सकते हैं, या आप जारी रख सकते हैं जैसे कि कुछ भी नहीं हुआ है!

उपयोग निर्देश ReadMe फ़ाइल में हैं । पुल अनुरोध या मुद्दों को प्रस्तुत करने के लिए स्वतंत्र महसूस करो!

मुझे लगा कि यह उल्लेख के लायक है।


4

@ टोनीओ'हैगन एक व्यापक shelljsजवाब है, लेकिन, मैं उनके उत्तर के समकालिक संस्करण पर प्रकाश डालना चाहूंगा:

var shell = require('shelljs');
var output = shell.exec('netstat -rn', {silent:true}).output;
console.log(output);


0

आपके run_cmdफ़ंक्शन में एक चर संघर्ष है :

  var me = this;
  child.stdout.on('data', function(me, data) {
    // me is overriden by function argument
    cb(me, data);
  });

बस इसे इसे बदलें:

  var me = this;
  child.stdout.on('data', function(data) {
    // One argument only!
    cb(me, data);
  });

त्रुटियों को देखने के लिए हमेशा इसे जोड़ें:

  child.stderr.on('data', function(data) {
      console.log( data );
  });

संपादित करें आप कोड विफल हैं क्योंकि आप चलाने की कोशिश कर रहे हैं dirजो एक अलग स्टैंडअलोन कार्यक्रम के रूप में प्रदान नहीं किया गया है। यह cmdप्रक्रिया में एक कमांड है । यदि आप फाइलसिस्टम के साथ खेलना चाहते हैं तो देशी का उपयोग करें require( 'fs' )

वैकल्पिक रूप से (जो मैं अनुशंसा नहीं करता हूं) आप एक बैच फ़ाइल बना सकते हैं जिसे आप तब चला सकते हैं। ध्यान दें कि डिफ़ॉल्ट रूप से बैच फ़ाइलों के माध्यम से ओएस cmd


आपकी मदद के लिए धन्यवाद ... हालांकि, जब भी मैं दौड़ता हूं, तब C:\Windows\System32\netstat.exeभी यह परिणाम नहीं देता है ... मेरा सटीक सिंटैक्स था foo = new run_cmd('netstat.exe', ['-an'], function (me, data){me.stdout=data;});... मैंने अब तक बिना किसी सफलता के साथ पूरा रास्ता आज़माया
माइक पेनिंगटन

0

आप वास्तव में अपने run_cmd फ़ंक्शन से कुछ भी नहीं लौटा रहे हैं।

function run_cmd(cmd, args, done) {
    var spawn = require("child_process").spawn;
    var child = spawn(cmd, args);
    var result = { stdout: "" };
    child.stdout.on("data", function (data) {
            result.stdout += data;
    });
    child.stdout.on("end", function () {
            done();
    });
    return result;
}

> foo = run_cmd("ls", ["-al"], function () { console.log("done!"); });
{ stdout: '' }
done!
> foo.stdout
'total 28520...'

ठीक काम करता है। :)


मुझे नहीं लगता कि returnजब तक आप उचित रूप से ऑब्जेक्ट विशेषताओं को निर्धारित नहीं करते हैं
माइक पेनिंगटन

0

बहुप्रतिक्षित उत्तर का एक अनुमानित संस्करण:

  runCmd: (cmd, args) => {
    return new Promise((resolve, reject) => {
      var spawn = require('child_process').spawn
      var child = spawn(cmd, args)
      var resp = ''
      child.stdout.on('data', function (buffer) { resp += buffer.toString() })
      child.stdout.on('end', function () { resolve(resp) })
    })
  }

काम में लाना:

 runCmd('ls').then(ret => console.log(ret))
हमारी साइट का प्रयोग करके, आप स्वीकार करते हैं कि आपने हमारी Cookie Policy और निजता नीति को पढ़ और समझा लिया है।
Licensed under cc by-sa 3.0 with attribution required.