最新消息:Welcome to the puzzle paradise for programmers! Here, a well-designed puzzle awaits you. From code logic puzzles to algorithmic challenges, each level is closely centered on the programmer's expertise and skills. Whether you're a novice programmer or an experienced tech guru, you'll find your own challenges on this site. In the process of solving puzzles, you can not only exercise your thinking skills, but also deepen your understanding and application of programming knowledge. Come to start this puzzle journey full of wisdom and challenges, with many programmers to compete with each other and show your programming wisdom! Translated with DeepL.com (free version)

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

matteradmin3PV0评论

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.

Post a comment

comment list (0)

  1. No comments so far