vatsa
vatsa

Reputation: 49

How to execute synchronously in nodejs?

I have the following code.

router.post('/',function(req, res, next) {
        var id=req.body.id;
        console.log(id);

    const testscript = exec('sh script.sh');

    testscript.stdout.on('data', function(data){
        console.log(data);
        // sendBackInfo();
    });

    testscript.stderr.on('data', function(data){
        console.log(data);
        // triggerErrorStuff();
    });

        res.redirect('/Visualise');
});

I need to completely execute my shell script and then redirect to '/Visualise'. Some part of code in the next page uses the output file generated by shell script. It is redirecting before executing the shell script completely and i am getting a file not found error. How can i execute synchronously. Please make the required changes in the above code to do so. Thank you.

Upvotes: 1

Views: 3836

Answers (2)

Terry Lennox
Terry Lennox

Reputation: 30705

You can use child_process.execSync for this, it returns stdout:

child_process.execSync(command[, options])

e.g.

const child_process = require('child_process');
var response = child_process.execSync('sh script.sh');

Response will be a Buffer object.

Documention is here:

https://nodejs.org/api/child_process.html#child_process_child_process_execsync_command_options

Beware that if the script times out or has a non-zero exit code, this method will throw an error, so you might want to wrap with a try / catch.

To add this to your code do this:

const child_process = require('child_process');

router.post('/',function(req, res, next) {
        var id=req.body.id;
        console.log(id);    

        try
        {
            var response = child_process.execSync('sh script.sh');
            console.log('Script response: ', response.toString());
        }
        catch (error) {
            console.error('An error occurred: ', error);
        }

        res.redirect('/Visualise');
});

A better pattern is to do this asynchronously:

const child_process = require('child_process');

router.post('/',function(req, res, next) {
        var id=req.body.id;
        console.log(id);    

        child_process.exec('sh script.sh', (error, stdout) => {
            if (error) {
                console.error(`exec error: ${error}`);
                return;
            }
            console.log(`stdout: ${stdout}`);

            res.redirect('/Visualise');
        });
});

NB: Never pass unsanitized user input to this function, it's a big security risk.

Upvotes: 1

Darkhogg
Darkhogg

Reputation: 14165

What you really want is not to execute an script synchronously, as that would block the event loop and prevent other requests from running. Instead, you need to (asynchronously) wait for your script to finish.

To do that, write the redirect inside the exit event of the child process, not on the body of your handler:

router.post('/', function(req, res, next) {
    // ...whatever

    const testscript = exec('sh script.sh');

    // ...stdouts

    testscript.on('exit', function (code, signal) {
        res.redirect('/Visualise');
    });
});

Upvotes: 1

Related Questions