Si vous essayez d'exécuter un fichier avec jar intégré dans un script shell comme embulk ou digdag en utilisant un sous-processus Python avec shell = False
>>> import subprocess
>>> subprocess.check_call(["digdag"])
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
File "/usr/local/Cellar/python/2.7.13/Frameworks/Python.framework/Versions/2.7/lib/python2.7/subprocess.py", line 181, in check_call
retcode = call(*popenargs, **kwargs)
File "/usr/local/Cellar/python/2.7.13/Frameworks/Python.framework/Versions/2.7/lib/python2.7/subprocess.py", line 168, in call
return Popen(*popenargs, **kwargs).wait()
File "/usr/local/Cellar/python/2.7.13/Frameworks/Python.framework/Versions/2.7/lib/python2.7/subprocess.py", line 390, in __init__
errread, errwrite)
File "/usr/local/Cellar/python/2.7.13/Frameworks/Python.framework/Versions/2.7/lib/python2.7/subprocess.py", line 1024, in _execute_child
raise child_exception
OSError: [Errno 8] Exec format error
Cela échoue comme. Cela peut être évité en définissant shell = True, mais j'ai étudié comment passer des arguments au programme car c'était différent lorsque shell était False (par défaut) et quand il était True.
Si vous donnez une liste lorsque shell = False, elle sera traitée comme une commande et ses arguments. Par exemple
sample.sh
#!/bin/sh
echo "$1", "$2", "$3" > out.txt
Code qui appelle le script shell appelé à l'aide de subprocess.check_call
caller_l0.py
import subprocess
cmd = ["./sample.sh", "1starg", "2ndarg", "3rdarg"]
subprocess.check_call(cmd, shell=False)
Lorsque vous exécutez
$ python caller_l0.py
$ cat out.txt
1starg, 2ndarg, 3rdarg
Vous pouvez voir que les arguments sont passés comme prévu. Réglez-le simplement sur shell = True et
caller_l1.py
import subprocess
cmd = ["./sample.sh", "1starg", "2ndarg", "3rdarg"]
subprocess.check_call(cmd, shell=True)
Lorsque vous exécutez
$ python caller_l1.py
$ cat out.txt
, ,
Où êtes-vous allé après le deuxième élément de la liste?
La documentation officielle (https://docs.python.org/3/library/subprocess.html) décrit les paramètres args à passer au sous-processus:
args is required for all calls and should be a string, or a sequence of program arguments.
Providing a sequence of arguments is generally preferred, as it allows the module to take
care of any required escaping and quoting of arguments (e.g. to permit spaces in file names).
If passing a single string, either shell must be True (see below) or else the string must
simply name the program to be executed without specifying any arguments.
Il n'y a pas d'explication ici pour le cas où la liste est donnée avec shell = True. Si tu regardes un peu plus
If args is a sequence, the first item specifies the command string, and any additional
items will be treated as additional arguments to the shell itself.
That is to say, Popen does the equivalent of:
Popen(['/bin/sh', '-c', args[0], args[1], ...])
Sur MacOS, / bin / sh est bash, donc si vous faites man
-c string If the -c option is present, then commands are read from
string. If there are arguments after the string, they are
assigned to the positional parameters, starting with $0.
Je ne l'ai pas compris, alors je l'ai cherché https://stackoverflow.com/questions/1711970/cant-seem-to-use-bash-c-option-with-arguments-after-the-c Je suis arrivé à -option-string et j'ai compris que \ $ 0, \ $ 1, ... dans la chaîne donnée à -c serait remplacé.
caller_l1_.py
import subprocess
cmd = ["./sample.sh $0 $1 $2", "1starg", "2ndarg", "3rdarg"]
subprocess.check_call(cmd, shell=True)
$ python caller_l1_.py
$ cat out.txt
1starg, 2ndarg, 3rdarg
Quand j'ai vérifié le comportement lorsque plusieurs arguments étaient passés après sh -c, autres que bash, c'était le même comportement avec le tiret d'Ubuntu et sh de FreeBSD. De là, je me suis demandé s'il y avait une utilité pour cela.
$ bash -c '$0 $1, $2, $3' echo '1-0 1-1' 2 3
1-0 1-1, 2, 3
Ensuite, appliquez celui cité et faites de même via le sous-processus.
$ python -c 'import subprocess;subprocess.check_call(["$0 $1, $2, $3", "echo", "1-0 1-1", "2", "3"], shell=True)'
1-0 1-1, 2, 3
Cependant, si tel est le cas, vous pouvez étendre la chaîne de caractères depuis le début, tandis que d'un autre côté
caller_l1__.py
import subprocess
cmd = ["$0 $1 $2 $3", "./sample.sh", "1-1 1-2", "2", "3"]
subprocess.check_call(cmd, shell=True)
Parce que celui qui a été remplacé n'est passé qu'à sample.sh
$ python caller_l1__.py
$ cat out.txt
1-1, 1-2, 2
Après tout, je ne savais pas trop où donner plusieurs arguments après -c.
Le comportement lorsqu'une liste est passée avec shell = True dans le sous-processus Python est similaire au comportement lorsque plusieurs arguments sont passés après sh -c. Cependant, je ne savais pas comment l'utiliser (quelqu'un me l'a dit).
Lorsque shell = True, j'ai senti qu'il était simple de spécifier une chaîne de caractères au lieu d'une liste.
caller_s1.py
import subprocess
cmd = "./sample.sh 1starg 2ndarg 3rdarg"
subprocess.check_call(cmd, shell=True)
$ python2.7 caller_s1.py
$ cat out.txt
1starg, 2ndarg, 3rdarg
Recommended Posts