Estoy llamando a diferentes procesos con el subprocess
módulo. Sin embargo, tengo una pregunta.
En los siguientes códigos:
callProcess = subprocess.Popen(['ls', '-l'], shell=True)
y
callProcess = subprocess.Popen(['ls', '-l']) # without shell
Ambos trabajan. Después de leer los documentos, supe que eso shell=True
significa ejecutar el código a través del shell. Eso significa que en ausencia, el proceso se inicia directamente.
Entonces, ¿qué debería preferir para mi caso? Necesito ejecutar un proceso y obtener su salida. ¿Qué beneficio tengo de llamarlo desde dentro del shell o fuera de él?
python
subprocess
usuario225312
fuente
fuente
-l
se pasa a/bin/sh
(el shell) en lugar dells
programa en Unix sishell=True
. El argumento de cadena debe usarseshell=True
en la mayoría de los casos en lugar de una lista.shell=True
aFalse
y viceversa es un error. Desde documentos : "En POSIX con shell = True, (...) Si args es una secuencia, el primer elemento especifica la cadena de comando, y cualquier elemento adicional se tratará como argumentos adicionales para el propio shell". En Windows hay una conversión automática , que puede no ser deseada.Respuestas:
El beneficio de no llamar a través del shell es que no está invocando un 'programa misterioso'. En POSIX, la variable de entorno
SHELL
controla qué binario se invoca como el "shell". En Windows, no hay descendiente de shell bourne, solo cmd.exe.Invocar el shell invoca un programa de elección del usuario y depende de la plataforma. En términos generales, evite las invocaciones a través del shell
Invocar a través del shell le permite expandir variables de entorno y archivos globales de acuerdo con el mecanismo habitual del shell. En los sistemas POSIX, el shell expande los archivos globales a una lista de archivos. En Windows, un pegote de archivos (por ejemplo, "*. *") No se expande por la cáscara, de todos modos (pero variables de entorno en una línea de comandos están expandido en cmd.exe).
Si cree que desea expansiones variables de entorno y globos de archivos, investigue los
ILS
ataques de 1992-ish en los servicios de red que realizaron invocaciones de subprogramas a través del shell. Los ejemplos incluyen las diversassendmail
puertas traseras involucradasILS
.En resumen, use
shell=False
.fuente
$SHELL
no es correcta. Para citar subprocess.html: "En Unix conshell=True
, el shell por defecto es/bin/sh
". (no$SHELL
)open
si desea formas seguras de invocar un programa y capturar la salida.fuente: Módulo de subproceso
fuente
Aquí se muestra un ejemplo en el que las cosas podrían salir mal con Shell = True
Consulta el documento aquí: subprocess.call ()
fuente
La ejecución de programas a través del shell significa que todas las entradas del usuario pasadas al programa se interpretan de acuerdo con la sintaxis y las reglas semánticas del shell invocado. En el mejor de los casos, esto solo causa inconvenientes al usuario, porque el usuario tiene que obedecer estas reglas. Por ejemplo, las rutas que contienen caracteres especiales de shell como comillas o espacios en blanco deben escaparse. En el peor de los casos, causa fugas de seguridad, porque el usuario puede ejecutar programas arbitrarios.
shell=True
A veces es conveniente hacer uso de funciones específicas de shell como división de palabras o expansión de parámetros. Sin embargo, si se requiere dicha función, utilice otros módulos que se le proporcionan (por ejemplo,os.path.expandvars()
para la expansión de parámetros oshlex
para la división de palabras). Esto significa más trabajo, pero evita otros problemas.En resumen: evitar
shell=True
por todos los medios.fuente
Las otras respuestas aquí explican adecuadamente las advertencias de seguridad que también se mencionan en la
subprocess
documentación. Pero además de eso, la sobrecarga de iniciar un shell para iniciar el programa que desea ejecutar a menudo es innecesaria y definitivamente tonta para situaciones en las que realmente no utiliza ninguna de las funciones del shell. Además, la complejidad oculta adicional debería asustarlo, especialmente si no está muy familiarizado con el shell o los servicios que proporciona.Cuando las interacciones con el shell no son triviales, ahora necesita que el lector y el responsable del script Python (que puede ser o no su futuro yo) comprenda tanto el script Python como el shell. Recuerde el lema de Python "explícito es mejor que implícito"; incluso cuando el código de Python va a ser algo más complejo que el script de shell equivalente (y a menudo muy breve), es mejor que elimine el shell y reemplace la funcionalidad con construcciones de Python nativas. Minimizar el trabajo realizado en un proceso externo y mantener el control dentro de su propio código en la medida de lo posible suele ser una buena idea simplemente porque mejora la visibilidad y reduce los riesgos de efectos secundarios deseados o no deseados.
La expansión de comodines, la interpolación variable y la redirección son fáciles de reemplazar con construcciones nativas de Python. Una tubería compleja de shell en la que partes o todas las partes no pueden reescribirse razonablemente en Python sería la única situación en la que quizás podría considerar usar el shell. Todavía debe asegurarse de comprender las implicaciones de rendimiento y seguridad.
En el caso trivial, para evitar
shell=True
, simplemente reemplacecon
Observe cómo el primer argumento es una lista de cadenas para pasar
execvp()
, y cómo citar cadenas y metacaracteres de shell con barra invertida generalmente no es necesario (o útil o correcto). Quizás vea también ¿ Cuándo ajustar las comillas alrededor de una variable de shell?Como comentario aparte, a menudo desea evitar
Popen
si uno de los envoltorios más simples delsubprocess
paquete hace lo que desea. Si tiene un Python lo suficientemente reciente, probablemente debería usarlosubprocess.run
.check=True
esto fallará si el comando que ejecutó falló.stdout=subprocess.PIPE
él capturará la salida del comando.universal_newlines=True
él decodificará la salida en una cadena Unicode adecuada (de lobytes
contrario, solo está en la codificación del sistema, en Python 3).Si no, para muchas tareas, desea
check_output
obtener la salida de un comando, mientras verifica que tuvo éxito, ocheck_call
si no hay salida para recopilar.Terminaré con una cita de David Korn: "Es más fácil escribir un shell portátil que un script de shell portátil". Even
subprocess.run('echo "$HOME"', shell=True)
no es portátil para Windows.fuente
shell=True
, muchas con excelentes respuestas. Por casualidad elegiste el que trata sobre por qué .subprocess