2010-11-01 10 views
5

Sto combattendo il bug degli spazi nel metodo exec di Runtime di Java. Ecco cosa è unico in questo problema: il comando che sto tentando di eseguire è una stringa in entrata e può avere o meno spazi e non è necessariamente in alcun formato specifico. Ad ogni modo, ho bisogno di eseguirlo. Se non ci sono spazi, sono bravo; se ci sono spazi, non sono così bravo.Utilizzo del comando exec di Java quando non si sa se ci sono spazi

Come si tiene conto di entrambe le circostanze?

Informazioni sui bonus senza costi aggiuntivi: uno dei grandi problemi sembra essere che sto cercando di chiamare un eseguibile in c: \ programmi file \ blablabla ... ed exec sembra dividere nello spazio dopo 'c :\programma'. Sono sicuro che anche altri parametri si presenterebbero per i parametri.

Ecco un esempio più specifico dei tipi di stringhe che potrei ottenere. Questo dovrebbe chiarire alcune delle confusione:

  • c: \ someApp \ someapp.exe
  • c: \ someApp \ someapp.exe -someParam = foo
  • c: \ programmi \ someapp \ someapp .exe
  • c: \ programmi \ someapp \ someapp.exe -someParam = bar

Il primo funziona bene perché non ha spazi. Il secondo è anche a posto perché si divide nello spazio e usa il primo come comando e il secondo come parametro. Il terzo e il quarto esempio si dividono nel primo spazio, usano 'C: \ program' e il comando, 'files ...' e (nel caso della quarta stringa) '-someParam = bar' come parametri.

+0

Sei in grado di eseguire una pre-elaborazione della stringa in entrata? Se è così, puoi usare Runtime.exec (String [] cmdarray) metodo che gestirà gli spazi per te, assumendo che tu sia in grado di spezzare la stringa in arrivo con gli argomenti – Benn

+4

Garbage In, Garbage Out, non puoi analizzare una stringa senza senso. Assicurati che il mittente sfugga agli spazi che voglio mantenere, o mettere le stringhe che corrono insieme tra virgolette, solo così facendo, il tuo problema passa da impossibile a piuttosto difficile –

risposta

4

OK, ho ottenuto qualcosa lavorando facendo qualcosa di simile. La prego di dirmi se c'è un problema con questo approccio:

 

try{ 
    String[] command = {"cmd", "/c", getMySuperAwesomeString()}; 
    Runtime.getRuntime().exec(command); 
}catch(IOExecption ioe){ 
    System.err.println("I'm borken"); 
} 
 

In una nota correlata, dovrei usare ProcessBuilder invece?

+0

Questo probabilmente funzionerà, a seconda del processo si sta iniziando. Se funziona probabilmente è più flessibile della mia risposta (e con meno codice). Stai solo scaricando la parte più difficile di capire gli argomenti per la shell cmd :) Non dovrebbe essere necessario ProcessBuilder a meno che non hai intenzione di avviare tutta una serie di processi simili, come ci si esegue negli stessi problemi creazione di token. – Benn

+0

Sì, in entrambi i casi stai facendo ipotesi, giusto? Grazie per il tuo contributo! – Dave

+0

Sì questo è quello che ho dovuto fare in un Microservice, è stato un vero e proprio scratcher testa, ma questo metodo sembra molto più robusto. – wired00

0

Forse sto pensando troppo semplicemente, ma potrebbe funzionare?

Runtime.exec(commandstring.split(" ")); 

(sto supponendo che si desidera che il comando da eseguire come se eseguito in un guscio o giù di lì.)

+2

Penso che stia pensando a qualcosa come 'comando C: \ Documents and Settings \ user \ datafile.dat ', che non vorresti interpretare come' ["comando", "C: \ Documenti", "e", "Impostazioni \ utente \ datafile.dat"] ' – Benn

+0

Sì, hai capito. quello più chiaro nella mia domanda: – Dave

0

darò per scontato che si può trattare la stringa in entrata. In questo caso, si può vedere se si dispone di un ingresso con spazi con:

if("string with possible spaces".contains(" ")) { 
    System.out.println("yay"); 
} 

Si noti che questo funziona solo se c'è un carattere di spazio reale nel vostro input. Se si vuole essere più approfondita, assumendo i caratteri di tabulazione o ritorni a capo sono possibili ingressi, è possibile utilizzare un'espressione regolare:

String s = ".+\\s.+"; 
Pattern p = Pattern.compile(s); 

Matcher m = p.matcher("string with possible spaces or tabs"); 
if(m.matches()) { 
    System.out.println("yay"); 
} 

