example check_output python subprocess

python - check_output - subprocess popen()



Significado real de ''shell=True'' en el subproceso (5)

Ejecutar programas a través del shell significa que toda la entrada de usuario que se pasa al programa se interpreta 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 debe obedecer estas reglas. Por ejemplo, las rutas que contienen caracteres de shell especiales como comillas o espacios en blanco deben ser escapadas. En el peor, causa filtraciones de seguridad, porque el usuario puede ejecutar programas arbitrarios.

shell=True es a veces conveniente para hacer uso de características de shell específicas como la división de palabras o la expansión de parámetros. Sin embargo, si se requiere dicha función, se le otorgan otros módulos (por ejemplo, os.path.expandvars() para la expansión de parámetros o shlex para división de palabras). Esto significa más trabajo, pero evita otros problemas.

En resumen: Evitar shell=True por todos los medios.

Estoy llamando a diferentes procesos con el módulo de subprocess . 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, llegué a saber que shell=True significa ejecutar el código a través del shell. Entonces eso significa en ausencia, el proceso se inicia directamente.

Entonces, ¿qué debería preferir para mi caso? Necesito ejecutar un proceso y obtener su resultado. ¿Qué beneficio tengo al llamarlo desde el caparazón o fuera de él?


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 ningún descendiente de shell bourne, solo cmd.exe.

Por lo tanto, invocar el shell invoca un programa de elección del usuario y depende de la plataforma. En general, evite las invocaciones a través del shell.

Invocar a través del shell le permite expandir variables de entorno y archivos globs de acuerdo con el mecanismo habitual del shell. En sistemas POSIX, el shell expande globs de archivos a una lista de archivos. En Windows, un glob de archivo (por ejemplo, "*. *") No se expande por el shell, de todos modos (pero las variables de entorno en una línea de comando se expanden mediante cmd.exe).

Si cree que desea expansiones de variables de entorno y archivos globs, investigue los ataques ILS de 1992-ish en servicios de red que realizan invocaciones de subprogramas a través del shell. Los ejemplos incluyen las diversas puertas traseras de sendmail implican ILS .

En resumen, use shell=False .


Las otras respuestas aquí explican adecuadamente las advertencias de seguridad que también se mencionan en la documentación del subprocess . Pero además de eso, la sobrecarga de iniciar un intérprete de comandos para iniciar el programa que desea ejecutar a menudo es innecesario y definitivamente tonto para situaciones en las que no utiliza realmente ninguna de las funciones del intérprete de comandos. Además, la complejidad oculta adicional debería asustarlo, especialmente si no está muy familiarizado con el shell o los servicios que proporciona.

La expansión de comodines, la interpolación de variables y la redirección son simples de reemplazar con construcciones nativas de Python. Una tubería de shell compleja donde partes o todas no pueden ser razonablemente reescritas en Python (herramientas externas especializadas, ¿tal vez fuente cerrada?) Sería la única situación donde quizás podría considerar usar el shell. Aún debes sentirte mal por eso.

En el caso trivial, simplemente reemplace

subprocess.Popen("command -with -options ''like this'' and// an// argument", shell=True)

con

subprocess.Popen([''command'', ''-with'',''-options'', ''like this'', ''and an argument''])

Observe cómo el primer argumento es una lista de cadenas para pasar a execvp() , y cómo citar cadenas y metacaracteres de shell que escapan de barra invertida generalmente no es necesario (ni útil, ni correcto).

Por otro lado, muy a menudo quiere evitar Popen si uno de los envoltorios más simples en el paquete de subprocess hace lo que quiere. Si tienes un Python lo suficientemente reciente, probablemente deberías usar subprocess.run .

  • Con check=True fallará si falla el comando que ejecutó.
  • Con stdout=subprocess.PIPE capturará la salida del comando.
  • Algo oscuramente, con universal_newlines=True descodificará la salida en una cadena Unicode adecuada (es solo bytes en la codificación del sistema de lo contrario, en Python 3).

De lo contrario, para muchas tareas, quiere que check_output obtenga el resultado de un comando, mientras verifica que tuvo éxito, o check_call si no hay salida para recopilar.

Cerraré con una cita de David Korn: "Es más fácil escribir un shell portátil que un script de shell portátil". Incluso subprocess.run(''echo "$HOME"'', shell=True) no es portátil para Windows.


Un ejemplo donde las cosas podrían salir mal con Shell = True se muestra aquí

>>> from subprocess import call >>> filename = input("What file would you like to display?/n") What file would you like to display? non_existent; rm -rf / # THIS WILL DELETE EVERYTHING IN ROOT PARTITION!!! >>> call("cat " + filename, shell=True) # Uh-oh. This will end badly...

Verifique el documento aquí: subprocess.call()


>>> import subprocess >>> subprocess.call(''echo $HOME'') Traceback (most recent call last): ... OSError: [Errno 2] No such file or directory >>> >>> subprocess.call(''echo $HOME'', shell=True) /user/khong 0

Establecer el argumento de shell en un valor verdadero hace que el subproceso genere un proceso de shell intermedio y le dice que ejecute el comando. En otras palabras, el uso de una capa intermedia significa que las variables, patrones glob y otras características especiales de la capa en la cadena de comandos se procesan antes de que se ejecute el comando. Aquí, en el ejemplo, $ HOME se procesó antes del comando echo. En realidad, este es el caso del comando con expansión de shell mientras que el comando ls -l considerado como un comando simple.

fuente: Módulo de subproceso