¿Cómo ejecuto un programa desde Python? El sistema os falla debido a espacios en la ruta

273

Tengo un script de Python que necesita ejecutar un programa externo, pero por alguna razón falla.

Si tengo el siguiente script:

import os;
os.system("C:\\Temp\\a b c\\Notepad.exe");
raw_input();

Entonces falla con el siguiente error:

'C: \ Temp \ a' no se reconoce como un comando interno o externo, programa operativo o archivo por lotes.

Si escapo del programa con comillas:

import os;
os.system('"C:\\Temp\\a b c\\Notepad.exe"');
raw_input();

Entonces funciona. Sin embargo, si agrego un parámetro, deja de funcionar nuevamente:

import os;
os.system('"C:\\Temp\\a b c\\Notepad.exe" "C:\\test.txt"');
raw_input();

¿Cuál es la forma correcta de ejecutar un programa y esperar a que se complete? No necesito leer el resultado, ya que es un programa visual que hace un trabajo y luego simplemente sale, pero necesito esperar a que se complete.

También tenga en cuenta, mover el programa a una ruta no espaciada tampoco es una opción.


Esto tampoco funciona:

import os;
os.system("'C:\\Temp\\a b c\\Notepad.exe'");
raw_input();

Tenga en cuenta las comillas simples / dobles intercambiadas.

Con o sin un parámetro para el Bloc de notas aquí, falla con el mensaje de error

El nombre de archivo, el nombre del directorio o la sintaxis de la etiqueta de volumen es incorrecta.

Lasse V. Karlsen
fuente
Use esto: os.system(r'C:\temp\"a b c"\Notepad.exe') o esto:os.system('C:\\temp\\"a b c"\\Notepad.exe')
chanzerre
Para futuros visitantes, si desea ejecutar una aplicación con argumentos (usando un subproceso). necesita dividir sus argumentos por espacio y pasar cada uno individualmente. Por ejemplo, esto es desde un archivo bat: "C:\Program Files\GDAL\gdal_translate.exe" -ot byte -of GTIFF -scale -co PHOTOMETRIC=CMYK "cmyk-16.tif" "cmyk-8_out.tif". En Python, se convierte en: ["C:\\Program Files\\GDAL\\gdal_translate.exe", "-ot", "byte", "-scale", "-co", "PHOTOMETRIC=CMYK", "input_cmyk-16.tif", "output_cmyk-8.tif"].
akinuri

Respuestas:

297

subprocess.callevitará problemas al tener que lidiar con convenciones de cotización de varios shells. Acepta una lista, en lugar de una cadena, por lo que los argumentos se delimitan más fácilmente. es decir

import subprocess
subprocess.call(['C:\\Temp\\a b c\\Notepad.exe', 'C:\\test.txt'])
Brian
fuente
81
Es mucho más simple usar cadenas sin procesar en Windows: r "C: \ Temp \ abc \ Notepad.exe"
PierreBdR
1
Sí, las funciones os.exec * reemplazarán el proceso actual, por lo que su proceso de Python no continuará. Se usan más en Unix, donde el método general para que un shell inicie un comando es fork () y luego exec () en el elemento secundario.
Brian
1
El método de Windows para esto es la familia os.spawn, que podría usarse en su lugar. Sin embargo, el subproceso es más portátil y ofrece más flexibilidad para controlar el proceso (captura de entrada / salida, etc.), por lo que se prefiere.
Brian
66
@PierreBdr: Hay un caso en el que las cuerdas no funcionan: donde necesitas una barra inclinada final. por ejemplo, r'c: \ foo \ bar \ '. En realidad, probablemente sea mejor usar barras diagonales en su lugar. Estos son aceptados en toda la API de Windows (aunque no siempre por algunos comandos de shell (por ejemplo, copiar))
Brian
1
Para python> = 3.5 subprocess.calldebe reemplazarse por subprocess.run docs.python.org/3/library/subprocess.html#older-high-level-api
gbonetti
67

Aquí hay una forma diferente de hacerlo.

Si está utilizando Windows, lo siguiente actúa como hacer doble clic en el archivo en el Explorador, o dar el nombre del archivo como argumento para el comando "iniciar" de DOS: el archivo se abre con cualquier aplicación (si la hay) a la que está asociada su extensión .

filepath = 'textfile.txt'
import os
os.startfile(filepath)

Ejemplo:

import os
os.startfile('textfile.txt')

Esto abrirá textfile.txt con el Bloc de notas si el Bloc de notas está asociado con archivos .txt.

usuario16738
fuente
1
¿Existe una función equivalente para los sistemas * nix?
Romeno
@Romeno: puedes probar: webbrowser.open("textfile.txt")debería abrir un editor de texto. Consulte también "iniciar el segundo programa completamente solo, como si acabara de hacer doble clic en él".
jfs
En mi configuración, textfile.txt debe estar entre comillas, por ejemplo:os.startfile('path\to\textfile.txt')
thdoan
34

