Question

Lors de l'appel de scripts shell depuis Erlang, j'ai généralement besoin de leur état de sortie (0 ou autre), donc je les lance en utilisant cette fonction:

%% in module util
os_cmd_exitstatus(Action, Cmd) ->
    ?debug("~ts starting... Shell command: ~ts", [Action, Cmd]),
    try erlang:open_port({spawn, Cmd}, [exit_status, stderr_to_stdout]) of
        Port -> 
            os_cmd_exitstatus_loop(Action, Port)
    catch
        _:Reason ->
            case Reason of
                badarg ->
                    Message = "Bad input arguments";
                system_limit ->
                    Message = "All available ports in the Erlang emulator are in use";
                _ ->
                    Message = file:format_error(Reason)
            end,
            ?error("~ts: shell command error: ~ts", [Action, Message]),
            error
    end.

os_cmd_exitstatus_loop(Action, Port) ->
    receive
        {Port, {data, Data}} ->
            ?debug("~ts... Shell output: ~ts", [Action, Data]),
            os_cmd_exitstatus_loop(Action, Port);
        {Port, {exit_status, 0}} ->
            ?info("~ts finished successfully", [Action]),
            ok;
        {Port, {exit_status, Status}} ->
            ?error("~ts failed with exit status ~p", [Action, Status]),
            error;
        {'EXIT', Port, Reason} ->
            ?error("~ts failed with port exit: reason ~ts", 
                         [Action, file:format_error(Reason)]),
            error
    end.

Cela a bien fonctionné, jusqu'à ce que j'utilise ceci pour démarrer un script qui ferme un programme et quitte:

#!/bin/sh

FILENAME=$1

eog $FILENAME &

exit 0

(Dans le cas d'utilisation actuel, il y a pas mal d'arguments supplémentaires, et quelques massages avant qu'ils ne soient transmis au programme).Lorsqu'il est exécuté à partir du terminal, il affiche l'image et se termine immédiatement, comme prévu.

Mais en fuyant Erlang, ce n'est pas le cas.Dans le fichier journal, je vois que ça commence bien:

22/Mar/2011 13:38:30.518  Debug: Starting player starting... Shell command: /home/aromanov/workspace/gmcontroller/scripts.dummy/image/show-image.sh /home/aromanov/workspace/media/images/9e89471e-eb0b-43f8-8c12-97bbe598e7f7.png

et la fenêtre eog apparaît.Mais je ne comprends pas

22/Mar/2011 13:47:14.709  Info: Starting player finished successfully

jusqu'à tuer le processus eog (avec kill ou simplement fermer la fenêtre), ce qui ne convient pas à mes besoins.Pourquoi cette différence de comportement?Y a-t-il un moyen de résoudre ce problème?

Était-ce utile?

La solution

Normalement, si vous exécutez une commande en arrière-plan avec & dans un script shell et que le script shell se termine avant la commande, alors la commande devient orpheline. Il se peut que erlang essaie d'empêcher les processus orphelins dans open_port et attend que eog se termine. Normalement, si vous voulez exécuter quelque chose en arrière-plan pendant un script shell, vous devez mettre un wait à la fin du script pour attendre que vos processus d'arrière-plan se terminent. Mais c'est exactement ce que vous ne voulez pas faire.

Vous pouvez essayer ce qui suit dans votre script shell:

#!/bin/sh

FILENAME=$1

daemon eog $FILENAME

# exit 0 not needed: daemon returns 0 if everything is ok

Si votre système d'exploitation dispose d'une commande daemon. J'ai vérifié dans FreeBSD et il en a un: démon (8)

Ce n'est pas une commande disponible sur tous les systèmes Unix identiques, cependant il peut y avoir une commande différente faisant la même chose dans votre système d'exploitation.

L'utilitaire démon se détache du terminal de contrôle et exécute le programme spécifié par ses arguments.

Je ne suis pas sûr que cela résout votre problème, mais je soupçonne que eog reste en quelque sorte attaché à stdin / stdou comme une sorte de terminal de contrôle. Ça vaut le coup d'essayer de toute façon.

Cela devrait également résoudre le problème possible que le contrôle des tâches est activé par erreur, ce qui pourrait également causer le problème. Puisque daemon se ferme normalement, votre shell ne peut pas essayer d'attendre la tâche d'arrière-plan à la sortie car il n'y en a pas dans la vue des shells.

Cela dit: pourquoi ne pas simplement garder le port ouvert à Erlang pendant que eog s'exécute?

Commencez avec:

#!/bin/sh

FILENAME=$1

exec eog $FILENAME

L'appeler avec exec ne le fourche pas mais remplace le processus shell par eog. Le statut de sortie que vous verrez dans Erlang sera alors le statut de eog quand il se terminera. Vous avez également la possibilité de fermer le port et de terminer eog d'Erlang si vous le souhaitez.

Autres conseils

Peut-être que votre /bin/sh ne prend pas en charge le contrôle des tâches lorsqu'il n'est pas exécuté de manière interactive?Au moins le /bin/sh (en fait dash(1)!) Sur mon système Ubuntu mentionne:

      -m monitor       Turn on job control (set automatically
                       when interactive).

Lorsque vous exécutez le script à partir d'un terminal, le shell reconnaît probablement qu'il est exécuté de manière interactive et prend en charge le contrôle des tâches.Lorsque vous exécutez le script shell en tant que port, le shell s'exécute probablement sans contrôle de travail.

Licencié sous: CC-BY-SA avec attribution
Non affilié à StackOverflow
scroll top