2009-11-22 23 views
35

In nodejs, l'unico modo per eseguire comandi esterni è tramite sys.exec (cmd). Mi piacerebbe chiamare un comando esterno e dargli dati tramite stdin. In nodejs non sembra ancora essere un modo per aprire un comando e quindi spingere i dati su di esso (solo per eseguire e ricevere i suoi output standard + errore), quindi sembra che l'unico modo per farlo ora sia tramite un unico comando stringa come:Come faccio a uscire da una stringa per un comando di shell nel nodo?

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

la maggior parte delle risposte a domande come questa si sono concentrati su entrambi espressione regolare che non funziona per me in nodejs (che utilizza il motore JavaScript V8 di Google) o caratteristiche native da altri linguaggi come Pitone.

Mi piacerebbe scappare da dangerStr in modo che sia sicuro comporre una stringa exec come quella sopra. Se aiuta, dangerStr conterrà dati JSON.

+9

Per le shell di tipo Bourne è possibile utilizzare il seguente algoritmo per evitare le stringhe in modo sicuro: 1) sostituire tutte le occorrenze di virgoletta singola (') con la virgoletta singola sequenza a quattro caratteri, barra rovesciata, virgoletta singola, virgoletta singola (' \ '') 2) aggiungi una virgola singola aggiuntiva all'inizio e alla fine della stringa modificata. Le virgolette singole e finali non sono codificate in modo perfettamente efficiente, ma funziona ancora - 'diventa' '\' '' quando potrebbe essere solo \ '. –

+0

Per chiarimenti: mi ci è voluto un po 'per capire il consiglio di @ ChrisJohnsen ma si verifica. Se vuoi 'non farlo sulla shell, fai 'echo' don '\' t do that' per produrre' do not do that'. – mikemaccana

risposta

4

C'è un modo per scrivere su un comando esterno: process.createChildProcess (documentation) restituisce un oggetto con un metodo write. createChildProcess non è così conveniente, perché non bufferizza stdout e stderr, quindi avrai bisogno di gestori di eventi per leggere l'output in blocchi.

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

Sei rock! grazie per l'esempio dettagliato – Maciek

+0

Interessante .. Grazie! A proposito, il nuovo URI è http://nodejs.org/api/child_process.html – grilix

+29

Non si spiega nulla sugli argomenti di escape. – Will

33

Questo è quello che uso:

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

Cosa sta facendo il primo $? Nel riferimento api dice che corrisponde solo se è la fine della stringa, ma non è questo il caso. Ho provato la stringa "/ aPath '/ con/qu'otes'" (nota che termina con virgolette singole + doppie), con $ e senza $. Il risultato è lo stesso. –

+1

@DavidTorres 'abc $ abc' diventa' abc \ $ abc' –

+1

Non c'è bisogno di esacpe '$' se si usa apostrofo ''' –

14

Se avete bisogno di una soluzione semplice è possibile utilizzare questo:

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

Così la stringa verrà semplicemente scappato con virgolette singole come Chris Johnsen menzionato.

echo 'John'\''s phone'; 

Funziona in bash a causa di strong quoting, si sente come funziona anche in fish, ma non funziona in zsh e sh.

Se disponi di bash, puoi eseguire il tuo script in sh o zsh con 'bash -c \'' + escape('all-the-rest-escaped') + '\''.

Ma in realtà ... node.js sfuggiranno tutti i caratteri necessari alle tue esigenze:

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); 
}); 

questo blocco di codice eseguirà:

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

e uscita volontà:

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

o qualche errore.

Date un'occhiata a http://nodejs.org/api/child_process.html#child_process_child_process_spawn_command_args_options

Con la soluzione più semplice modo per eseguire una serie di comandi è:

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

Have a nice day!

-1

Se è necessario anche occuparsi di caratteri speciali (interruzioni di riga, ecc.) Si può fare in questo modo:

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

Ciò presuppone si utilizza strong-quoting di Bash tramite apici singoli) e il ricevitore possa capire fuga di JSON C-like.

-1

Una variante di risposta di 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') + "'"; 
}; 

Sulla premessa che $ non ha bisogno di essere sfuggito in una sola stringa tra virgolette (come Alex ha sottolineato) e gli altri tipi di citazione non è necessario essere entrambi

Problemi correlati