Python consume las citas más externas y el shell de Windows no lo ve. Como se mencionó anteriormente, Windows solo entiende comillas dobles. Python convertirá barras diagonales en barras diagonales en Windows, por lo que puede usar

os.system('"C://Temp/a b c/Notepad.exe"')

Python consume el ', que luego pasa "C: //Temp/abc/Notepad.exe" (como una ruta de Windows, no se necesitan barras invertidas dobles) a CMD.EXE

Daniel Serodio
fuente
1
Este parece el mejor en un escenario como os.system('curl URL > file')donde quiero ver la actualización del medidor de progreso de cURL para archivos realmente grandes.
Zach Young
Si la primera letra después de una barra invertida tiene un significado especial (es decir \t, \n, etc), entonces esa particular barra invertida debe ser duplicado. Ser una ruta de Windows no tiene nada que ver con eso.
Ethan Furman
1
Tenga en cuenta que si usa os.system()Windows, la ventana cmd se abrirá y permanecerá abierta hasta que cierre el proceso que comenzó. En mi humilde opinión es mejor usar os.startfile().
thdoan
1
No lo olvidesimport os
Besi
no funciona para mí stackoverflow.com/questions/56241616/…
Gulzar
19

Al menos en Windows 7 y Python 3.1, os.systemen Windows quiere que la línea de comando se doble entre comillas si hay espacios en la ruta del comando. Por ejemplo:

  TheCommand = '\"\"C:\\Temp\\a b c\\Notepad.exe\"\"'
  os.system(TheCommand)

Un ejemplo del mundo real que me estaba confundiendo era clonar una unidad en VirtualBox. La subprocess.callsolución anterior no funcionó debido a un problema de derechos de acceso, pero cuando hice una doble cita del comando, me os.systemalegré:

  TheCommand = '\"\"C:\\Program Files\\Sun\\VirtualBox\\VBoxManage.exe\" ' \
                 + ' clonehd \"' + OrigFile + '\" \"' + NewFile + '\"\"'
  os.system(TheCommand)
Paul Hoffman
fuente
¡Eso fue todo! Iría por subprocess, pero a veces os.systemy os.popen(...).read()son más rápidos de escribir. Por cierto, no necesita escapar de las comillas dobles dentro de simple, es decir, '""C:\\Temp\\a b c\\Notepad.exe""'lo hará.
Tomasz Gandor
9
import win32api # if active state python is installed or install pywin32 package seperately

try: win32api.WinExec('NOTEPAD.exe') # Works seamlessly
except: pass
rahul
fuente
y parece que no se necesitan citas con este método, por ejemplo, win32api.WinExec ('pythonw.exe d: \ web2py \ web2py.py -K welcome') inicia el programador web2py en segundo plano.
Tim Richardson
@rahul y ¿excepto argumentos para el ejecutable? Entonces, si desea que el Bloc de notas abra un archivo o ¿está separado?
dice el
3

Sospecho que es el mismo problema que cuando usas accesos directos en Windows ... Prueba esto:

import os;
os.system("\"C:\\Temp\\a b c\\Notepad.exe\" C:\\test.txt");
Matthew Scharley
fuente
lo siento, eso tampoco funciona, pregunta editada para reflejar esto.
Lasse V. Karlsen
Creo que Windows solo usa ", en lugar de 'para citar. Esto probablemente funcionará si cambia esto. Sin embargo, todavía tendrá problemas si tiene comillas incrustadas, etc.
Brian
Pensé que hacía falta ambos, pero probablemente tengas razón. Sé que funciona (al menos en el shell) con comillas dobles.
Matthew Scharley
+1 este es el mejor, Windows XP, 2007 Home Edition funcionó bien
0

Supongamos que queremos ejecutar su servidor web Django (en Linux) que hay espacio entre su ruta (ruta = '/home/<you>/<first-path-section> <second-path-section>'), así que haga lo siguiente:

import subprocess

args = ['{}/manage.py'.format('/home/<you>/<first-path-section> <second-path-section>'), 'runserver']
res = subprocess.Popen(args, stdout=subprocess.PIPE)
output, error_ = res.communicate()

if not error_:
    print(output)
else:
    print(error_)

[ Nota ]:

  • No olvides acceder al permiso: chmod 755 -R <'yor path'>
  • manage.py es excelente: chmod +x manage.py
Benyamin Jafari
fuente
0

Para Python 3.7, use subprocess.call . Use una cadena sin formato para simplificar las rutas de Windows:

import subprocess
subprocess.call([r'C:\Temp\Example\Notepad.exe', 'C:\test.txt'])
WestAce
fuente
0

No hay necesidad de subproceso, simplemente se puede lograr mediante

GitPath = "C: \ Archivos de programa \ Git \ git-bash.exe" # Ruta del archivo de aplicación en mycase su archivo GITBASH os.startfile (GitPath)

rajat prakash
fuente