Use child_process.execSync, mas mantenha a saída no console

160

Gostaria de usar o execSyncmétodo que foi adicionado no NodeJS 0.12, mas ainda tenho a saída na janela do console a partir da qual executei o script Node.

Por exemplo, se eu executar um script NodeJS com a seguinte linha, gostaria de ver a saída completa do comando rsync "ao vivo" dentro do console:

require('child_process').execSync('rsync -avAXz --info=progress2 "/src" "/dest"');

Eu entendo que execSyncretorna a saída do comando e que eu poderia imprimi-lo no console após a execução, mas desta forma não tenho saída "ao vivo" ...

suamikim
fonte

Respostas:

324

Você pode passar o estágio dos pais para o processo filho, se é isso que você deseja:

require('child_process').execSync(
    'rsync -avAXz --info=progress2 "/src" "/dest"',
    {stdio: 'inherit'}
);
gregers
fonte
3
Isso significa que o processo filho usará os fluxos stdin, stdout e stderr do pai. Portanto, quando o processo filho gravar em um deles, ele será gravado diretamente no fluxo dos pais.
Gregers
7
Esta é uma resposta muito valiosa, pois a documentação oficial não é realmente explícita sobre a sintaxe esperada.
Chikamichi
49
Em vez de [0,1,2]eu ter usado 'inherit', o que é equivalente a [process.stdin, process.stdout, process.stderr]ou [0,1,2]conforme os documentos
Kurt
10
Link correto para options.stdioa documentação: nodejs.org/api/child_process.html#child_process_options_stdio
Shaun Lebron
2
@Booligoosh Em vez de simplesmente adicionar {stdio:'inherit'}, você precisa adicionar .toString () e chamar console.log manualmente com o resultado. Além disso, ele nem preenche o requisito de perguntas de ver o resultado do comando "ativo". Não acho que seja "muito mais simples", na verdade, não acho que seja mais simples.
precisa
19

Você pode simplesmente usar .toString().

var result = require('child_process').execSync('rsync -avAXz --info=progress2 "/src" "/dest"').toString();
console.log(result);

Isso foi testado no Node v8.5.0, não tenho certeza sobre as versões anteriores. De acordo com @etov , ele não funciona v6.3.1- não tenho certeza sobre isso.

Ethan
fonte
3
Isso não funciona com falha (código de status! = 0) porque .execSync()lança uma Errorinstância.
Álvaro González
Não funciona para mim, ou seja, a saída é gravada somente após a conclusão do comando. Isso se aplica a uma versão específica? meu nó -v: v6.3.1
etov 28/09
Por favor, considere atualizar a resposta para notar que é aplicável apenas a certas versões de nós - este seria torná-lo mais útil para os outros
etov
1
A votação foi reduzida, uma vez que os ti estão agora relacionados à questão referente à saída durante o comando.
karfau 11/01
14

A menos que você redirecione stdout e stderr como a resposta aceita sugere, isso não é possível com execSync ou spawnSync. Sem redirecionar stdout e stderr, esses comandos retornam apenas stdout e stderr quando o comando é concluído.

Para fazer isso sem redirecionar stdout e stderr, você precisará usar spawn para fazer isso, mas é bem direto:

var spawn = require('child_process').spawn;

//kick off process of listing files
var child = spawn('ls', ['-l', '/']);

//spit stdout to screen
child.stdout.on('data', function (data) {   process.stdout.write(data.toString());  });

//spit stderr to screen
child.stderr.on('data', function (data) {   process.stdout.write(data.toString());  });

child.on('close', function (code) { 
    console.log("Finished with code " + code);
});

Eu usei um comando ls que lista recursivamente os arquivos para que você possa testá-lo rapidamente. Spawn usa como primeiro argumento o nome do executável que você está tentando executar e, como segundo argumento, usa uma matriz de seqüências de caracteres representando cada parâmetro que você deseja passar para esse executável.

No entanto, se você estiver usando o execSync e não puder redirecionar stdout ou stderr por algum motivo, poderá abrir outro terminal como o xterm e passar um comando da seguinte maneira:

var execSync = require('child_process').execSync;

execSync("xterm -title RecursiveFileListing -e ls -latkR /");

Isso permitirá que você veja o que seu comando está fazendo no novo terminal, mas ainda tem a chamada síncrona.

Brian
fonte
2
O exemplo usando spawn pode estar correto, mas a declaração de abertura sobre não estar prestes a usar o execSync não é precisa. Veja a resposta de @gregers
AgDude