2010-09-10 18 views
30

Come posso eseguire un comando shell in background da uno script bash, se il comando è in una stringa?esecuzione del comando shell in background dallo script

Ad esempio:

#!/bin/bash 
cmd="nohup mycommand"; 
other_cmd="nohup othercommand"; 

"$cmd &"; 
"$othercmd &"; 

questo non funziona - come posso fare questo?

+2

Vedere anche [BashFAQ/050] (http://mywiki.wooledge.org/BashFAQ/050). –

risposta

32

lasciare fuori le virgolette

$cmd & 
$othercmd & 

esempio:

[email protected] /tmp 
$ cat test 
#!/bin/bash 

cmd="ls -la" 

$cmd & 


[email protected] /tmp 
$ ./test 

[email protected] /tmp 
$ total 6 
drwxrwxrwt+ 1 nicholas root 0 2010-09-10 20:44 . 
drwxr-xr-x+ 1 nicholas root 4096 2010-09-10 14:40 .. 
-rwxrwxrwx 1 nicholas None 35 2010-09-10 20:44 test 
-rwxr-xr-x 1 nicholas None 41 2010-09-10 20:43 test~ 
+2

grazie. è necessario anche lasciare il punto e virgola per quanto posso dire. – user248237dfsf

+0

Assicurati inoltre di fare ** non ** mettere le virgolette intorno a '$ cmd'. Se lo fai, proverà a eseguire un comando chiamato '" ls -la "' invece di 'ls' con le opzioni' -la'. – GreenRaccoon23

+0

'cmd = 'some-command" con argomenti "'; $ cmd' non è ** ** lo stesso di 'some-command" con argomenti "'. Fallirà se hai quotazioni nella tua lista di argomenti; fallirà se è necessario controllare quando i glob sono e non sono espansi; fallirà se il codice in esecuzione dipende dall'espansione del rinforzo o dall'espansione dei parametri al momento dell'esecuzione. Vedi [BashFAQ # 50] (http://mywiki.wooledge.org/BashFAQ/050): * Sto cercando di inserire un comando in una variabile, ma i casi complessi falliscono sempre! *. –

0

Questo funziona perché la si tratta di una variabile statica. Si potrebbe fare qualcosa di molto più fresco di simile:

filename="filename" 
extension="txt" 
for i in {1..20}; do 
    eval "filename${i}=${filename}${i}.${extension}" 
    touch filename${i} 
    echo "this rox" > filename${i} 
done 

Questo codice crea 20 file e dinamicamente set 20 variabili. Ovviamente potresti usare un array, ma ti sto solo mostrando la funzione :). Si noti che è possibile utilizzare le variabili $ nomefile1, $ nomefile2, $ nomefile3 ... perché sono stati creati con comando valuta. In questo caso sto solo creando file, ma puoi usare per creare argomenti dinamici ai comandi, e poi eseguire in background.

22

Costruzione off di risposta ngoozeff s', se si vuole fare un ordine di marcia completamente in background (ad esempio, se si vuole nascondere la sua uscita e evitare che venga ucciso quando si chiude la sua Terminal finestra), si può fare questo, invece:

cmd="google-chrome"; 
"${cmd}" &>/dev/null &disown; 

& (il primo) stacca il comando da stdin.
>/dev/null stacca la sessione di shell da stdout e stderr.
&disown rimuove il comando dall'elenco dei lavori della shell .

È inoltre possibile utilizzare &! anziché &disown; sono entrambi lo stesso comando.

Inoltre, quando mettendo un comando all'interno di una variabile, è più corretto di utilizzare eval "${cmd}" piuttosto che "${cmd}":

cmd="google-chrome"; 
eval "${cmd}" &>/dev/null &disown; 

Se si esegue questo comando direttamente nel Terminal, mostrerà il PID del processo a cui inizia il comando. Ma all'interno di uno script di shell, non verrà visualizzata alcuna uscita.

Ecco una funzione per esso:

#!/bin/bash 

# Run a command in the background. 
_evalBg() { 
    eval "[email protected]" &>/dev/null &disown; 
} 

cmd="google-chrome"; 
_evalBg "${cmd}"; 

http://felixmilea.com/2014/12/running-bash-commands-background-properly/

+1

@ user248237dfsf @ GreenRaccoon23 'eval" $ {cmd} "' è sicuramente molto meglio di solo '$ {cmd}'. Credo che sia quello che intendi come '" $ {cmd} "' fallirà per casi come: 'cmd = 'ls -l''. Inoltre, '$ {cmd}' non è la soluzione perfetta in quanto fallirà per i casi che utilizzano espansioni fatte prima dell'espansione dei parametri. Ad esempio, per 'cmd = 'touch file {1..5}''. – PesaThe

+0

'eval" $ @ "' è buggy - se qualcuno si aspetta '" $ @ "' per assicurare che gli argomenti siano passati separatamente gli uni dagli altri, usando 'eval' sconfigge il punto (concatenando tutti i suoi argomenti insieme in una singola stringa e quindi valutarlo). Meglio * usare * '$ @ '' (aspettando che gli argomenti siano pre-split), o' eval "$ 1" '(aspettandosi esattamente un argomento formattato per l'analisi). –

+0

@CharlesDuffy Che cosa è un esempio di quando "eval" $ @ "' è bacato? Non riesco a pensare a uno. Posso pensare ai casi in cui '" $ @ "' sarebbe buggato, come le variabili indirette. 'eval" $ {1} "' ignorerebbe anche più argomenti, come hai sottolineato. 'eval" $ @ "' gestiva entrambi i casi limite. Sono d'accordo sul fatto che 'eval" $ {1} "' dovrebbe essere sufficiente perché il tuo codice dovrebbe essere coerente nel modo in cui chiama quella funzione. Richiedere le virgolette in '_evalBg" $ {cmd} "' invece di '_evalBg $ {cmd}' renderà il codice più gestibile a lungo termine. – GreenRaccoon23

0

Per esempio si ha un programma di avvio di nome corsa.sh per avviarlo lavorando in background, eseguire la seguente riga di comando. ./run.sh &>/dev/null &

Problemi correlati