node.js는 시스템 명령을 동 기적으로 실행합니다


171

node.js 함수 가 필요 합니다

result = execSync('node -v');

주어진 명령 줄 을 동 기적으로 실행하고 해당 명령 텍스트로 모든 표준을 반환합니다.

추신. 동기화가 잘못되었습니다. 알아. 개인적인 용도로만 사용하십시오.

최신 정보

이제 종료 코드를 제공하지만 stdout은 제공하지 않는 mgutz의 솔루션이 있습니다! 더 정확한 답변을 기다리는 중입니다.

최신 정보

mgutz는 그의 대답을 업데이트했고 해결책은 여기에 있습니다 :)
또한 dgo.a에서 언급했듯이 독립형 모듈 exec-sync가 있습니다.

2014-07-30 업데이트

ShellJS lib가 도착했습니다. 이것이 현재 최선의 선택이라고 생각하십시오.


업데이트 2015-02-10

마지막에! NodeJS 0.12는 execSync기본적으로 지원합니다 .
공식 문서를 참조하십시오


26
자신이 바보가 가지 않도록 동기화 경우에도 명시 적으로 ... 비동기 메서드를 호출하지 않는 한 모든 코드는 동 기적으로 실행 NodeJS에 ... 잘못되지 않습니다 모든 비동기 방식으로 이루어지지 않았습니다 아무것도 해본 것입니다. 또한 비동기 메서드를 선호한다고해서 긴 계산으로 서버가 차단되지는 않습니다. 선택입니다. Node 제작자들은 비동기 파일 시스템 메소드와 함께 비동기 파일 시스템 메소드를 제공하기로 선택했다는 사실도 그 장소가 있음을 보여줍니다.
흐름

2
우리가 말하는 "Unix shell emulation library"는 어디에서 찾을 수 있습니까?
Florian

@ 플로리안 그는 ShellJS를 의미 합니다
xst

답변:


153

Node.js (버전 0.12부터-잠시 동안)는 execSync다음을 지원합니다 .

child_process.execSync(command[, options])

이제 직접 할 수 있습니다 :

const execSync = require('child_process').execSync;
code = execSync('node -v');

그리고 당신이 기대하는 것을 할 것입니다. (i / o 결과를 상위 프로세스로 파이프하는 기본값) 참고 수행 할 수도 있습니다 spawnSync지금.


6
절망 10 시간 후 감사합니다
Tom Dev

이 하위 프로세스에서 어떻게 연결을 끊을 수 있습니까?
JulianSoto


54

execSync 라이브러리를 참조하십시오 .

node-ffi로하 는 것은 상당히 쉽습니다 . 서버 프로세스에는 권장하지 않지만 일반적인 개발 유틸리티의 경우에는 작업이 완료됩니다. 라이브러리를 설치하십시오.

npm install node-ffi

스크립트 예 :

var FFI = require("node-ffi");
var libc = new FFI.Library(null, {
  "system": ["int32", ["string"]]
});

var run = libc.system;
run("echo $USER");

[편집 2012 년 6 월 : STDOUT를 얻는 방법]

var lib = ffi.Library(null, {
    // FILE* popen(char* cmd, char* mode);
    popen: ['pointer', ['string', 'string']],

    // void pclose(FILE* fp);
    pclose: ['void', [ 'pointer']],

    // char* fgets(char* buff, int buff, in)
    fgets: ['string', ['string', 'int','pointer']]
});

function execSync(cmd) {
  var
    buffer = new Buffer(1024),
    result = "",
    fp = lib.popen(cmd, 'r');

  if (!fp) throw new Error('execSync error: '+cmd);

  while(lib.fgets(buffer, 1024, fp)) {
    result += buffer.readCString();
  };
  lib.pclose(fp);

  return result;
}

console.log(execSync('echo $HOME'));

2
실제로 stdout이것으로부터 무엇을 보내려고 합니까? 내가 얻을 수있는 것은 프로세스 종료 코드입니다
Mark Kahn