Modifica: È possibile utilizzare il codice ho fornito per rilevare se ci sono spazi in ingresso . Se non ci sono, non devi fare nulla. Se hai spazi, la situazione è un po 'più complessa. Leggendo le risposte di altre persone e la tua domanda rivista, posso solo supporre che l'input che ha spazi debba essere citato, quindi la spaziatura non rovinerà l'esecuzione del comando standard.Nel ci sono spazi, è necessario:

  1. controllo se ci sono delle citazioni nel vostro ingresso
  2. se ce ne sono, loro (il cambiamento " a \")
  3. circondano l'ingresso con le virgolette Escape (some input diventa "some input")

definitiva, si vuole di ingresso come some "funky" input per diventare "some \"funky\" input".

Nota: fare attenzione alle virgolette singole ('). Occupati di loro in modo appropriato.

+0

Potrei dividerlo, ma cosa farei con i singoli pezzi? Solo non saprei cosa ho in attesa dopo averli divisi. – Dave

0

sto assumendo questo è il bug si stanno combattendo:

http://bugs.sun.com/bugdatabase/view_bug.do?bug_id=4506936

http://bugs.sun.com/bugdatabase/view_bug.do;jsessionid=8582245ba20fa4da33ac0967e858?bug_id=4491217

Si dice che la soluzione potrebbe essere:

Utilizzare un JRE che non si trova in una percorso che contiene spazi.

Usa Processo pubblico exec (String [] cmdarray, String [] envp) throws IOException

e mettere il comando ed i parametri in un array separato. In questo modo non proverebbe a bloccarlo e usare lo spazio come separatore.

+0

Il nostro JRE non si trova in un percorso che contiene spazi. – Dave

+0

Sull'altro bug dicono che è necessario inserire tutti gli argomenti nello slot separato: per riassumere, l'unico modo sicuro è mettere ciascun argomento in uno slot separato nella matrice degli argomenti. Quindi, utilizzare http://download.oracle.com/javase/1.4.2/docs/api/java/lang/Runtime.html#exec%28java.lang.String [],% 20java.lang.String [] % 29. Correggerò il post originale –

+0

Il problema è che non so cosa sia un argomento e cosa no. – Dave

4

io effettivamente fare questo una risposta, invece di un commento: (dal J2SE 1.5, Runtime.exec(String[]))

Supponendo che è possibile pre-elaborazione, utilizzare un array di stringhe per alleviare i problemi con gli spazi nei comandi, il seguente dovrebbe funzionare:

String[] args = {"C:\Program Files\app\app.exe","C:\Data Files\data1.dat"}; 
Runtime.exec(args); 

da lì dipende dalla capacità di capire ciò che è uno spazio tra le due comandi e ciò è uno spazio in un percorso.

EDIT

Ciò funzionerà se gli spazi appaiono nel percorso dell'eseguibile, ma non vi aiuterà sugli spazi negli argomenti.

String input = "c:\\program files\\someapp\\someapp.exe -someParam=bar"; 
int firstSplit = input.indexOf(".exe") + 4; //account for length of ".exe" 
String command = input.substring(0,firstSplit); 
String args = input.substring(firstSplit).trim(); //trim off extraneous whitespace 
String[] argarray = args.split(" "); 
String[] cmdargs = new String[argarray.length + 1]; 
cmdargs[0] = command; 
for (int i = 0; i < argarray.length; i++) { 
    cmdargs[i+1] = argarray[i]; 
} 
Runtime.exec(cmdargs); 

Si noti che questo è ancora abbastanza fragile (e solo lavora per exe, non di pipistrello o qualsiasi altra cosa). Se è necessario tenere conto degli spazi negli argomenti, è necessario eseguire ulteriori elaborazioni sulla stringa args o su argarray. La soluzione corretta è far sì che gli utenti (o il processo di input) differenziano correttamente tutti gli argomenti.

+0

Mi piacerebbe fare qualcosa di simile, ma non ho modo di sapere in modo affidabile dove interrompere la stringa di comando. – Dave

+0

Ciò rende le cose piuttosto sfortunate, se non impossibili. Si potrebbe comunque indovinare: (dalla propria modifica) se gli spazi si verificano solo nel percorso dell'eseguibile, pre-processare per portare tutto a ".exe" come un comando, e quindi fare uno String.split (" ") sulle opzioni rimanenti. Se le opzioni stesse o gli argomenti possono contenere spazi, diventerà doloroso. Modificherò la mia risposta per mostrarne un esempio. – Benn

+0

Soluzione interessante. Terrò questo in mente. – Dave

1

Esempio per eseguire un file JAR con spazi nel percorso del file:

String qoutation = "\"" 
String path = "C:\\JAR File\\File.jar" 
Runtime.getRuntime().exec("java -jar " + quotation + path + quotation); 

Questo esegue il comando: java-jar "C: \ vaso File \ file.jar"

Quando la barra rovesciata \ appare in una stringa usata come fuga, facendo in modo che il programma salti. Questo ci permette di usare le virgolette "nella stringa, non per avviare/chiudere la stringa

Problemi correlati