javascriptnode.jsbashexpressshelljs

in an expressJS application, is it possible to collect data written to the console in real-time as a script is executing?


I'm trying to get the output of a bash script into an ExpressJS application where I can then send the data to a client. I created a script below that mimics the output of the actual script I will be using for my project. I want to be able to collect this data as it written to the terminal, store it in a variable in my express app where I can then send the data via SSE or websocket.

n=`expr 10 \* $1`
executionprocessing="processing"
jobdone="done"
sleep 5
echo $executionprocessing
sleep 5
echo $jobdone
echo $n

What I have so far:

app.post('/compute', function(req, res) {
  shell.exec('sh ./Scripts/mytestscript.sh 10', function(code, stdout, stderr) {
    console.log('code:' + code)
    console.log('stdout:' + stdout)
  })
})

When there is a post request, shellJS executes a script in a local directory and the output is written to the console. The problem is, the data is written all at once when the script finishes execution instead of writing the data as it comes. I want to be able to interact with this data in real-time. Is this even possible?

EDIT: child process is the way to go. Here is my solution for anyone else that has this problem.

const child = spawn('sh',['mytestscript.sh','10'],{cwd:'./Scripts'})
child.stdout.on('data', (data) => {
  console.log('code:' + data.toString())
});

Solution

  • As far as I can tell, this cannot be done with ShellJS. However, it should be possible using node's built-in Child Process module. You can pass sh ./Scripts/mytestscript.sh 10 to spawn, which will return a ChildProcess object. One of that object's properties, stdout, is a Readable Stream which streams your script's stdout.

    The code would probably look something like this:

    const { spawn } = require('child_process');
    
    var child = spawn('sh ./Scripts/mytestscript.sh 10');
    child.stdout.on('data', (data) => {
        // do stuff with data chunk that the script sent to stdout
    });
    

    If you just want to send the data directly to a websocket, then it might also be possible to just do child.stdout.pipe(yourWebsocketSteam);.