最新消息:雨落星辰是一个专注网站SEO优化、网站SEO诊断、搜索引擎研究、网络营销推广、网站策划运营及站长类的自媒体原创博客

How to use javascript asyncawait on executing shell script - Stack Overflow

programmeradmin0浏览0评论

So I have a server listening to RabbitMQ requests:

        console.log(' [*] Waiting for messages in %s. To exit press CTRL+C', q);
        channel.consume(q, async function reply(msg) {
            const mongodbUserId = msg.content.toString();
            console.log(' [x] Received %s', mongodbUserId);

            await exec('./new_user_run_athena.sh ' + mongodbUserId, function(
                error,
                stdout,
                stderr
            ) {
                console.log('Running Athena...');
                console.log('stdout: ' + stdout);
                console.log('stderr: ' + stderr);
                if (error !== null) {
                    console.log('exec error: ' + error);
                }
            });

            console.log(
                ' Finished running Athena for mongodbUserId=%s',
                mongodbUserId
            );

            channel.sendToQueue(
                msg.properties.replyTo,
                new Buffer(mongodbUserId),
                { correlationId: msg.properties.correlationId }
            );

            channel.ack(msg);
        });

The problem is that the await call on executing the shell script new_user_run_athena.sh happens after I print out Finished running Athena for mongodbUserId. You can see it happening in the console log:

 [*] Waiting for messages in run_athena_for_new_user_queue. To exit press CTRL+C
 [x] Received 5aa96f36ed4f68154f3f2143
 Finished running Athena for mongodbUserId=5aa96f36ed4f68154f3f2143
Running Athena...
stdout: 
stderr:

Is it even possible to use async await syntax on executing a shell script?

So I have a server listening to RabbitMQ requests:

        console.log(' [*] Waiting for messages in %s. To exit press CTRL+C', q);
        channel.consume(q, async function reply(msg) {
            const mongodbUserId = msg.content.toString();
            console.log(' [x] Received %s', mongodbUserId);

            await exec('./new_user_run_athena.sh ' + mongodbUserId, function(
                error,
                stdout,
                stderr
            ) {
                console.log('Running Athena...');
                console.log('stdout: ' + stdout);
                console.log('stderr: ' + stderr);
                if (error !== null) {
                    console.log('exec error: ' + error);
                }
            });

            console.log(
                ' Finished running Athena for mongodbUserId=%s',
                mongodbUserId
            );

            channel.sendToQueue(
                msg.properties.replyTo,
                new Buffer(mongodbUserId),
                { correlationId: msg.properties.correlationId }
            );

            channel.ack(msg);
        });

The problem is that the await call on executing the shell script new_user_run_athena.sh happens after I print out Finished running Athena for mongodbUserId. You can see it happening in the console log:

 [*] Waiting for messages in run_athena_for_new_user_queue. To exit press CTRL+C
 [x] Received 5aa96f36ed4f68154f3f2143
 Finished running Athena for mongodbUserId=5aa96f36ed4f68154f3f2143
Running Athena...
stdout: 
stderr:

Is it even possible to use async await syntax on executing a shell script?

Share Improve this question asked May 7, 2018 at 17:43 letter Qletter Q 15.4k34 gold badges85 silver badges125 bronze badges 1
  • What is exec in your code? child_process.exec? Because it doesn't return a promise. So using await on it doesn't do anything. – T.J. Crowder Commented May 7, 2018 at 17:47
Add a ment  | 

4 Answers 4

Reset to default 2

Since exec looks like it takes a callback, you can use that to wrap it into a promise. Then you can await that promise instead of awaiting the exec call directly. So, for your example, something like:

// Await a new promise:
await new Promise((resolve, reject) => {
    exec('./new_user_run_athena.sh ' + mongodbUserId, function(
        error,
        stdout,
        stderr
    ) {
        console.log('Running Athena...');
        console.log('stdout: ' + stdout);
        console.log('stderr: ' + stderr);
        if (error !== null) {
            console.log('exec error: ' + error);
            // Reject if there is an error:
            return reject(error);
        }

        // Otherwise resolve the promise:
        resolve();
    });
});

See the MDN documentation for await:

The await operator is used to wait for a Promise. It can only be used inside an async function.

The exec function does not return a Promise, so you cannot await for it.

You could write a function which wraps exec in a Promise and returns that Promise though.

Wrap exec in a promise. Here a typescript example:

import { exec as childProcessExec } from 'child_process'

const exec = async (mand: string): Promise<string> => {
  return new Promise((resolve, reject) => {
    childProcessExec(mand, (error, stdout, stderr) => {
      if (error !== null) reject(error)
      if (stderr !== '') reject(stderr)
      else resolve(stdout)
    })
  })
}

Usage:

const mandOutput = await exec('echo Hey there!')
console.log(mandOutput)

Based on the other examples I came up with a typed async execute call that returns an object or in the second case a string:

/**
 * Adds typed await and async support 
 * @param mand string
 * @returns Promise<{error:ExecException, standardError:string, standardOut:string}
 */
async callProcess(mand:string): Promise<{error:ExecException, standardError:string, standardOut:string}> {
  
  return new Promise((resolve, reject) => {
    childProcessExec(mand, (error: ExecException, standardOut: string, standardError: string) => {
      var result = {error, standardError, standardOut};

      if (error !== null) {
        reject(result);
      }
      if (standardError !== '') {
        reject(result);
      }
      else {
        resolve(result);
      }
    })
  })
}

You call it like so:

try {
   var callResult = await this.callProcess(execCommand);

   if (callResult.standardOut) {

   }
}
catch(error) {

   if (error.standardError) {

   }
   else if (error.error) {
  
   }
   else {

   }
}

And example returning string:

/**
 * Adds typed await and async support. 
 * In a try block returns standard out and error in catch block.  
 * @param mand string
 * @returns Promise<string>
 */
async callProcess(mand:string): Promise<string> {
  
  return new Promise((resolve, reject) => {
    childProcessExec(mand, (error: ExecException, standardOut: string, standardError: string) => {

      if (error !== null) {
        reject(error);
      }
      if (standardError !== '') {
        reject(standardError);
      }
      else {
        resolve(standardOut);
      }
    })
  })
}
try {
   var standardOut = await this.callProcess(execCommand);

}
catch(error) {

   if (error instanceof object) {

   }
   else {

   }
}

It's not fully tested so add any corrections.

发布评论

评论列表(0)

  1. 暂无评论