@ cwolves : 비동기가 더 좋을 것이라고 생각합니다. ( 이보의 대답 )
pvorb

@pvorb - 당신이 비동기 : 사용할 수없는 경우 예를 제외하고
마크 칸

1
모든 네일에 비동기 해머를 사용하지 않는 데는 유효한 이유가 있습니다. 예를 들어, 템플릿 엔진은 Express 3에서 비동기식이며 도우미 기능 (로컬)은 동기식이어야합니다. 이러한 도우미 함수가 적은 파일을 비동기식으로 컴파일해야하는 경우 어떻게해야합니까?
mgutz 2016 년

8
왜이 단순한 execSync것이 일부가 아닌지 궁금 child_process합니다. 나는 그렇게 생각한다.
Michael Härtl

31

ShellJS 모듈을 사용하십시오 .

콜백을 제공하지 않고 exec 함수.

예:

var version = exec('node -v').output;

2
문서 작성 시점에서 문서는 동기 exec()가 긴 프로세스에서 CPU를 많이 사용 한다고 언급 합니다.
Aram Kocharyan

1
옵션, {silent : true}가 핵심입니다
Nick

1
이것은 짧은 구문을 제공하는 것 외에는 그렇지 않은 것을합니까? const execSync = require('child_process').execSync; code = execSync('node -v');
user2503764

23

node.js에는 asyncblock 이라는 흐름 제어를위한 훌륭한 모듈이 있습니다 . 함수에 코드를 래핑하는 것이 괜찮다면 다음 샘플을 고려할 수 있습니다.

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

asyncblock(function (flow) {
    exec('node -v', flow.add());
    result = flow.wait();
    console.log(result);    // There'll be trailing \n in the output

    // Some other jobs
    console.log('More results like if it were sync...');
});

1
그는 흐름 라이브러리를 제어하지 않고 동기화 버전에 대해 명시 적으로 질문했습니다.
Alexey Petrushin

22
@AlexeyPetrushin 여기에있는 모든 질문은 목표를 달성하기위한 구체적인 방법이 아니라 목표에 관한 것입니다. downvoting 주셔서 감사합니다.
nab

1
또한 이것은 Windows 사용자에게 매우 유용한 답변입니다. Windows에 설치 exec-sync하거나 ffiWindows에 설치 하면 오버 헤드가 커지지 만 (VC ++, SDK, Python 등) 이는 더 가볍습니다.
Mendhak

10

이 Node.js를에 가능하지 않다, 모두 child_process.spawnchild_process.exec비동기로 처음부터 건설되었다.

자세한 내용은 https://github.com/ry/node/blob/master/lib/child_process.js 를 참조하십시오.

이 블로킹을 실제로 원한다면 나중에 콜백에 필요한 모든 것을 넣거나 블로킹 방식으로 처리하기 위해 자신의 대기열을 작성하려면 이 작업에 Async.js 를 사용할 수 있다고 가정합니다 .

또는 너무 많은 시간을 할애 할 수없는 경우 Node.js에서 스스로 해킹하십시오.


12
파일 시스템 모듈에 동기 호출이 있기 때문에 이상합니다. 왜 실행하지 않습니까?
Alfred

4
@Alfred sync FS 호출은 주로 프로그램 시작시 구성을로드하기위한 것입니다.
Ivo Wetzel

3
@IvoWetzel-tisk tisk ... 뭔가 불가능하다고 말하는 법을 배운 적이 없습니까? ;) 아래 내 솔루션을 참조하십시오.
Marcus 교황

1
@IvoWetzel "동기 FS 호출 ..."— 맞습니다. 때로는 프로그램 시작시 무언가를 컴파일하는 명령을 실행하고 완료를 계속하려고합니다 .— 동기 exec가없는 동기화 FS 호출이있는 경우 감독처럼 보입니다. 나는 모두 비동기식이지만 동기식에는 장점과 사용 사례가 있습니다. 물론 그것을 신중하게 사용해야합니다.
흐름

