Node.js बच्चे की प्रक्रिया को रोकते हैं और टर्मिनल आउटपुट को लाइव करते हैं


113

मेरे पास एक स्क्रिप्ट है जो 'हाय' को आउटपुट करती है, एक सेकंड के लिए सोती है, 'हाय' को आउटपुट करती है, 1 सेकंड के लिए सोती है, और इसी तरह आगे भी। अब मैंने सोचा कि मैं इस मॉडल के साथ इस समस्या से निपटने में सक्षम हूं।

var spawn = require('child_process').spawn,
temp    = spawn('PATH TO SCRIPT WITH THE ABOVE BEHAVIOUR');

temp.stdout.pipe(process.stdout);

अब समस्या यह है कि आउटपुट को प्रदर्शित करने के लिए कार्य को पूरा करने की आवश्यकता है। जैसा कि मैं इसे समझ रहा हूं, यह इस तथ्य के कारण है कि नव स्पंदित प्रक्रिया निष्पादन नियंत्रण लेती है। जाहिर है नोड। जे एस किसी भी समाधान का समर्थन नहीं करता है? मेरा विचार संभवतः दो उदाहरणों को चलाना था, पहला जो कार्य को बनाने के विशिष्ट उद्देश्य के लिए था और यह दूसरी आवृत्ति की प्रक्रिया के लिए आउटपुट को पाइप करता है, यह देखते हुए कि इसे प्राप्त किया जा सकता है।


1
यदि बाल प्रक्रिया लिखी गई है, pythonतो -uकंसोल कंसोल आउटपुट को बफर न करने के लिए इसके लिए झंडा पास करना न भूलें , अन्यथा ऐसा लगेगा कि स्क्रिप्ट लाइव नहीं है stackoverflow.com/a/49947671/906265
Aivaras

किसी और चीज़ के बजाय npmjs.com/package/cross-spawn का उपयोग करें । यह बेहतर है।
एंड्रयू कोस्टर

जवाबों:


92

मैं अभी भी अपने पैरों को Node.js के साथ गीला कर रहा हूं, लेकिन मेरे पास कुछ विचार हैं। पहले, मेरा मानना ​​है कि आपको execFileइसके बजाय उपयोग करने की आवश्यकता है spawn; execFileउस समय के लिए होता है जब आपके पास एक स्क्रिप्ट के लिए रास्ता होता spawnहै , जबकि एक प्रसिद्ध कमांड को निष्पादित करने के लिए होता है जो Node.js आपके सिस्टम पथ के खिलाफ हल कर सकता है।

1. बफ़र्ड आउटपुट को संसाधित करने के लिए कॉलबैक प्रदान करें :

var child = require('child_process').execFile('path/to/script', [ 
    'arg1', 'arg2', 'arg3', 
], function(err, stdout, stderr) { 
    // Node.js will invoke this callback when process terminates.
    console.log(stdout); 
});  

2. एक श्रोता को बाल प्रक्रिया में जोड़ें 'stdout stream ( 9thport.net )

var child = require('child_process').execFile('path/to/script', [ 
    'arg1', 'arg2', 'arg3' ]); 
// use event hooks to provide a callback to execute when data are available: 
child.stdout.on('data', function(data) {
    console.log(data.toString()); 
});

इसके अलावा, ऐसे विकल्प दिखाई देते हैं जिससे आप नोड के कंट्रोलिंग टर्मिनल से स्पैन्ड प्रक्रिया को अलग कर सकते हैं, जो इसे अतुल्यकालिक रूप से चलाने की अनुमति देगा। मैंने अभी तक इसका परीक्षण नहीं किया है, लेकिन एपीआई डॉक्स में ऐसे उदाहरण हैं जो कुछ इस तरह से चलते हैं:

child = require('child_process').execFile('path/to/script', [ 
    'arg1', 'arg2', 'arg3', 
], { 
    // detachment and ignored stdin are the key here: 
    detached: true, 
    stdio: [ 'ignore', 1, 2 ]
}); 
// and unref() somehow disentangles the child's event loop from the parent's: 
child.unref(); 
child.stdout.on('data', function(data) {
    console.log(data.toString()); 
});

8
बोनस अंक यदि आप बता सकते हैं कि निष्पादन के साथ यह कैसे करना है () जैसा कि मुझे एक शेल cmd निष्पादित करने की आवश्यकता है।
डायनमानडॉन

