2010-09-10 18 views
30

Wie kann ich einen Shell-Befehl im Hintergrund aus einem Bash-Skript ausführen, wenn der Befehl in einer Zeichenfolge ist?Ausführen von Shell-Befehl im Hintergrund von Skript

Zum Beispiel:

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

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

das funktioniert nicht - wie kann ich das tun?

+2

Siehe auch [BashFAQ/050] (http://mywiki.wooledge.org/BashFAQ/050). –

Antwort

32

wegzulassen die Zitate

$cmd & 
$othercmd & 

zB:

[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

danke. Es ist notwendig, die Semikolons zu verlassen, soweit ich das beurteilen kann. – user248237dfsf

+0

Auch stellen Sie sicher, dass Sie ** nicht ** Zitate um $ cmd setzen. Wenn Sie dies tun, wird es versuchen, einen Befehl namens "ls -la" 'statt" ls "mit den Schaltern" -la "auszuführen. – GreenRaccoon23

+0

'cmd = 'some-command" mit Argumenten "'; $ cmd' ist überhaupt nicht ** das gleiche wie 'some-command' mit Argumenten" '. Es wird fehlschlagen, wenn Sie in Ihrer Argumentliste angeben; es wird scheitern, wenn Sie kontrollieren müssen, wann Globs sind und nicht erweitert werden; Es wird fehlschlagen, wenn Code ausgeführt wird, der zur Laufzeit von der Klammererweiterung oder der Parametererweiterung abhängt. Siehe [BashFAQ # 50] (http://mywiki.wooledge.org/BashFAQ/050): * Ich versuche, einen Befehl in eine Variable zu setzen, aber komplexe Fälle scheitern immer! *. –

0

Das funktioniert, weil die es eine statische Variable ist. Sie könnten etwas viel kühl, wie dies tun:

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 

Dieser Code 20 Dateien und dynamisch Satz 20 Variablen schaffen. Natürlich könnten Sie ein Array verwenden, aber ich zeige Ihnen nur die Funktion :). Beachten Sie, dass Sie die Variablen $ filename1, $ filename2, $ filename3 ... verwenden können, da sie mit dem Befehl evaluate erstellt wurden. In diesem Fall erstelle ich nur Dateien, aber Sie könnten dynamische Argumente für die Befehle erstellen und dann im Hintergrund ausführen.

22

Gebäude weg von ngoozeff ‚s Antwort, wenn Sie einen Befehl ausführen zu wollen vollständig im Hintergrund (dh, wenn Sie wollen verstecken seinen Ausgang und verhindern, dass es getötet zu werden, wenn Sie in der Nähe seines Terminal-Fenster), können Sie diese stattdessen tun:

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

& (die erste) löst den Befehl von stdin.
>/dev/null löst die Shell-Sitzung von stdout und stderr.
&disown entfernt den Befehl aus der Auftragsliste der Shell.

Sie können auch &! statt &disown verwenden; Sie sind beide derselbe Befehl.

Auch wenn ein Befehl in einer Variablen setzen, dann ist es geeignetere eval "${cmd}" eher zu verwenden als "${cmd}":

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

Wenn Sie diesen Befehl ausführen direkt im Terminal, wird die PID der Show Prozess, der der Befehl startet. Aber innerhalb eines Shell-Skript, keine Ausgabe wird angezeigt.

Hier ist eine Funktion für sie:

#!/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} "' ist sicherlich viel besser als nur '$ {cmd}'. Ich glaube, das ist es, was Sie als "$ {cmd}" 'für Fälle wie:' cmd = 'ls -l'' misslingt. Außerdem ist '$ {cmd}' selbst nicht die perfekte Lösung, da es in Fällen fehlschlägt, in denen Erweiterungen vor der Parametererweiterung verwendet werden. Also zum Beispiel für 'cmd = 'touch file {1..5}''. – PesaThe

+0

'eval" $ @ "' ist fehlerhaft - wenn jemand '' $ @ "' erwartet, um sicherzustellen, dass Argumente getrennt voneinander übergeben werden, besiegt 'eval' den Punkt (indem er alle seine Argumente zu einer einzigen Zeichenfolge zusammenfügt) und dann evaluieren). Besser, * entweder * '' $ @ "' zu benutzen (das erwartet, dass Argumente vorher geteilt werden), oder 'eval" $ 1 "' (erwartet genau ein Argument, das zum Parsen formatiert ist). –

+0

@CharlesDuffy Was ist ein Beispiel dafür, wenn 'eval" $ @ "' fehlerhaft ist? Ich kann mir keinen vorstellen. Ich kann mir Fälle vorstellen, in denen '$ @ '' wie indirekte Variablen fehlerhaft wäre. 'eval" $ {1} "' würde auch mehrere Argumente ignorieren, wie Sie darauf hingewiesen haben. 'eval" $ @ "' würde beide Randfälle behandeln. Ich stimme zu, dass 'eval" $ {1} "' trotzdem ausreichen sollte, da Ihr Code in der Art konsistent sein sollte, wie er diese Funktion aufruft. Wenn Sie die Anführungszeichen in '_evalBg" $ {cmd} "' anstelle von '_evalBg $ {cmd}' benötigen, wird der Code auf lange Sicht besser zu verwalten sein. – GreenRaccoon23

0

Zum Beispiel können Sie ein Startprogramm mit dem Namen Lauf haben.sh, um es im Hintergrund arbeiten zu starten, die folgende Befehlszeile. ./run.sh &>/dev/null &

Verwandte Themen