비동기는 괜찮지 만 WidgetB가 WidgetA의 최종 결과에 의존하는 경우 전 세계의 모든 비동기가 작업을 완료하지 못합니다. 때때로 프로세스는 동기식이어야합니다. 비동기식으로 요리하십시오. ;)
Lloyd Sargent

9

이것이 내가 찾은 가장 쉬운 방법입니다.

exec-Sync : https://github.com/jeremyfa/node-exec-sync(execSync
와 혼동하지 마십시오.)
셸 명령을 동 기적으로 실행합니다. 마이그레이션 스크립트, cli 프로그램에는 사용하지만 일반 서버 코드에는 사용하지 마십시오.

예:

var execSync = require('exec-sync');   
var user = execSync('echo $USER');
console.log(user);


5

섬유를 사용하여이를 달성 할 수 있습니다. 예를 들어, 공통 노드 라이브러리 를 사용하면 코드는 다음과 같습니다.

result = require('subprocess').command('node -v');

3

"synchronous"콜백 함수의 끝에서 물건 을 구현하는 데 익숙해졌습니다 . 그리 좋지는 않지만 작동합니다. 일련의 명령 행 실행을 구현해야하는 경우 exec일부 명명 된 함수 로 랩핑 하고 재귀 적으로 호출해야합니다. 이 패턴은 나에게 유용한 것 같습니다.

SeqOfExec(someParam);

function SeqOfExec(somepParam) {
    // some stuff
    // .....
    // .....

    var execStr = "yourExecString";
    child_proc.exec(execStr, function (error, stdout, stderr) {
        if (error != null) {
            if (stdout) {
                throw Error("Smth goes wrong" + error);
            } else {
                // consider that empty stdout causes
                // creation of error object
            }
        }
        // some stuff
        // .....
        // .....

        // you also need some flag which will signal that you 
        // need to end loop
        if (someFlag ) {
            // your synch stuff after all execs
            // here
            // .....
        } else {
            SeqOfExec(someAnotherParam);
        }
    });
};

3

비슷한 문제가 발생하여 노드 확장을 작성했습니다. git 저장소를 체크 아웃 할 수 있습니다. 오픈 소스이고 무료이며 모든 좋은 것들입니다!

https://github.com/aponxi/npm-execxi

ExecXI는 C ++로 작성된 노드 확장으로 쉘 명령을 하나씩 실행하여 명령 출력을 콘솔에 실시간으로 출력합니다. 선택적인 연결 및 연결되지 않은 방법이 있습니다. 즉, 명령이 실패한 후 (체인 된) 스크립트를 중지하거나 아무 일도없는 것처럼 계속할 수 있습니다!

사용법 지침은 ReadMe 파일에 있습니다. 풀 요청을하거나 문제를 제출하십시오!

편집 : 그러나 그것은 아직 stdout을 반환하지 않습니다 ... 그냥 실시간으로 출력합니다. 지금은 그렇습니다. 글쎄, 나는 오늘 그것을 발표했다. 어쩌면 우리는 그것을 만들 수 있습니다.

어쨌든, 나는 그것을 언급 할 가치가 있다고 생각했습니다.


이것은 내가 찾던 것입니다. 시간 내 주셔서 감사합니다.
thealfreds

내가 이해하고 구현하지 않은 유일한 것은 다른 nodejs 버전에 대한 빌드 구성입니다. 필자는 노드 0.8 ( travis-ci.org/aponxi/npm-execxi/builds/5248535 )에 작성 했으므로 npm install(즉, 플러그인 컴파일과 같이) 성공하면 생산을 시작하는 것이 좋습니다. 다른 nodejs 버전을 타겟팅하는 것 외에도 프로덕션 용으로 패치되었거나 꽤 안정적이라고 말합니다. 버그가있는 경우 풀 요청을 보내거나 github에 문제를 게시 할 수 있습니다 :)
Logan

1

nodejs에서 다음과 같이 동기식 쉘 작업을 수행 할 수 있습니다.

