ดำเนินการและรับเอาต์พุตของคำสั่งเชลล์ใน node.js


113

ใน node.js ฉันต้องการหาวิธีรับเอาต์พุตของคำสั่ง Unix terminal มีวิธีใดบ้างที่จะทำเช่นนี้?

function getCommandOutput(commandString){
    // now how can I implement this function?
    // getCommandOutput("ls") should print the terminal output of the shell command "ls"
}

รายการนี้ซ้ำกันหรือไม่หรืออธิบายถึงสิ่งที่แตกต่างไปจากเดิมอย่างสิ้นเชิง stackoverflow.com/questions/7183307/…
Anderson Green

สิ่งนี้อาจทำให้คุณสนใจ
benkastah

คำตอบ:


143

นั่นคือวิธีที่ฉันทำในโครงการที่ฉันกำลังดำเนินการอยู่

var exec = require('child_process').exec;
function execute(command, callback){
    exec(command, function(error, stdout, stderr){ callback(stdout); });
};

ตัวอย่าง: การดึงข้อมูลผู้ใช้ git

module.exports.getGitUser = function(callback){
    execute("git config --global user.name", function(name){
        execute("git config --global user.email", function(email){
            callback({ name: name.replace("\n", ""), email: email.replace("\n", "") });
        });
    });
};

3
เป็นไปได้หรือไม่ที่จะทำให้ฟังก์ชันนี้ส่งคืนผลลัพธ์ของคำสั่ง (นั่นคือสิ่งที่ฉันพยายามทำ)
Anderson Green

1
นั่นคือสิ่งที่รหัสนั้นทำ ดูตัวอย่างการแก้ไขที่ฉันเพิ่งทำ
Renato Gama

2
@AndersonGreen คุณคงไม่ต้องการให้ฟังก์ชันกลับมาเป็นปกติโดยใช้แป้นพิมพ์ "return" เนื่องจากกำลังเรียกใช้คำสั่งเชลล์แบบอะซิงโครนัส ด้วยเหตุนี้จึงเป็นการดีกว่าที่จะส่งผ่านการเรียกกลับด้วยรหัสที่ควรทำงานเมื่อคำสั่งเชลล์เสร็จสมบูรณ์
Nick McCurdy

1
อุ๊ยตัวอย่างแรกของคุณเพิกเฉยต่อความเป็นไปได้ที่จะเกิดข้อผิดพลาดเมื่อโทรกลับ ฉันสงสัยว่าจะเกิดอะไรขึ้นstdoutหากมีข้อผิดพลาด หวังว่าจะกำหนดและจัดทำเป็นเอกสาร
doug65536

31

คุณกำลังมองหาchild_process

var exec = require('child_process').exec;
var child;

child = exec(command,
   function (error, stdout, stderr) {
      console.log('stdout: ' + stdout);
      console.log('stderr: ' + stderr);
      if (error !== null) {
          console.log('exec error: ' + error);
      }
   });

ตามที่ Renato ระบุไว้ตอนนี้มีแพ็คเกจ exec แบบซิงโครนัสอยู่ด้วยเช่นกันดูsync-execที่อาจมีอะไรมากกว่าที่คุณกำลังมองหา โปรดทราบว่า node.js ได้รับการออกแบบให้เป็นเซิร์ฟเวอร์เครือข่ายที่มีเธรดประสิทธิภาพสูงเพียงตัวเดียวดังนั้นหากเป็นสิ่งที่คุณต้องการใช้งานให้หลีกเลี่ยงสิ่งที่ sync-exec เว้นแต่คุณจะใช้เฉพาะในระหว่างการเริ่มต้น หรือบางสิ่งบางอย่าง.


1
ในกรณีนี้ฉันจะรับผลลัพธ์ของคำสั่งได้อย่างไร "stdout" ที่มีเอาต์พุตบรรทัดคำสั่งคืออะไร
Anderson Green

นอกจากนี้ยังสามารถทำสิ่งที่คล้ายกันโดยไม่ใช้การโทรกลับได้หรือไม่?
Anderson Green

ถูกต้อง stdout มีเอาต์พุตของโปรแกรม และไม่เป็นไปไม่ได้ที่จะทำโดยไม่มีการโทรกลับ ทุกอย่างใน node.js เน้นไปที่การไม่ปิดกั้นซึ่งหมายความว่าทุกครั้งที่คุณทำ IO คุณจะต้องใช้การโทรกลับ
hexist

โปรดทราบว่าหากคุณกำลังมองหาการใช้ javascript เพื่อทำสิ่งที่เป็นสคริปต์ในที่ที่คุณต้องการรอเอาต์พุตและสิ่งนั้นจริงๆคุณอาจดูที่ v8 shell, d8
hexist

