Problema al usar os.system () con el comando sed

Estoy escribiendo un pequeño método para reemplazar un poco de texto en un archivo. El único argumento que necesito es el nuevo texto, ya que siempre es el mismo archivo y texto que se reemplazará.

Tengo un problema al usar la llamada os.system () cuando bash usar el argumento del método

Si uso una cadena como la de abajo, todo funciona bien:

stringId = "GRRRRRRRRR" cmd="sed '1,$s/MANAGER_ID=[0-9]*/MANAGER_ID=" + stringId + "/g' path/file.old > path/file.new" os.system(cmd) 

Ahora, si bash dar una cadena como un parámetro como abajo, el comando no se ejecuta. Hago una impresión para ver si el comando es correcto, y lo es. Incluso puedo ejecutarlo con éxito si copio / pego en mi shell

 import os def updateExportConfigId(id): stringId = "%s" % id cmd= "sed '1,$s/MANAGER_ID=[0-9]*/MANAGER_ID=" + stringId + "/g' path/file.old > path/file.new" print "command is " + cmd os.system(cmd) 

¿Alguien sabe lo que está mal?

Gracias

Obligatorio: no use os.system – use el módulo de subprocess :

 import subprocess def updateExportConfigId(m_id, source='path/file.old', destination='path/file.new'): if isinstance(m_id, unicode): m_id = m_id.encode('utf-8') cmd= [ "sed", ",$s/MANAGER_ID=[0-9]*/MANAGER_ID=%s/g" % m_id, source, ] subprocess.call(cmd, stdout=open(destination, 'w')) 

con este código puede pasar la ID del administrador, puede tener espacios, comillas, etc. Los nombres de los archivos también se pueden pasar a la función, y también pueden contener espacios y algunos otros caracteres especiales. Esto se debe a que su shell no se invoca innecesariamente, por lo que se inicia un proceso menos en su sistema operativo y no tiene que preocuparse por escapar de caracteres de shell especiales.

Otra opción: No lances sed. Utilice el módulo de re de python.

 import re def updateExportConfigID(m_id, source, destination): if isinstance(m_id, unicode): m_id = m_id.encode('utf-8') for line in source: new_line = re.sub(r'MANAGER_ID=\d*', r'MANAGER_ID=' + re.escape(m_id), line) destination.write(new_line) 

y llámalo así:

 updateExportConfigID('GRRRR', open('path/file.old'), open('path/file.new', 'w')) 

No se necesitan nuevos procesos.

Para ayudarte a depurarlo, intenta agregar:

 print repr(cmd) 

Es posible que algunos caracteres especiales se hayan deslizado en el comando que oculta la impresión normal cuando lo copia y lo pega.

Lo que está mal es que hay alguna diferencia. Sí, ya sé que no es útil, pero necesitas descubrir la diferencia.

Intenta ejecutar esto:

 import os def updateExportConfigId(id): stringId = "%s" % id cmd1 = "sed '1,$s/MANAGER_ID=[0-9]*/MANAGER_ID=" + stringId + "/g' path/file.old > path/file.new" stringId = "GRRRRRRRRR" cmd2 = "sed '1,$s/MANAGER_ID=[0-9]*/MANAGER_ID=" + stringId + "/g' path/file.old > path/file.new" print "cmd1:" , cmd1 print "cmd2:" , cmd2 print cmd1 == cmd2 updateExportConfigId("GRRRRRRRRR") 

El código debe imprimir:

 sed '1,$s/MANAGER_ID=[0-9]*/MANAGER_ID=GRRRRRRRRR/g' path/file.old > path/file.new sed '1,$s/MANAGER_ID=[0-9]*/MANAGER_ID=GRRRRRRRRR/g' path/file.old > path/file.new True 

De este modo se demuestra que son exactamente iguales. Si la última línea es “Falso”, entonces no son lo mismo, y usted debería poder ver la diferencia.

Entonces, de las respuestas anteriores, ahora sabemos que id es una cadena Unicode, que convierte a cmd1 en una cadena Unicode, que os.system () está convirtiendo en una cadena de bytes para su ejecución en la encoding predeterminada.

a) Sugiero usar subproceso en lugar de os.system ()

b) Sugiero no usar el nombre de una función incorporada como una variable ( id ).

c) Sugiero codificar explícitamente la cadena en una cadena de bytes antes de ejecutar:

 if isinstance(cmd,unicode): cmd = cmd.encode("UTF-8") 

d) Para la sugerencia de Lennart Regebro agregue:

 assert type(cmd1) == type(cmd2) 

después

 print cmd1 == cmd2 

Tal vez algún problema de sangría?

Los siguientes trabajos funcionan correctamente:

 import os def updateExportConfigId(id): stringId = "%s" % id cmd= "sed '1,$s/MANAGER_ID=[0-9]*/MANAGER_ID=" + stringId + "/g' test.dat > test.new" print "command is " + cmd os.system(cmd) updateExportConfigId("adsf") 

Tampoco utilice palabras reservadas ( id ) como variables.

Tal vez sea útil usar solo cuerdas en bruto .

¡Finalmente, encontré una manera de ejecutar el sistema operativo OS (cmd)!

Truco simple, para “limpiar” la cadena cmd:

 os.system(str(cmd)) 

Ahora, puedo construir el cmd con todos los argumentos que necesito y al final simplemente lo “limpio” con la llamada a str () antes de ejecutarlo con la llamada os.system ().

¡Muchas gracias por sus respuestas!

swon