var execSync = function(cmd) {

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

    //for linux use ; instead of &&
    //execute your command followed by a simple echo 
    //to file to indicate process is finished
    exec(cmd + " > c:\\stdout.txt && echo done > c:\\sync.txt");

    while (true) {
        //consider a timeout option to prevent infinite loop
        //NOTE: this will max out your cpu too!
        try {
            var status = fs.readFileSync('c:\\sync.txt', 'utf8');

            if (status.trim() == "done") {
                var res = fs.readFileSync("c:\\stdout.txt", 'utf8');
                fs.unlinkSync("c:\\stdout.txt"); //cleanup temp files
                fs.unlinkSync("c:\\sync.txt");
                return res;
            }
        } catch(e) { } //readFileSync will fail until file exists
    }

};

//won't return anything, but will take 10 seconds to run
console.log(execSync("sleep 10")); 

//assuming there are a lot of files and subdirectories, 
//this too may take a while, use your own applicable file path
console.log(execSync("dir /s c:\\usr\\docs\\"));

편집-이 예제는 Windows 환경을위한 것이며 필요한 경우 자신의 Linux 요구에 맞게 조정하십시오.


그렇습니다. CPU가 가능한 한 빨리 소환 할 수 있습니다 ...하지만 악한 일을 "필요"할 때 사탄이 맞습니까?
Marcus Pope

좋아, 이것은 순수한 악이지만 굉장하다. 콜백이없는 파일 시스템 이벤트 browserify.on ( 'register')을 처리하기 위해 이것이 필요했습니다. 내 하루를 구했다!
Robert Gould

왜 이것이 자바 스크립트 엔진에서 작동하는지 설명 할 수 있습니까? exec가 다음 틱에서 실행되는 동안 while 루프가 동일한 틱에서 무한대로 실행되어서는 안됩니까?
badunk

바쁜 대기로 CPU를 최대한 활용하는 것은 잘못된 설계입니다.
Louis

@ Louis-DominiqueDubeau 물론, 크로스 플랫폼과 호환되거나 호환되지 않는 일부 타사 소스에 의존하지 않는 대안은 없습니다. OS가 nodejs 프로세스에 우선 순위를 부여하지 않기 때문에 CPU를 최대한 활용하는 것도 아닙니다. 나는 쉘 ops의 동기화 구현이 수평선에 있거나 이미 여기에 있다고 생각합니다.
Marcus 교황

1

실제로 Windows와 Linux / OSX 모두에서 작동하는 방식으로 package.json 사전 설치 스크립트에서 여러 명령을 차례로 실행 해야하는 상황이 있었으므로 비 코어 모듈에 의존 할 수 없었습니다.

그래서 이것은 내가 생각해 낸 것입니다.

#cmds.coffee
childproc = require 'child_process'

exports.exec = (cmds) ->
  next = ->
    if cmds.length > 0
      cmd = cmds.shift()
      console.log "Running command: #{cmd}"
      childproc.exec cmd, (err, stdout, stderr) ->
        if err? then console.log err
        if stdout? then console.log stdout
        if stderr? then console.log stderr
        next()
    else
      console.log "Done executing commands."

  console.log "Running the follows commands:"
  console.log cmds
  next()

다음과 같이 사용할 수 있습니다.

require('./cmds').exec ['grunt coffee', 'nodeunit test/tls-config.js']

편집 : 지적한 바와 같이, 실제로 출력을 반환하지 않거나 Node 프로그램에서 명령 결과를 사용할 수 없습니다. 이를위한 또 다른 아이디어는 LiveScript 백콜을 사용하는 것입니다. http://livescript.net/


감사하지만 코드에서 명령을 비동기식으로 실행하기 때문에 대답이 아닙니다.
disfated

내 예제에 따라 일련의 명령을 동기식으로 실행 해야하는 경우 작동합니다. 그래도 귀하의 질문을 오해 한 것 같습니다. 죄송합니다. 답변에 다른 아이디어를 추가했습니다.
Jason Livesay
당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.