2
आप के लिए निर्धारित विकल्प के child.spawn()साथ उपयोग कर सकते हैं । नोडज्स.ओआरपीshelltrue
सीडएक्स

5
आप चाइल्ड को भी पाइप कर सकते हैं। सीधे सीधे प्रक्रिया के लिए। child.stdout.pipe(process.stdout);
स्टडआउट

@ डायनामिकडैन javascript let childProcess = exec ( './script-to-run --arg1 arg1value', ( error, stdout, stderror ) => { console.log( '[CALLBACK]: ' + error ); // or stdout or stderror } ); // Same as with spawn: childProcess.stdout.on ( 'data', ( data ) => { console.log( '[LIVE]: ' + data ); // Here's your live data! } );
रिक

130

यह अब बहुत आसान है (6 साल बाद)!

स्पॉन एक चाइल्ड ऑबजेक्ट लौटाता है , जिसके साथ आप घटनाओं को सुन सकते हैं । घटनाएँ हैं:

  • क्लास: चाइल्डप्रोसेस
    • घटना: 'त्रुटि'
    • घटना: 'बाहर निकलें'
    • घटना: 'करीब'
    • घटना: 'डिस्कनेक्ट'
    • घटना: 'संदेश'

चाइल्डऑबजेक्ट से वस्तुओं का एक गुच्छा भी है , वे हैं:

  • क्लास: चाइल्डप्रोसेस
    • child.stdin
    • child.stdout
    • child.stderr
    • child.stdio
    • child.pid
    • child.connected
    • child.kill ([संकेत])
    • चाइल्ड.सेंड (संदेश [, sendHandle] [, कॉलबैक])
    • child.disconnect ()

चाइल्डऑबजेक्ट के बारे में अधिक जानकारी यहाँ देखें: https://nodejs.org/api/child_process.html

अतुल्यकालिक

यदि आप अपनी प्रक्रिया को पृष्ठभूमि में चलाना चाहते हैं जबकि नोड अभी भी निष्पादित करना जारी रखने में सक्षम है, तो एसिंक्रोनस विधि का उपयोग करें। आप अपनी प्रक्रिया पूरी होने के बाद भी कार्रवाई करना चुन सकते हैं, और जब प्रक्रिया में कोई आउटपुट होता है (उदाहरण के लिए यदि आप क्लाइंट को स्क्रिप्ट का आउटपुट भेजना चाहते हैं)।

child_process.spawn (...); (नोड v0.1.90)

var spawn = require('child_process').spawn;
var child = spawn('node ./commands/server.js');

// You can also use a variable to save the output 
// for when the script closes later
var scriptOutput = "";

child.stdout.setEncoding('utf8');
child.stdout.on('data', function(data) {
    //Here is where the output goes

    console.log('stdout: ' + data);

    data=data.toString();
    scriptOutput+=data;
});

child.stderr.setEncoding('utf8');
child.stderr.on('data', function(data) {
    //Here is where the error output goes

    console.log('stderr: ' + data);

    data=data.toString();
    scriptOutput+=data;
});

child.on('close', function(code) {
    //Here you can get the exit code of the script

    console.log('closing code: ' + code);

    console.log('Full output of script: ',scriptOutput);
});

यहां बताया गया है कि आप कॉलबैक + अतुल्यकालिक विधि का उपयोग कैसे करेंगे :

var child_process = require('child_process');

console.log("Node Version: ", process.version);

run_script("ls", ["-l", "/home"], function(output, exit_code) {
    console.log("Process Finished.");
    console.log('closing code: ' + exit_code);
    console.log('Full output of script: ',output);
});

console.log ("Continuing to do node things while the process runs at the same time...");

// This function will output the lines from the script 
// AS is runs, AND will return the full combined output
// as well as exit code when it's done (using the callback).
function run_script(command, args, callback) {
    console.log("Starting Process.");
    var child = child_process.spawn(command, args);

    var scriptOutput = "";

    child.stdout.setEncoding('utf8');
    child.stdout.on('data', function(data) {
        console.log('stdout: ' + data);

        data=data.toString();
        scriptOutput+=data;
    });

    child.stderr.setEncoding('utf8');
    child.stderr.on('data', function(data) {
        console.log('stderr: ' + data);

        data=data.toString();
        scriptOutput+=data;
    });

    child.on('close', function(code) {
        callback(scriptOutput,code);
    });
}

उपरोक्त विधि का उपयोग करना, आप उत्पादन के प्रत्येक पंक्ति की स्क्रिप्ट से ग्राहक के लिए (उदाहरण के लिए, जब आप पर घटनाओं प्राप्त प्रत्येक पंक्ति भेजने के लिए Socket.io का उपयोग कर भेज सकते हैं stdoutया stderr)।

एक समय का

यदि आप चाहते हैं कि नोड यह क्या कर रहा है और स्क्रिप्ट के पूरा होने तक प्रतीक्षा करें , तो आप तुल्यकालिक संस्करण का उपयोग कर सकते हैं:

child_process.spawnSync (...); (नोड v0.11.12 +)

इस पद्धति के मुद्दे:

  • यदि स्क्रिप्ट को पूरा होने में थोड़ा समय लगता है, तो आपका सर्वर उस समय के लिए लटका रहेगा!
  • स्क्रिप्ट समाप्त होने के बाद ही स्टडआउट लौटाया जाएगा । क्योंकि यह समकालिक है, यह तब तक जारी नहीं रह सकता जब तक कि वर्तमान रेखा समाप्त नहीं हो जाती। इसलिए स्पॉन लाइन समाप्त होने तक यह 'stdout' इवेंट को कैप्चर करने में असमर्थ है।

इसे कैसे उपयोग करे:

var child_process = require('child_process');

var child = child_process.spawnSync("ls", ["-l", "/home"], { encoding : 'utf8' });
console.log("Process finished.");
if(child.error) {
    console.log("ERROR: ",child.error);
}
console.log("stdout: ",child.stdout);
console.log("stderr: ",child.stderr);
console.log("exist code: ",child.status);

11
+1, इसे अब सही उत्तर के रूप में चुना जाना चाहिए। बस एक नोट, कॉलबैक में डेटा चर बफर ऑब्जेक्ट के रूप में आता है। child.stdout.setEncoding('utf8')यदि आप utf8 स्ट्रिंग्स में आना चाहते हैं तो आप इसका इस्तेमाल कर सकते हैं ।
आशीष

2
यदि आपको stdoutअतुल्यकालिक रूप से जानकारी की आवश्यकता है, तो यह काम नहीं करता है, जबकि शेष कार्यक्रम जारी है, अगर प्रक्रिया जारी है।
ईसाई हुजेर

2
अरे @ChristianHujer! मैंने अपने उत्तर को अद्यतन किया है जिसमें एसिंक्स और सिंक दोनों शामिल हैं: D
केटी

यदि आपके पास एक स्क्रिप्ट है जो है: console.log("Output 1"); console.error("Boom"); console.log("Output 2");और मैं कर रहा हूँ spawnAsync('node ./script.js')... आप आउटपुट के क्रम को कैसे संरक्षित करते हैं? मेरा आउटपुट हमेशा गलत क्रम में निकलता है।
ब्रायन रे

FYI करें, यह और भी आसान अगर आप का उपयोग करें pipeया pipelineया करने के लिए उपयुक्त विकल्पों में से गुजरती हैं spawn
रिचस

25

यहाँ मैंने पाया सबसे साफ तरीका है:

require("child_process").spawn('bash', ['./script.sh'], {
  cwd: process.cwd(),
  detached: true,
  stdio: "inherit"
});

15
यह क्या कर रहा है, बिल्कुल? यह काम क्यों करता है? यह क्लीनर दृष्टिकोण क्यों है?
किशमिश

16

जब मुझे एक बच्चे की प्रक्रिया में npm spawned था, तो मुझे "npm install" कमांड से लॉगिंग आउटपुट प्राप्त करने में थोड़ी परेशानी हुई। निर्भरता का वास्तविक समय लॉगिंग माता-पिता के कंसोल में नहीं दिखा।

मूल पोस्टर क्या चाहता है यह करने का सबसे आसान तरीका यह प्रतीत होता है (विंडोज़ पर स्पॉन एनपीएम और पेरेंट कंसोल के लिए सब कुछ लॉग इन करें):

var args = ['install'];

var options = {
    stdio: 'inherit' //feed all child process logging into parent process
};

var childProcess = spawn('npm.cmd', args, options);
childProcess.on('close', function(code) {
    process.stdout.write('"npm install" finished with code ' + code + '\n');
});

3

मैंने खुद को इस कार्यक्षमता की आवश्यकता के लिए पर्याप्त पाया कि मैंने इसे एक लाइब्रेरी में पैक किया, जिसे std-pour कहा जाता है । यह आपको एक कमांड निष्पादित करने और वास्तविक समय में आउटपुट देखने देना चाहिए। बस स्थापित करने के लिए:

npm install std-pour

फिर एक कमांड निष्पादित करना और रियलटाइम में आउटपुट देखना काफी सरल है:

const { pour } = require('std-pour');
pour('ping', ['8.8.8.8', '-c', '4']).then(code => console.log(`Error Code: ${code}`));

यह वादा किया गया है ताकि आप कई कमांड को चेन कर सकें। यह फ़ंक्शन हस्ताक्षर-संगत भी है, child_process.spawnइसलिए इसे आपके द्वारा उपयोग किए जा रहे कहीं भी प्रतिस्थापन में एक बूंद होना चाहिए।


1
@KodieGrantham खुशी है कि यह आपके लिए काम कर रहा है! ऐसा लगता है कि आप कुछ अच्छा काम कर रहे हैं, इसलिए मुझे आशा है कि यह आपको चालू रखेगा।
जोएल बी


1

PHP की तरह passthru

import { spawn } from 'child_process';

export default async function passthru(exe, args, options) {
    return new Promise((resolve, reject) => {
        const env = Object.create(process.env);
        const child = spawn(exe, args, {
            ...options,
            env: {
                ...env,
                ...options.env,
            },
        });
        child.stdout.setEncoding('utf8');
        child.stderr.setEncoding('utf8');
        child.stdout.on('data', data => console.log(data));
        child.stderr.on('data', data => console.log(data));
        child.on('error', error => reject(error));
        child.on('close', exitCode => {
            console.log('Exit code:', exitCode);
            resolve(exitCode);
        });
    });
}

प्रयोग

const exitCode = await passthru('ls', ['-al'], { cwd: '/var/www/html' })

0

child_process.execजैसा कि मुझे भी लाइव फीडबैक की आवश्यकता थी, से संबंधित उत्तर जोड़ना और स्क्रिप्ट समाप्त होने के बाद तक कोई भी नहीं मिल रहा था। यह स्वीकृत उत्तर के लिए मेरी टिप्पणी को भी पूरक करता है, लेकिन जैसा कि यह स्वरूपित है यह थोड़ा और अधिक समझने और पढ़ने में आसान होगा।

मूल रूप से, मेरे पास एक एनपीएम स्क्रिप्ट है, जो कि गुल्प को कॉल करती है, एक कार्य को लागू करती है जो बाद child_process.execमें ओएस के आधार पर एक बैश या बैच स्क्रिप्ट को निष्पादित करने के लिए उपयोग करती है। या तो स्क्रिप्ट, गुल के माध्यम से एक निर्माण प्रक्रिया चलाती है और फिर कुछ बायनेरिज़ को कुछ कॉल करती है जो गुल आउटपुट के साथ काम करते हैं।

यह बिल्कुल दूसरों की तरह है (स्पॉन, इत्यादि), लेकिन पूरा होने के लिए, यहाँ बिल्कुल यह है कि यह कैसे किया जाए:

// INCLUDES
import * as childProcess from 'child_process'; // ES6 Syntax


// GLOBALS
let exec = childProcess.exec; // Or use 'var' for more proper 
                              // semantics, though 'let' is 
                              // true-to-scope


// Assign exec to a variable, or chain stdout at the end of the call
// to exec - the choice, yours (i.e. exec( ... ).stdout.on( ... ); )
let childProcess = exec
(
    './binary command -- --argument argumentValue',
    ( error, stdout, stderr ) =>
    {
        if( error )
        {
            // This won't show up until the process completes:
            console.log( '[ERROR]: "' + error.name + '" - ' + error.message );
            console.log( '[STACK]: ' + error.stack );

            console.log( stdout );
            console.log( stderr );
            callback();            // Gulp stuff
            return;
        }

        // Neither will this:
        console.log( stdout );
        console.log( stderr );
        callback();                // Gulp stuff
    }
);

अब एक घटना श्रोता जोड़ने के रूप में सरल है। के लिए stdout:

childProcess.stdout.on
(
    'data',
    ( data ) =>
    {
        // This will render 'live':
        console.log( '[STDOUT]: ' + data );
    }
);

और इसके लिए stderr:

childProcess.stderr.on
(
    'data',
    ( data ) =>
    {
        // This will render 'live' too:
        console.log( '[STDERR]: ' + data );
    }
);

बहुत बुरा नहीं है - HTH

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