Estoy confundido sobre cómo usar correctamente el módulo de subproceso de Python, específicamente, el primer argumento del método check_output y la opción de shell . Consulte el resultado del mensaje interactivo a continuación. Paso el primer argumento como una lista y dependiendo de si shell=True está configurado, obtengo un resultado diferente. ¿Alguien puede explicar por qué es esto y la salida que se genera?
>>> import subprocess >>> subprocess.check_output(["echo", "Hello World!"]) 'Hello World!\n' >>> subprocess.check_output(["echo", "Hello World!"], shell=True) '\n'Ahora, cuando paso el primer argumento como una cadena simple en lugar de una lista, obtengo este rastro de pila desagradable. ¿Por qué es eso y qué está pasando aquí?
>>> subprocess.check_output("echo Hello World!") Traceback (most recent call last): File "<stdin>", line 1, in <module> File "/System/Library/Frameworks/Python.framework/Versions/2.7/lib/python2.7/subprocess.py", line 537, in check_output process = Popen(stdout=PIPE, *popenargs, **kwargs) File "/System/Library/Frameworks/Python.framework/Versions/2.7/lib/python2.7/subprocess.py", line 679, in __init__ errread, errwrite) File "/System/Library/Frameworks/Python.framework/Versions/2.7/lib/python2.7/subprocess.py", line 1228, in _execute_child raise child_exception OSError: [Errno 2] No such file or directorySin embargo, cuando activo shell=True, funciona perfectamente:
>>> subprocess.check_output("echo Hello World!", shell=True) 'Hello World!\n' Así que estoy un poco confundido, funciona cuando el primer argumento está en una lista SIN shell=True y luego funciona como una cadena simple CON shell=True . No entiendo qué hace shell=True y la diferencia entre pasar el primer argumento como una lista frente a una cadena.
De la documentación de Popen :
El argumento de shell (que por defecto es
False) especifica si usar el shell como el programa a ejecutar. Si shell esTrue, se recomienda pasarargscomo una cadena en lugar de una secuencia.En Unix con
shell=True, el shell predeterminado es/bin/sh. Si args es una cadena, la cadena especifica el comando a ejecutar a través del shell . Esto significa que la cadena debe formatearse exactamente como lo sería cuando se escribiera en el indicador de shell. Esto incluye, por ejemplo, comillas o barras invertidas que escapan de nombres de archivo con espacios en ellos. Si args es una secuencia, el primer elemento especifica la cadena de comando y cualquier elemento adicional se tratará como argumentos adicionales al propio shell . Es decir,Popenhace el equivalente a:Popen(['/bin/sh', '-c', args[0], args[1], ...])En Windows con
shell=True, la variable de entorno COMSPEC especifica el shell predeterminado. La única vez que necesita especificarshell=Trueen Windows es cuando el comando que desea ejecutar está integrado en el shell (por ejemplo,dirocopy). No necesitashell=Truepara ejecutar un archivo por lotes o un ejecutable basado en consola.
En su caso, dado que echo es un shell incorporado cuando se inicia con shell=True , si desea pasar argumentos al comando echo , debe escribir el comando como una cadena o pasar una secuencia que tenga el comando completo como una cadena como primer elemento. Otros elementos de la secuencia se pasan como argumentos al shell , no al comando que está invocando.
En algunos sistemas operativos, echo también es un programa (generalmente /bin/echo ). Esto explica por qué su primer ejemplo no generó una excepción, sino que genera '\n' en lugar del esperado 'Hello, World!\n' : el comando /bin/echo se ejecutó sin argumentos, porque el argumento fue "consumido" por la cáscara.
El error saltó al llamar:
subprocess.check_output("echo Hello World!") se debe a que, como no usaste shell=True , python está intentando ejecutar el programa echo Hello World! es decir, un programa que tiene el nombre echo<space>Hello<space>World! . Es un nombre de programa válido, pero no hay ningún programa con ese nombre, de ahí la excepción.
Cada vez que usa shell=True , ingresa como primer argumento para check_output una cadena entre comillas que representa lo que normalmente ingresa en un shell. "En Unix con shell=True, el shell predeterminado es /bin/sh ". Esto le da todas las características de shell. "Esto significa que la cadena se debe formatear exactamente como se escribiría en el indicador de shell". Ver Popen