Cuando se usa os.system () a menudo es necesario escapar de los nombres de archivo y otros argumentos pasados como parámetros a los comandos. ¿Cómo puedo hacer esto? Preferiblemente algo que funcione en múltiples sistemas operativos / shells pero en particular para bash.
Actualmente estoy haciendo lo siguiente, pero estoy seguro de que debe haber una función de biblioteca para esto, o al menos una opción más elegante / robusta / eficiente:
def sh_escape(s):
return s.replace("(","\\(").replace(")","\\)").replace(" ","\\ ")
os.system("cat %s | grep something | sort > %s"
% (sh_escape(in_filename),
sh_escape(out_filename)))
Editar: he aceptado la respuesta simple de usar comillas, no sé por qué no pensé en eso; Supongo que porque vine de Windows donde 'y "se comportan un poco diferente.
Con respecto a la seguridad, entiendo la preocupación, pero, en este caso, estoy interesado en una solución rápida y fácil que os.system () proporcione, y la fuente de las cadenas no es generada por el usuario o al menos ingresada por un usuario de confianza (yo).
sh_escape
función ideal sería escapar de los;
espacios y eliminar el problema de seguridad simplemente creando un archivo llamado algo asífoo.txt\;\ rm\ -rf\ /
.Respuestas:
Esto es lo que uso:
El shell siempre aceptará un nombre de archivo entre comillas y eliminará las comillas circundantes antes de pasarlo al programa en cuestión. En particular, esto evita problemas con los nombres de archivo que contienen espacios o cualquier otro tipo de metacarácter de shell desagradable.
Actualización : si está utilizando Python 3.3 o posterior, use shlex.quote en lugar de rodar el suyo.
fuente
shlex
opipes
. Esos módulos de Python erróneamente asumen que los caracteres especiales son la única cosa que necesitan ser citado, lo que significa que Shell palabras clave (comotime
,case
owhile
) se analiza cuando no se espera que el comportamiento. Por esa razón, recomendaría usar la rutina de comillas simples en esta respuesta, porque no trata de ser "inteligente", por lo que no tiene esos casos tontos.shlex.quote()
hace lo que quieres desde python 3.(Úselo
pipes.quote
para admitir python 2 y python 3)fuente
commands.mkarg
. También agrega un espacio inicial (fuera de las comillas) que puede o no ser deseable. Es interesante cómo sus implementaciones son bastante diferentes entre sí, y también mucho más complicado que la respuesta de Greg Hewgill.pipes.quote
no se menciona en la documentación de la biblioteca estándar para el módulo de tuberíascommand.mkarg
es obsoleto y eliminado en 3.x, mientras que tuberías.quote permaneció.shlex.quote()
en 3.3,pipes.quote()
retenido por compatibilidad. [ bugs.python.org/issue9723]Quizás tenga una razón específica para usar
os.system()
. Pero si no, probablemente deberías estar usando elsubprocess
módulo . Puede especificar las tuberías directamente y evitar usar el shell.Lo siguiente es de PEP324 :
fuente
subprocess
(especialmente concheck_call
etc.) a menudo es dramáticamente superior, pero hay algunos casos en los que el escape de shell sigue siendo útil. El principal con el que me encuentro es cuando tengo que invocar comandos remotos ssh.Tal vez
subprocess.list2cmdline
es una mejor oportunidad?fuente
subprocess.list2cmdline(["'",'',"\\",'"'])
da' "" \ \"
list2cmdline
ajusta a la sintaxis cmd.exe de Windows ( consulte la función docstring en el código fuente de Python ).shlex.quote
se ajusta a la sintaxis de shell bourne de Unix, sin embargo, generalmente no es necesario ya que Unix tiene un buen soporte para pasar argumentos directamente. Windows prácticamente requiere que pase una sola cadena con todos sus argumentos (por lo tanto, la necesidad de un escape adecuado).Tenga en cuenta que pipes.quote en realidad está roto en Python 2.5 y Python 3.1 y no es seguro de usar: no maneja argumentos de longitud cero.
Ver Python número 7476 ; Se ha corregido en Python 2.6 y 3.2 y posteriores.
fuente
Aviso : esta es una respuesta para Python 2.7.x.
Según la fuente ,
pipes.quote()
es una forma de " Citar una cadena de forma confiable como un argumento único para / bin / sh ". (Aunque está en desuso desde la versión 2.7 y finalmente se expone públicamente en Python 3.3 como lashlex.quote()
función).Por otro lado ,
subprocess.list2cmdline()
es una forma de " Traducir una secuencia de argumentos a una cadena de línea de comando, utilizando las mismas reglas que el tiempo de ejecución de MS C ".Aquí estamos, la forma independiente de la plataforma de citar cadenas para líneas de comando.
Uso:
fuente
Creo que os.system solo invoca cualquier shell de comandos configurado para el usuario, por lo que no creo que pueda hacerlo de forma independiente de la plataforma. Mi shell de comandos podría ser cualquier cosa, desde bash, emacs, ruby o incluso quake3. Algunos de estos programas no esperan el tipo de argumentos que les está pasando e incluso si lo hicieran, no hay garantía de que escapen de la misma manera.
fuente
La función que uso es:
es decir: siempre incluyo el argumento entre comillas dobles, y luego la barra invertida entre comillas los únicos caracteres especiales dentro de las comillas dobles.
fuente
pipes.quote
que @JohnWiseman señaló también está rota. La respuesta de Greg Hewgill es, por lo tanto, la que hay que usar. (También es el que usan los proyectiles internamente para los casos normales.)Si utiliza el comando del sistema, intentaría incluir en la lista blanca lo que se incluye en la llamada os.system (). Por ejemplo ...
El módulo de subproceso es una mejor opción, y recomendaría intentar evitar usar algo como os.system / subprocess siempre que sea posible.
fuente
La verdadera respuesta es: no utilizar
os.system()
en primer lugar. Utilice en susubprocess.call
lugar y proporcione los argumentos sin escape.fuente