@hexist มีSyncวิธีการบางอย่างที่สามารถใช้ได้แม้กระทั่ง IMHO ก็ควรหลีกเลี่ยง
Renato Gama

30

หากคุณใช้โหนดที่ช้ากว่า 7.6 และคุณไม่ชอบสไตล์การโทรกลับคุณยังสามารถใช้promisifyฟังก์ชันของ node-util async / awaitเพื่อรับคำสั่งเชลล์ที่อ่านได้อย่างหมดจด นี่คือตัวอย่างของคำตอบที่ยอมรับโดยใช้เทคนิคนี้:

const { promisify } = require('util');
const exec = promisify(require('child_process').exec)

module.exports.getGitUser = async function getGitUser () {
  const name = await exec('git config --global user.name')
  const email = await exec('git config --global user.email')
  return { name, email }
};

นอกจากนี้ยังมีประโยชน์เพิ่มเติมในการส่งคืนคำสัญญาที่ถูกปฏิเสธสำหรับคำสั่งที่ล้มเหลวซึ่งสามารถจัดการได้ด้วยtry / catchรหัส async


คุณลองสิ่งนี้แล้วหรือยัง? ฉันได้รับ{ stdout: string, stderr: string }ผลสำหรับawait exec(...)
fwoelffel

1
ใช่ฉันควรจะชี้แจงว่าสิ่งนี้ให้ผลลัพธ์เชลล์เต็มรูปแบบรวมทั้ง stdout และ stderr return { name: name.stdout.trim(), email: email.stdout.trim() }หากคุณต้องการเพียงแค่ออกคุณสามารถเปลี่ยนบรรทัดสุดท้ายไปที่:
Ansikt

16

ขอบคุณคำตอบของ Renato ฉันได้สร้างตัวอย่างพื้นฐานจริงๆ:

const exec = require('child_process').exec

exec('git config --global user.name', (err, stdout, stderr) => console.log(stdout))

มันจะพิมพ์ชื่อผู้ใช้ git ส่วนกลางของคุณ :)


11

ข้อกำหนด

สิ่งนี้จะต้องใช้ Node.js 7 ขึ้นไปพร้อมการสนับสนุนสำหรับ Promises และ Async / Await

สารละลาย

สร้างฟังก์ชัน wrapper ที่ใช้ประโยชน์จากสัญญาว่าจะควบคุมลักษณะการทำงานของchild_process.execคำสั่ง

คำอธิบาย

การใช้สัญญาและฟังก์ชันอะซิงโครนัสคุณสามารถเลียนแบบพฤติกรรมของเชลล์ที่ส่งคืนเอาต์พุตโดยไม่ตกอยู่ในนรกเรียกกลับและด้วย API ที่ค่อนข้างเรียบร้อย การใช้awaitคำหลักคุณสามารถสร้างสคริปต์ที่อ่านได้อย่างง่ายดายในขณะที่ยังสามารถทำงานให้child_process.execเสร็จได้

ตัวอย่างโค้ด

const childProcess = require("child_process");

/**
 * @param {string} command A shell command to execute
 * @return {Promise<string>} A promise that resolve to the output of the shell command, or an error
 * @example const output = await execute("ls -alh");
 */
function execute(command) {
  /**
   * @param {Function} resolve A function that resolves the promise
   * @param {Function} reject A function that fails the promise
   * @see https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Promise
   */
  return new Promise(function(resolve, reject) {
    /**
     * @param {Error} error An error triggered during the execution of the childProcess.exec command
     * @param {string|Buffer} standardOutput The result of the shell command execution
     * @param {string|Buffer} standardError The error resulting of the shell command execution
     * @see https://nodejs.org/api/child_process.html#child_process_child_process_exec_command_options_callback
     */
    childProcess.exec(command, function(error, standardOutput, standardError) {
      if (error) {
        reject();

        return;
      }

      if (standardError) {
        reject(standardError);

        return;
      }

      resolve(standardOutput);
    });
  });
}

การใช้งาน

async function main() {
  try {
    const passwdContent = await execute("cat /etc/passwd");

    console.log(passwdContent);
  } catch (error) {
    console.error(error.toString());
  }

  try {
    const shadowContent = await execute("cat /etc/shadow");

    console.log(shadowContent);
  } catch (error) {
    console.error(error.toString());
  }
}

main();

ตัวอย่างผลลัพธ์

root:x:0:0::/root:/bin/bash
[output trimmed, bottom line it succeeded]

Error: Command failed: cat /etc/shadow
cat: /etc/shadow: Permission denied

ลองออนไลน์

Repl.it

แหล่งข้อมูลภายนอก

สัญญา .

child_process.exec.

ตารางการสนับสนุน Node.js

โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.