script interprete ejecutar desde consola compilar comandos python linux operating-system

interprete - ¿Por qué usar los métodos del módulo os de Python en lugar de ejecutar comandos de shell directamente?



ejecutar.py desde consola python (6)

  1. Es más rápido , os.system y subprocess.call crean nuevos procesos que son innecesarios para algo tan simple. De hecho, os.system y subprocess.call con el argumento de shell generalmente crean al menos dos procesos nuevos: el primero es el shell y el segundo el comando que está ejecutando (si no es un shell incorporado) como test ).

  2. Algunos comandos son inútiles en un proceso separado . Por ejemplo, si ejecuta os.spawn("cd dir/") , cambiará el directorio de trabajo actual del proceso secundario, pero no del proceso de Python. Necesitas usar os.chdir para eso.

  3. No tiene que preocuparse por los caracteres especiales interpretados por el shell. os.chmod(path, mode) funcionará sin importar cuál sea el nombre de archivo, mientras que os.spawn("chmod 777 " + path) fallará horriblemente si el nombre de archivo es algo así ; rm -rf ~ ; rm -rf ~ . (Tenga en cuenta que puede solucionar esto si usa subprocess.call sin el argumento de shell ).

  4. No tiene que preocuparse por los nombres de archivo que comienzan con un guión . os.chmod("--quiet", mode) cambiará los permisos del archivo llamado --quiet , pero os.spawn("chmod 777 --quiet") fallará, ya que --quiet se interpreta como un argumento. Esto es cierto incluso para subprocess.call(["chmod", "777", "--quiet"]) .

  5. Tiene menos preocupaciones entre plataformas y conchas cruzadas, ya que se supone que la biblioteca estándar de Python se ocupará de eso por usted. ¿Su sistema tiene el comando chmod ? ¿Está instalado? ¿Admite los parámetros que espera que admita? El módulo os intentará ser lo más multiplataforma posible y documentará cuando eso no sea posible.

  6. Si el comando que está ejecutando tiene un resultado que le interesa, debe analizarlo, lo que es más complicado de lo que parece, ya que puede olvidarse de las mayúsculas y minúsculas (nombres de archivo con espacios, pestañas y nuevas líneas en ellas), incluso cuando No me importa la portabilidad.

Estoy tratando de entender cuál es la motivación detrás del uso de las funciones de la biblioteca de Python para ejecutar tareas específicas del sistema operativo, como crear archivos / directorios, cambiar los atributos de los archivos, etc., en lugar de simplemente ejecutar esos comandos a través de os.system() o subprocess.call() ?

Por ejemplo, ¿por qué querría usar os.chmod lugar de hacer os.system("chmod...") ?

Entiendo que es más "pitónico" usar los métodos de biblioteca disponibles de Python tanto como sea posible en lugar de simplemente ejecutar comandos de shell directamente. Pero, ¿hay alguna otra motivación detrás de hacer esto desde un punto de vista funcional?

Solo estoy hablando de ejecutar comandos simples de shell de una línea aquí. Cuando necesitamos más control sobre la ejecución de la tarea, entiendo que usar el módulo de subprocess tiene más sentido, por ejemplo.


Es mas seguro. Para darle una idea aquí hay un script de ejemplo

import os file = raw_input("Please enter a file: ") os.system("chmod 777 " + file)

Si la entrada del usuario fue de test; rm -rf ~ test; rm -rf ~ esto eliminaría el directorio de inicio.

Es por eso que es más seguro usar la función integrada.

Por lo tanto, también debería utilizar el subproceso en lugar del sistema.


Es mucho más eficiente. El "shell" es solo otro binario del sistema operativo que contiene muchas llamadas al sistema. ¿Por qué incurrir en la sobrecarga de crear todo el proceso de shell solo para esa única llamada al sistema?

La situación es aún peor cuando usas os.system para algo que no es un shell incorporado. Inicia un proceso de shell que a su vez inicia un ejecutable que luego (a dos procesos de distancia) realiza la llamada al sistema. Al menos el subprocess habría eliminado la necesidad de un proceso intermedio de shell.

No es específico de Python, esto. systemd es una mejora para los tiempos de inicio de Linux por la misma razón: hace que el sistema necesario se llame a sí mismo en lugar de generar miles de shells.


