Pregunta

Cuando se utiliza os.system(), a menudo es necesario escapar de los nombres de archivos y otros argumentos pasados ​​como parámetros de 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: Acepté la respuesta simple de usar comillas, no sé por qué no pensé en eso;Supongo que porque vengo 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 proporciona os.system(), y la fuente de las cadenas no es generada por el usuario o al menos ingresada por un usuario de confianza (yo).

¿Fue útil?

Solución

Esto es lo que uso:

def shellquote(s):
    return "'" + s.replace("'", "'\\''") + "'"

El shell siempre aceptará un nombre de archivo entre comillas y eliminará las comillas que lo rodean antes de pasarlo al programa en cuestión.En particular, esto evita problemas con nombres de archivos que contienen espacios o cualquier otro tipo de metacarácter de shell desagradable.

Actualizar:Si está utilizando Python 3.3 o posterior, utilice shlex.cita en lugar de rodar el tuyo propio.

Otros consejos

shlex.quote() hace lo que quieres desde Python 3.

(Usar pipes.quote para soportar tanto Python 2 como Python 3)

Quizás tenga una razón específica para usar os.system().Pero si no, probablemente deberías usar el subprocess módulo.Puede especificar las tuberías directamente y evitar el uso del shell.

Lo siguiente es de pep324:

Replacing shell pipe line
-------------------------

output=`dmesg | grep hda`
==>
p1 = Popen(["dmesg"], stdout=PIPE)
p2 = Popen(["grep", "hda"], stdin=p1.stdout, stdout=PIPE)
output = p2.communicate()[0]

Tal vez subprocess.list2cmdline ¿Es un mejor tiro?

Tenga en cuenta que pipes.quote en realidad no funciona en Python 2.5 y Python 3.1 y no es seguro de usar: no maneja argumentos de longitud cero.

>>> from pipes import quote
>>> args = ['arg1', '', 'arg3']
>>> print 'mycommand %s' % (' '.join(quote(arg) for arg in args))
mycommand arg1  arg3

Ver Problema de Python 7476;se ha solucionado en Python 2.6 y 3.2 y posteriores.

Creo que os.system simplemente invoca cualquier comando shell configurado para el usuario, por lo que no creo que puedas 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ás pasando e incluso si lo hicieran, no hay garantía de que escapen de la misma manera.

Aviso:Esta es una respuesta para Python 2.7.x.

De acuerdo con la fuente, pipes.quote() es una manera de "Cita de forma fiable una cadena como argumento único para /bin/sh".(Aunque es en desuso desde la versión 2.7 y finalmente expuesto públicamente en Python 3.3 como el shlex.quote() función.)

En por otro lado, subprocess.list2cmdline() es una manera de "Traducir una secuencia de argumentos a una cadena de línea de comando, usando 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.

import sys
mswindows = (sys.platform == "win32")

if mswindows:
    from subprocess import list2cmdline
    quote_args = list2cmdline
else:
    # POSIX
    from pipes import quote

    def quote_args(seq):
        return ' '.join(quote(arg) for arg in seq)

Uso:

# Quote a single argument
print quote_args(['my argument'])

# Quote multiple arguments
my_args = ['This', 'is', 'my arguments']
print quote_args(my_args)

La función que uso es:

def quote_argument(argument):
    return '"%s"' % (
        argument
        .replace('\\', '\\\\')
        .replace('"', '\\"')
        .replace('$', '\\$')
        .replace('`', '\\`')
    )

eso es:Siempre incluyo el argumento entre comillas dobles y luego cito con barra invertida los únicos caracteres especiales entre comillas dobles.

Si usa el comando del sistema, intentaría incluir en la lista blanca lo que se incluye en la llamada os.system().Por ejemplo..

clean_user_input re.sub("[^a-zA-Z]", "", user_input)
os.system("ls %s" % (clean_user_input))

El módulo de subproceso es una mejor opción y recomendaría intentar evitar el uso de algo como os.system/subprocess siempre que sea posible.

La verdadera respuesta es:no usar os.system() en primer lugar.Usar subprocess.call en su lugar y proporcione los argumentos no escapados.

Licenciado bajo: CC-BY-SA con atribución
No afiliado a StackOverflow
scroll top