Home > database >  Is it possible to await for a shell command to be fully executed and then return something after it?
Is it possible to await for a shell command to be fully executed and then return something after it?

Time:01-24

I am trying to make one function that returns a 1 after a command from terminal is fully executed.

Any idea how to do it?

This is my code:

const speed = async () => {
try {
    exec(`speedtest`, (error, stdout, stderr) => {
        if (error) {
            // console.log(`error: ${error.message}`);
            return;
        }
        if (stderr) {
            console.log(`stderr: ${stderr}`);
            return;
        }
        console.log(`stdout: ${stdout}`);
    });
    console.log(stdout);
} catch (error) {
    console.log('error')
}

Knowing that speedtest command takes sometime to print the whole output, i would like to proceed to other line of code only if the command is fully executed.

CodePudding user response:

You can use Promises for that:

const { exec } = require('child_process');

const speed = () => new Promise((resolve, reject) => {
  try {
      exec(`speedtest`, (error, stdout, stderr) => {
          if (error) {
            reject(error);
          } else if (stderr) {
            reject(stderr);
          } else {
            const downloadSpeed = stdout.match(/Download:\s (\d (\.\d )?)/i);
            const uploadSpeed = stdout.match(/Upload:\s (\d (\.\d )?)/i);
            const speed = {
              download: downloadSpeed? Number(downloadSpeed[1]) : null,
              upload: uploadSpeed? Number(uploadSpeed[1]) : null,
            }
            resolve(speed);
          }
          
      });
  } catch (error) {
      reject(error)
  }
});

speed()
  .then(speed => console.log('got resolve:', speed))
  .catch(error => console.log('got reject:', error));

Promise will be resolved after something will be in stdout. If You want to wait for something special, you can use regular expressions and add timeout arg:

const {
  exec
} = require('child_process');

const speed = (timeout = 60000) => new Promise((resolve, reject) => {
  try {

    const searchingString = 'Result URL:';
    let fullOutput = '';
    let finished = false;

    setTimeout(() => {
      if (finished) return;
      reject(new Error('Timeout'));
    }, timeout);

    exec(`speedtest`, (error, stdout, stderr) => {
      if (error) {
        reject(error);
      } else if (stderr) {
        reject(stderr);
      } else {
        fullOutput  = stdout;
        if (fullOutput.indexOf(searchingString) === -1) {
          return;
        }
        finished = true;
        const downloadSpeed = fullOutput.match(/Download:\s (\d (\.\d )?)/i);
        const uploadSpeed = fullOutput.match(/Upload:\s (\d (\.\d )?)/i);
        const speed = {
          download: downloadSpeed ? Number(downloadSpeed[1]) : null,
          upload: uploadSpeed ? Number(uploadSpeed[1]) : null,
        }
        resolve(speed);
      }

    });
  } catch (error) {
    reject(error)
  }
});

speed()
  .then(speed => console.log('got resolve:', speed))
  .catch(error => console.log('got reject:', error));

The other way is to use listeners on child process:

const {
  exec
} = require('child_process');

const speed = (timeout = 60000) => new Promise((resolve, reject) => {
  try {

    let fullOutput = '';

    let timer = setTimeout(() => {
      if (finished) return;
      reject(new Error('Timeout'));
    }, timeout);

    const child = exec(`speedtest`, (error, stdout, stderr) => {
      if (error) {
        reject(error);
      } else if (stderr) {
        reject(stderr);
      } else {
        fullOutput  = stdout;
      }
    });

    child.on('close', () => {
      clearTimeout(timer);
      const downloadSpeed = fullOutput.match(/Download:\s (\d (\.\d )?)/i);
      const uploadSpeed = fullOutput.match(/Upload:\s (\d (\.\d )?)/i);
      const speed = {
        download: downloadSpeed ? Number(downloadSpeed[1]) : null,
        upload: uploadSpeed ? Number(uploadSpeed[1]) : null,
      }
      resolve(speed);
    });
    child.on('error', reject);
  } catch (error) {
    reject(error)
  }
});

speed()
  .then(speed => console.log('got resolve:', speed))
  .catch(error => console.log('got reject:', error));
  • Related