Wenn Sie versuchen, eine Datei mit jar auszuführen, die in ein Shell-Skript wie embulk oder digdag mit shell = False eingebettet ist, verwenden Sie den Python-Unterprozess
>>> 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
Es scheitert gerne. Dies kann vermieden werden, indem shell = True gesetzt wird. Ich habe jedoch untersucht, wie Argumente an das Programm übergeben werden, da es anders war, wenn die Shell False (Standard) und True war.
Wenn Sie eine Liste angeben, wenn shell = False ist, wird sie als Befehl und ihre Argumente verarbeitet. Zum Beispiel
sample.sh
#!/bin/sh
echo "$1", "$2", "$3" > out.txt
Code, der das mit subprocess.check_call aufgerufene Shell-Skript aufruft
caller_l0.py
import subprocess
cmd = ["./sample.sh", "1starg", "2ndarg", "3rdarg"]
subprocess.check_call(cmd, shell=False)
Wenn Sie ausführen
$ python caller_l0.py
$ cat out.txt
1starg, 2ndarg, 3rdarg
Sie können sehen, dass die Argumente wie beabsichtigt übergeben werden. Setzen Sie es einfach auf shell = True und
caller_l1.py
import subprocess
cmd = ["./sample.sh", "1starg", "2ndarg", "3rdarg"]
subprocess.check_call(cmd, shell=True)
Wenn Sie ausführen
$ python caller_l1.py
$ cat out.txt
, ,
Wohin sind Sie nach dem zweiten Element der Liste gegangen?
In der offiziellen Dokumentation (https://docs.python.org/3/library/subprocess.html) werden die args-Parameter beschrieben, die an den Unterprozess übergeben werden sollen:
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.
Es gibt hier keine Erklärung für den Fall, dass die Liste mit shell = True angegeben wird. Wenn du ein bisschen mehr aussiehst
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], ...])
Unter MacOS ist / bin / sh bash, wenn Sie also Mann sind
-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.
Ich habe es nicht verstanden, also habe ich danach gesucht https://stackoverflow.com/questions/1711970/cant-seem-to-use-bash-c-option-with-arguments-after-the-c Ich kam zu -option-string und verstand, dass \ $ 0, \ $ 1, ... in dem String, der -c gegeben wurde, ersetzt werden würde.
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
Als ich das Verhalten überprüfte, wenn nach sh -c mehrere Argumente übergeben wurden, außer bash, war es dasselbe Verhalten mit einem Schuss Ubuntu und sh von FreeBSD. Daraus heraus fragte ich mich, ob es irgendeinen Sinn dafür gab.
$ bash -c '$0 $1, $2, $3' echo '1-0 1-1' 2 3
1-0 1-1, 2, 3
Wenden Sie dann den angegebenen Wert an und führen Sie dasselbe über den Unterprozess aus.
$ 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
In diesem Fall können Sie die Zeichenfolge jedoch von Anfang an erweitern
caller_l1__.py
import subprocess
cmd = ["$0 $1 $2 $3", "./sample.sh", "1-1 1-2", "2", "3"]
subprocess.check_call(cmd, shell=True)
Weil die nach dem Ersetzen nur an sample.sh übergeben wird
$ python caller_l1__.py
$ cat out.txt
1-1, 1-2, 2
Schließlich war ich mir nicht sicher, wo ich nach -c mehrere Argumente angeben sollte.
Das Verhalten beim Übergeben einer Liste mit shell = True im Python-Unterprozess ähnelt dem Verhalten, wenn nach sh -c mehrere Argumente übergeben werden. Ich wusste jedoch nicht, wie ich es verwenden sollte (jemand sagte es mir).
Wenn shell = True ist, war es für mich unkompliziert, eine Zeichenfolge anstelle einer Liste anzugeben.
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