Existen cuatro casos sólidos para preferir los métodos más específicos de Python en el módulo os en lugar de usar os.system o el módulo de subprocess al ejecutar un comando:

  • Redundancia : generar otro proceso es redundante y desperdicia tiempo y recursos.
  • Portabilidad : muchos de los métodos del módulo os están disponibles en varias plataformas, mientras que muchos comandos de shell son específicos de os.
  • Comprender los resultados : generar un proceso para ejecutar comandos arbitrarios te obliga a analizar los resultados de la salida y comprender si un comando ha hecho algo incorrecto y por qué .
  • Seguridad : un proceso puede ejecutar potencialmente cualquier comando que se le dé. Este es un diseño débil y puede evitarse utilizando métodos específicos en el módulo os .

Redundancia (ver código redundante ):

En realidad, está ejecutando un "intermediario" redundante en su camino a las llamadas eventuales del sistema ( chmod en su ejemplo). Este intermediario es un nuevo proceso o sub-shell.

Desde os.system :

Ejecute el comando (una cadena) en una subshell ...

Y el subprocess es solo un módulo para generar nuevos procesos.

Puede hacer lo que necesita sin generar estos procesos.

Portabilidad (ver portabilidad del código fuente ):

El objetivo del módulo os es proporcionar servicios genéricos del sistema operativo y su descripción comienza con:

Este módulo proporciona una forma portátil de utilizar la funcionalidad dependiente del sistema operativo.

Puede usar os.listdir en Windows y Unix. Intentar usar os.system / subprocess para esta funcionalidad te obligará a mantener dos llamadas (para ls / dir ) y verificar en qué sistema operativo estás. Esto no es tan portátil y causará aún más frustración más adelante (ver Salida de manejo ).

Comprender los resultados del comando:

Suponga que desea enumerar los archivos en un directorio.

Si está usando os.system("ls") / subprocess.call([''ls'']) , solo puede recuperar la salida del proceso, que es básicamente una cadena grande con los nombres de archivo.

¿Cómo puede distinguir un archivo con un espacio en su nombre de dos archivos?

¿Qué sucede si no tiene permiso para enumerar los archivos?

¿Cómo debe asignar los datos a los objetos de Python?

Estos solo están fuera de mi cabeza, y si bien hay soluciones a estos problemas, ¿por qué resolver de nuevo un problema que se resolvió para usted?

Este es un ejemplo de seguir el principio de No repetirse (a menudo denominado "SECO") al no repetir una implementación que ya existe y está disponible gratuitamente para usted.

La seguridad:

os.system y subprocess son potentes. Es bueno cuando necesitas este poder, pero es peligroso cuando no lo necesitas. Cuando usa os.listdir , sabe que no puede hacer nada más que enumerar archivos o generar un error. Cuando usa os.system o subprocess para lograr el mismo comportamiento, puede terminar haciendo algo que no quiso hacer.

Seguridad de inyección (ver ejemplos de inyección de conchas ) :

Si usa la entrada del usuario como un nuevo comando, básicamente le ha dado un shell. Esto es muy parecido a la inyección SQL que proporciona un shell en la base de datos para el usuario.

Un ejemplo sería un comando de la forma:

# ... read some user input os.system(user_input + " some continutation")

Esto puede explotarse fácilmente para ejecutar cualquier código arbitrario utilizando la entrada: NASTY COMMAND;# para crear el eventual:

os.system("NASTY COMMAND; # some continuation")

Hay muchos de estos comandos que pueden poner en riesgo su sistema.


Las llamadas de shell son específicas del sistema operativo, mientras que las funciones del módulo de Python os no lo son, en la mayoría de los casos. Y evita generar un subproceso.


Por una simple razón: cuando se llama a una función de shell, crea un sub-shell que se destruye después de que exista su comando, por lo que si cambia el directorio en un shell, no afecta su entorno en Python.

Además, la creación de sub-shell lleva mucho tiempo, por lo que usar los comandos del sistema operativo directamente afectará su rendimiento

EDITAR

Tuve algunas pruebas de tiempo en ejecución:

In [379]: %timeit os.chmod(''Documents/recipes.txt'', 0755) 10000 loops, best of 3: 215 us per loop In [380]: %timeit os.system(''chmod 0755 Documents/recipes.txt'') 100 loops, best of 3: 2.47 ms per loop In [382]: %timeit call([''chmod'', ''0755'', ''Documents/recipes.txt'']) 100 loops, best of 3: 2.93 ms per loop

La función interna se ejecuta más de 10 veces más rápido

EDIT2

Puede haber casos en los que invocar un ejecutable externo puede producir mejores resultados que los paquetes de Python: acabo de recordar un correo enviado por un colega mío que decía que el rendimiento de gzip llamado a través del subproceso fue mucho mayor que el rendimiento de un paquete de Python que utilizó. Pero ciertamente no cuando hablamos de paquetes estándar del sistema operativo que emulan comandos estándar del sistema operativo