[PYTHON] Verhalten beim Angeben einer Liste mit shell = True im Unterprozess

Ursprung

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.

Was ich mich gefragt habe

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?

Was ich nachgeschlagen habe

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

Argumente nach sh-c

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.

Zusammenfassung

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

Verhalten beim Angeben einer Liste mit shell = True im Unterprozess
Beim Erstellen einer Matrix in einer Liste
Verhalten bei der Rückkehr in den with-Block
Beachten Sie beim Initialisieren einer Liste in Python
Verwenden Sie communic (), wenn Sie eine Ausgabe in einem Python-Unterprozess empfangen
Unterschiede im Verhalten zwischen den Operatoren append () und "+ =" beim Hinzufügen von Daten zu einer Liste in Python
Erstellen Sie ein Flag in den Einstellungen, das nur beim Testen mit Django True ist
Versuchen Sie, mit einer Shell zu programmieren!
Verhalten in jeder Sprache, wenn Collouts mit for wiederverwendet werden
Verarbeiten Sie die Dateien im Ordner in der Reihenfolge mit dem Shell-Skript
Führen Sie einen Befehl in Go wie Pythons subprocess.call aus (~, shell = True).
Flask-Erstellen Sie eine Todo-Liste mit CSRF-Maßnahmen mit WTF mit Flask
Verarbeiten Sie den Inhalt der Datei der Reihe nach mit einem Shell-Skript
Ruft eine Liste der Dateien in einem Ordner mit Python ohne Pfad ab
Laden Sie die Django-Shell mit ipython neu
[Python] Verwalten Sie Funktionen in einer Liste
Beim Schreiben eines Programms in Python
Rufen Sie mit Python eine Liste der in der aktuellen Umgebung installierten Pakete ab
Generieren Sie eine Liste mit der Anzahl der Tage im aktuellen Monat.
Erhalten Sie eine Liste der Ergebnisse der Parallelverarbeitung in Python mit Starmap
Was tun, wenn eine Warnmeldung in der Pip-Liste angezeigt wird?
Spiralbuch in Python! Python mit einem Spiralbuch! (Kapitel 14 ~)
Python3> im Schlüsselwort> Wahr mit teilweiser Übereinstimmung?
Vorsichtsmaßnahmen beim Beizen einer Funktion in Python
Zeigen Sie eine Liste der Alphabete in Python 3 an
Zeichne mit PyCall ein Herz in Ruby
Ändern Sie die Liste in der for-Anweisung
Eine Problemumgehung bei der Installation von pyAudio mit pip.
Verwalten Sie Protokollrotationsgenerationen mit einem Shell-Skript.
Implementieren Sie ein Modell mit Status und Verhalten
So übergeben Sie das Ergebnis der Ausführung eines Shell-Befehls in einer Liste in Python
Unterschiede im Verhalten jeder LL-Sprache, wenn der Listenindex übersprungen wird
Wenn beim Tippen einer interaktiven Shell mit Anaconda eine lange Fehlermeldung angezeigt wird
In GCS mit Python platzierte Zeichenketten werden beim Anzeigen mit einem Browser verstümmelt
So erhalten Sie mit Python eine Liste der Dateien im selben Verzeichnis