2009-11-22 10 views
35

En nodejs, la única forma de ejecutar comandos externos es a través de sys.exec (cmd). Me gustaría llamar a un comando externo y darle datos a través de stdin. En nodejs todavía no parece haber una manera de abrir un comando y luego enviar datos a él (solo para ejecutar y recibir sus salidas estándar + error), por lo que parece que la única forma en que tengo que hacer esto ahora es a través de una sola cadena de comando, tales como:¿Cómo puedo escapar de una cadena para un comando de shell en un nodo?

var dangerStr = "bad stuff here"; 
sys.exec("echo '" + dangerStr + "' | somecommand"); 

la mayoría de respuestas a preguntas de este tipo se han centrado en cualquiera de expresiones regulares que no funciona para mí en nodejs (que utiliza el motor JavaScript V8 de Google) o características nativas de otros idiomas como el Pitón.

Me gustaría escapar de dangerStr para que sea seguro componer una cadena ejecutiva como la de arriba. Si esto ayuda, dangerStr contendrá datos JSON.

+9

Para shell de tipo Bourne puede usar el siguiente algoritmo para escapar cadenas de forma segura: 1) reemplazar todas las ocurrencias de comillas simples (') con la comilla simple de cuatro caracteres, barra invertida, comilla simple, comilla simple (' \ '') 2) agregue una comilla simple adicional al principio y al final de la cadena modificada. Las comillas simples iniciales y finales no están codificadas de manera perfectamente eficiente, pero todavía funciona: "se convierte en '' \ '' 'cuando podría ser solo \'. –

+0

Para aclarar: me tomó un poco de tiempo entender el consejo de @ ChrisJohnsen, pero se comprueba. Si quieres 'do not do that' en el shell, haz' echo 'no hacer eso para producir 'do not do that'. – mikemaccana

Respuesta

4

Hay una forma de escribir en un comando externo: process.createChildProcess (documentation) devuelve un objeto con un método write. createChildProcess no es tan conveniente, porque no almacena el stdout y el stderr, por lo que necesitará manejadores de eventos para leer los resultados en fragmentos.

var stdout = "", stderr = ""; 
var child = process.createChildProcess("someCommand"); 

child.addListener("output", function (data) { 
    if (data !== null) { 
     stdout += data; 
    } 
}); 
child.addListener("error", function (data) { 
    if (data !== null) { 
     stderr += data; 
    } 
}); 
child.addListener("exit", function (code) { 
    if (code === 0) { 
     sys.puts(stdout); 
    } 
    else { 
     // error 
    } 
}); 

child.write("This goes to someCommand's stdin."); 
+0

¡Rock! gracias por el ejemplo detallado. – Maciek

+0

Interesante ... ¡Gracias! Por cierto, el nuevo URI es http://nodejs.org/api/child_process.html – grilix

+29

No explicas nada sobre cómo escapar de los argumentos. – Will

33

Esto es lo que yo uso:

var escapeShell = function(cmd) { 
    return '"'+cmd.replace(/(["\s'$`\\])/g,'\\$1')+'"'; 
}; 
+0

¿Qué está haciendo los primeros $? En la API, la referencia dice que solo coincide si es el final de la cadena, pero no es este caso. Probé la cadena "/ aPath"/con/qu'otes '"(observe que termina con comillas simples + dobles), con $ y sin $. El resultado es el mismo. –

+1

@DavidTorres 'abc $ abc' se convierte en' abc \ $ abc' –

+1

No es necesario tener esacpe '$' if use apostrophe ''' –

14

Si necesita una solución simple que puede utilizar esto:

function escapeShellArg (arg) { 
    return `'${arg.replace(/'/g, `'\\''`)}'`; 
} 

Así que su cadena será simplemente escapó con comillas simples como Chris Johnsen mencionado.

echo 'John'\''s phone'; 

funciona en bash debido strong quoting, se siente como que también trabaja en fish, pero no funciona en zsh y sh.

Si tiene bash puede ejecutar su secuencia de comandos en sh o zsh con 'bash -c \'' + escape('all-the-rest-escaped') + '\''.

Pero en realidad ... Node.js escaparán todos los caracteres necesarios para usted:

var child = require('child_process') 
    .spawn('echo', ['`echo 1`;"echo $SSH_TTY;\'\\0{0..5}']); 

child.stdout.on('data', function (data) { 
    console.log('stdout: ' + data); 
}); 

child.stderr.on('data', function (data) { 
    console.log('stderr: ' + data); 
}); 

este bloque de código se ejecutará:

echo '`echo 1`;"echo $SSH_TTY;'\''\\0{0..5}' 

y la Salida:

stdout: `echo 1`;"echo $SSH_TTY;\'\\0{0..5} 

o algún error.

Tome un vistazo a http://nodejs.org/api/child_process.html#child_process_child_process_spawn_command_args_options

Por la solución simple forma de dirigir un grupo de comandos es:

require('child_process') 
    .spawn('sh', ['-c', [ 
    'cd all/your/commands', 
    'ls here', 
    'echo "and even" > more' 
    ].join('; ')]); 

tenga un buen día!

-1

Si también necesita tratar con caracteres especiales (saltos de línea, etc.)), Puede hacerlo de esta manera:

str = JSON.stringify(str) 
    .replace(/^"|"$/g,'') //remove JSON-string double quotes 
    .replace(/'/g, '\'"\'"\'') //escape single quotes the ugly bash way 

Esto supone utiliza strong-quoting de golpe a través de las comillas simples) y el receptor pueda comprender escape C-como JSON.

-1

Una variación en la respuesta de Sylvain:

var escapeShell = function(string) { 
    // Sanitise all space (newlines etc.) to a single space 
    string.replace(/\s+/g, " "); 
    // Optionally remove leading and trailing space 
    string.replace(/^\s+|\s+$/g, " "); 
    // Quote with single quotes, escaping backslashes and single quotes 
    return "'" + string.replace(/(['\\])/g, '\\$1') + "'"; 
}; 

Partiendo de la premisa de que $ no necesita ser escapado en una sola cadena entre comillas (como Alex señaló) y los otros tipos de cotización no necesitan ser tanto.

Cuestiones relacionadas