web-dev-qa-db-fra.com

Python subprocess.call n'attend pas que le processus se termine blender

J'ai un script Python dans Blender où il a

subprocess.call(os.path.abspath('D:/Test/run-my-script.sh'),Shell=True)

suivi de nombreux autres codes qui dépendent de ce script Shell pour finir. Qu'est-ce qui se passe, c'est qu'il n'attend pas la fin, je ne sais pas pourquoi? J'ai même essayé d'utiliser Popen au lieu de call comme indiqué:

p1 = subprocess.Popen(os.path.abspath('D:/Test/run-my-script.sh'),Shell=True)
p1.wait()

et j'ai essayé d'utiliser commuincate mais cela n'a toujours pas fonctionné:

p1 = subprocess.Popen(os.path.abspath('D:/Test/run-my-script.sh'),Shell=True).communicate()

ce script shell fonctionne parfaitement sur MacOS (après modification des chemins) et attend lorsque vous utilisez subprocess.call(['sh', '/userA/Test/run-my-script.sh'])

mais sous Windows, c’est ce qui se passe, j’exécute le script python ci-dessous dans Blender puis, une fois que celui-ci est entré dans la ligne de sous-processus, Git bash est ouvert et exécute le script Shell tant que Blender n’attend pas la fin du processus, imprime simplement Hello dans sa console sans en attendant que le Git Bash soit terminé. De l'aide?

import bpy
import subprocess
subprocess.call(os.path.abspath('D:/Test/run-my-script.sh'),Shell=True)
print('Hello')
10
Tak

Vous pouvez utiliser subprocess.call pour faire exactement cela.

sous-processus .call (arguments, *, stdin = Aucun, stdout = Aucun, stderr = Aucun, Shell = False, délai d'expiration = Aucun)

Exécutez la commande décrite par args. Attendez que la commande soit terminée, puis renvoyez l'attribut returncode.

Edit: Je pense avoir une idée de ce qui se passe. La commande fonctionne sur votre Mac car les Macs, je crois, prennent en charge Bash dès la sortie de la boîte (au moins quelque chose d’équivalent du point de vue fonctionnel) alors que sous Windows, elle tente de lancer un fichier ".sh" et se déclenche. Git Bash que je présume effectue quelques fourches lors du démarrage.

A cause de ce Python pense que votre script est terminé, le PID est parti. 

Si j'étais vous, je ferais ceci:

  • Générez un chemin absolu, unique et non existant dans votre script de "lancement" à l'aide du module tempfile .
  • Lors du lancement du script, transmettez le chemin que vous venez de créer en tant qu'argument.
  • Lorsque le script démarre, demandez-lui de créer un fichier dans le chemin. Une fois terminé, supprimez le fichier.
  • Le script de lancement doit surveiller la création et la suppression de ce fichier pour indiquer son statut. 

Espérons que cela a du sens.

4
joeb

Vous pouvez utiliser l'API Popen.communicate.

p1 = subprocess.Popen(os.path.abspath('D:/Test/run-my-script.sh'),Shell=True)
sStdout, sStdErr = p1.communicate()

La commande

Popen.communicate(input=None, timeout=None)

Interagir avec le processus: envoyer des données à stdin. Lire les données de stdout et stderr jusqu'à la fin du fichier. Attendez que le processus se termine.

4
Pankaj

subprocess.run attendra par défaut que le processus se termine. 

3
Grr

Utilisez subprocess.Popen et Popen.wait:

process = subprocess.Popen(['D:/Test/run-my-script.sh'],Shell=True, executable="/bin/bash")
process.wait()

Vous pouvez également utiliser check_call () au lieu de Popen.

2
Fran Raga

Vous pouvez utiliser os.system, comme ceci:

import bpy
import os
os.system("sh "+os.path.abspath('D:/Test/run-my-script.sh'))
print('Hello')
1
A STEFANI

Il y a apparemment des cas où la commande d'exécution échoue . Voici ma solution de contournement:

def check_has_finished(pfi, interval=1, timeout=100):
    if os.path.exists(pfi):
        if pfi.endswith('.nii.gz'):
            mustend = time.time() + timeout
            while time.time() < mustend:
                try:
                    # Command is an ad hoc one to check if the process  has finished.
                    subprocess.check_output('command {}'.format(pfi), Shell=True)
                except subprocess.CalledProcessError:
                    print "Caught CalledProcessError"
                else:
                    return True
                time.sleep(interval)
            msg = 'command {0} not working after {1} tests. \n'.format(pfi, timeout)
            raise IOError(msg)
        else:
            return True
    else:
        msg = '{} does not exist!'.format(pfi)
        raise IOError(msg)
0
SeF

Un essai sauvage, mais exécutez-vous le Shell en tant qu'administrateur alors que Blender en tant qu'utilisateur ordinaire ou vice versa? 

En bref (très court), Windows UAC est une sorte d’environnement isolé entre l’administrateur et l’utilisateur habituel, de telles aléas peuvent donc se produire. Malheureusement, je ne me souviens pas de la source, le plus proche que j'ai trouvé est ceci

Mon problème était l'exact opposé du vôtre, la wait() est restée coincée dans une boucle infinie parce que mon python REPL a été déclenché par un shell d'administrateur et n'a pas pu lire l'état du sous-processus utilisateur normal. Revenant à l'utilisateur normal, Shell l'a corrigé. Ce n'est pas la première fois que je me moque de ce snafu UAC.

0
Gruber