2010-09-10 3 views
30

Comment puis-je exécuter une commande shell en arrière-plan à partir d'un script bash, si la commande est dans une chaîne?Exécuter une commande shell en arrière-plan à partir du script

Par exemple:

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

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

cela ne fonctionne pas - comment puis-je faire cela?

+2

Voir aussi [BashFAQ/050] (http://mywiki.wooledge.org/BashFAQ/050). –

Répondre

32

les citations Laisser hors

$cmd & 
$othercmd & 

par exemple:

[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

merci. il est également nécessaire de laisser les points-virgules aussi loin que je peux dire. – user248237dfsf

+0

Assurez-vous également de ne pas ** mettre ** les citations autour de '$ cmd'. Si vous le faites, il essaiera d'exécuter une commande appelée '" ls -la "' au lieu de 'ls' avec les commutateurs' -la'. – GreenRaccoon23

+0

'cmd = 'une certaine commande' avec des arguments ''; $ cmd' n'est pas ** du tout ** la même chose que 'some-command 'avec les arguments" '. Cela échouera si vous avez des citations dans votre liste d'arguments; cela échouera si vous avez besoin de contrôler quand les globes sont et ne sont pas développés; cela échouera si vous exécutez du code qui dépend de l'expansion de l'accolade ou de l'expansion des paramètres au moment de l'exécution. Voir [BashFAQ # 50] (http://mywiki.wooledge.org/BashFAQ/050): * J'essaie de mettre une commande dans une variable, mais les cas complexes échouent toujours! *. –

0

Cela fonctionne parce que c'est une variable statique. Vous pourriez faire quelque chose de beaucoup plus frais comme celui-ci:

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 

Ce code va créer 20 fichiers et dynamiquement définir 20 variables. Bien sûr, vous pouvez utiliser un tableau, mais je ne fais que vous montrer la fonctionnalité :). Notez que vous pouvez utiliser les variables $ filename1, $ filename2, $ filename3 ... car elles ont été créées avec la commande evaluate. Dans ce cas, je ne fais que créer des fichiers, mais vous pouvez utiliser pour créer des arguments dynamiques pour les commandes, puis les exécuter en arrière-plan.

22

bâtiment hors de la réponse de ngoozeff, si vous souhaitez effectuer une commande à exécuter complètement en arrière-plan (par exemple, si vous voulez cacher sa sortie et l'empêchent d'être tué lorsque vous fermez la fenêtre de terminal), vous pouvez le faire à la place:

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

& (la première) désolidarise la commande de stdin.
>/dev/null désolidarise la session shell de stdout et stderr.
&disown supprime la commande de la liste des travaux du shell . Vous pouvez également utiliser &! au lieu de &disown; ils sont tous les deux la même commande.

En outre, lors de la mise d'une commande à l'intérieur d'une variable, il est plus approprié d'utiliser eval "${cmd}" plutôt que "${cmd}":

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

Si vous exécutez cette commande directement dans le Terminal, il affiche le PID du processus que la commande commence. Mais à l'intérieur d'un script shell, aucune sortie ne sera affichée.

Voici une fonction pour elle:

#!/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} "' est sûrement beaucoup mieux que juste '$ {cmd}'. Je crois que c'est ce que vous vouliez dire par "$ {cmd}" 'échouera dans des cas comme:' cmd = 'ls -l''. En outre, '$ {cmd}' n'est pas la solution parfaite, car elle échouera dans les cas utilisant des expansions effectuées avant l'expansion des paramètres. Donc par exemple pour le fichier tactile 'cmd = '{1..5}''. – PesaThe

+0

'eval" $ @ "' est bogué - si quelqu'un s'attend à ce que "" $ @ "' s'assure que les arguments sont passés séparément les uns des autres, utiliser 'eval' détruit le point (en concaténant tous ses arguments en une seule chaîne , puis en l'évaluant). Mieux vaut * soit * utiliser '" $ @ "' (en espérant que les arguments soient pré-divisés), soit 'eval" $ 1 "' (en attendant exactement un argument formaté pour l'analyse syntaxique). –

+0

@CharlesDuffy Quel est un exemple de quand 'eval" $ @ "' est bogué? Je ne peux pas y penser. Je peux penser à des cas où '' $ @ ''serait bogué, comme des variables indirectes. 'eval" $ {1} "' ignorerait aussi plusieurs arguments, comme vous l'avez souligné. 'eval" $ @ "' traiterait ces deux cas de contour. Je suis d'accord que 'eval" $ {1} "' devrait être suffisant, car votre code devrait être cohérent dans la façon dont il appelle cette fonction. Exiger les guillemets dans '_evalBg" $ {cmd} "' au lieu de '_evalBg $ {cmd}' rendra le code plus gérable à long terme. – GreenRaccoon23

0

Par exemple, vous avez un programme de démarrage appelé terme.sh pour commencer à travailler en arrière-plan faire la ligne de commande suivante. ./run.sh &>/dev/null &