Comment exécuter un programme à partir de Python? os.system échoue en raison d'espaces dans le chemin

273

J'ai un script Python qui doit exécuter un programme externe, mais pour une raison quelconque, il échoue.

Si j'ai le script suivant:

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

Ensuite, il échoue avec l'erreur suivante:

'C: \ Temp \ a' n'est pas reconnu comme une commande interne ou externe, un programme exploitable ou un fichier de commandes.

Si j'échappe au programme avec des guillemets:

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

Alors ça marche. Cependant, si j'ajoute un paramètre, il cesse de fonctionner à nouveau:

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

Quelle est la bonne façon d'exécuter un programme et d'attendre qu'il se termine? Je n'ai pas besoin de lire la sortie de celui-ci, car c'est un programme visuel qui fait un travail puis se termine, mais je dois attendre qu'il se termine.

Notez également que déplacer le programme vers un chemin non espacé n'est pas non plus une option.


Cela ne fonctionne pas non plus:

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

Notez les guillemets simples / doubles échangés.

Avec ou sans paramètre dans le Bloc-notes ici, il échoue avec le message d'erreur

Le nom de fichier, le nom de répertoire ou la syntaxe d'étiquette de volume est incorrect.

Lasse V. Karlsen
la source
Utilisez ceci: os.system(r'C:\temp\"a b c"\Notepad.exe') ou ceci:os.system('C:\\temp\\"a b c"\\Notepad.exe')
chanzerre
Pour les futurs visiteurs, si vous souhaitez exécuter une application avec des arguments (en utilisant un sous-processus). vous devez diviser vos arguments par espace et les passer individuellement. Par exemple, cela est d'un fichier de chauve - souris: "C:\Program Files\GDAL\gdal_translate.exe" -ot byte -of GTIFF -scale -co PHOTOMETRIC=CMYK "cmyk-16.tif" "cmyk-8_out.tif". En Python, il devient: ["C:\\Program Files\\GDAL\\gdal_translate.exe", "-ot", "byte", "-scale", "-co", "PHOTOMETRIC=CMYK", "input_cmyk-16.tif", "output_cmyk-8.tif"].
akinuri

Réponses:

297

subprocess.callévitera les problèmes liés au traitement des conventions de citation de différents shells. Il accepte une liste, plutôt qu'une chaîne, afin que les arguments soient plus facilement délimités. c'est à dire

import subprocess
subprocess.call(['C:\\Temp\\a b c\\Notepad.exe', 'C:\\test.txt'])
Brian
la source
81
Il est beaucoup plus simple d'utiliser une chaîne brute dans Windows: r "C: \ Temp \ abc \ Notepad.exe"
PierreBdR
1
Oui, les fonctions os.exec * remplaceront le processus actuel, donc votre processus python ne continuera pas. Ils sont plus utilisés sur unix où la méthode générale pour un shell pour lancer une commande est de fork () puis exec () dans l'enfant.
Brian
1
La méthode windows pour cela est la famille os.spawn, qui pourrait être utilisée à la place. le sous-processus est cependant plus portable et offre plus de flexibilité dans le contrôle du processus (capture des entrées / sorties, etc.), c'est donc préférable.
Brian
6
@PierreBdr: Il y a un cas où les chaînes brutes ne fonctionneront pas: où vous avez besoin d'une barre oblique de fin. par exemple r'c: \ foo \ bar \ '. En fait, il vaut probablement mieux utiliser des barres obliques à la place. Celles-ci sont acceptées dans toute l'API Windows (mais pas toujours par certaines commandes shell (par exemple, copie))
Brian
1
Pour python> = 3.5 subprocess.calldevrait être remplacé par subprocess.run docs.python.org/3/library/subprocess.html#older-high-level-api
gbonetti
67

Voici une façon différente de procéder.

Si vous utilisez Windows, les actions suivantes consistent à double-cliquer sur le fichier dans l'Explorateur ou à donner le nom du fichier comme argument à la commande DOS "start": le fichier est ouvert avec n'importe quelle application (le cas échéant) à laquelle son extension est associée .

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

Exemple:

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

Cela ouvrira textfile.txt avec le bloc-notes si le bloc-notes est associé à des fichiers .txt.

user16738
la source
1
Existe-t-il une fonction équivalente pour les systèmes * nix?
Romeno
@Romeno: vous pouvez essayer: webbrowser.open("textfile.txt")il devrait ouvrir un éditeur de texte. Voir aussi "démarrer le deuxième programme entièrement seul, comme si je venais de" double-cliquer dessus "."
jfs
Sur ma configuration, textfile.txt doit être entre guillemets, par exemple:os.startfile('path\to\textfile.txt')
thdoan
34

Les guillemets les plus externes sont consommés par Python lui-même, et le shell Windows ne le voit pas. Comme mentionné ci-dessus, Windows ne comprend que les guillemets doubles. Python convertira les barres obliques inversées en barres obliques inverses sous Windows, vous pouvez donc utiliser

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

Le 'est consommé par Python, qui passe ensuite "C: //Temp/abc/Notepad.exe" (en tant que chemin Windows, aucune double barre oblique inverse nécessaire) à CMD.EXE

Daniel Serodio
la source
1
Cela semble le meilleur dans un scénario comme celui os.system('curl URL > file')où je veux voir l'actualisation du compteur de progression de cURL pour les très gros fichiers.
Zach Young
Si la première lettre après une barre oblique inversée a une signification spéciale (c. \t-à- d . \n, Etc.), cette barre oblique inversée particulière doit être doublée. Être un chemin Windows n'a rien à voir avec cela.
Ethan Furman
1
Notez que si vous utilisez os.system()Windows, la fenêtre cmd s'ouvrira et restera ouverte jusqu'à ce que vous fermiez le processus qu'il a démarré. À mon humble avis, il vaut mieux utiliser os.startfile().
thdoan
1
N'oubliez pasimport os
Besi
ne fonctionne pas pour moi stackoverflow.com/questions/56241616/…
Gulzar
19

Au moins dans Windows 7 et Python 3.1, os.systemdans Windows, la ligne de commande doit être placée entre guillemets s'il y a des espaces dans le chemin d'accès à la commande. Par exemple:

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

Un exemple concret qui m'arrêtait était le clonage d'un lecteur dans VirtualBox. La subprocess.callsolution ci-dessus n'a pas fonctionné en raison d'un problème de droits d'accès, mais lorsque j'ai double-cité la commande, je suis os.systemdevenu heureux:

  TheCommand = '\"\"C:\\Program Files\\Sun\\VirtualBox\\VBoxManage.exe\" ' \
                 + ' clonehd \"' + OrigFile + '\" \"' + NewFile + '\"\"'
  os.system(TheCommand)
Paul Hoffman
la source
C'était ça! J'irais pour subprocess, mais parfois os.systemet os.popen(...).read()sont juste plus rapides à taper. BTW, vous n'avez pas besoin d'échapper aux guillemets doubles à l'intérieur de single, c'est à dire '""C:\\Temp\\a b c\\Notepad.exe""'fera l'affaire.
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
la source
et il semble qu'aucune citation ne soit nécessaire avec cette méthode, par exemple win32api.WinExec ('pythonw.exe d: \ web2py \ web2py.py -K welcome') démarre le planificateur web2py en arrière-plan.
Tim Richardson
@rahul et est-ce à l'exception des arguments pour l'exécutable? Donc, si vous voulez que le Bloc-notes ouvre un fichier ou est-ce séparé?
sayth
3

Je suppose que c'est le même problème que lorsque vous utilisez des raccourcis dans Windows ... Essayez ceci:

import os;
os.system("\"C:\\Temp\\a b c\\Notepad.exe\" C:\\test.txt");
Matthew Scharley
la source
désolé, cela ne fonctionne pas non plus, question modifiée pour refléter cela.
Lasse V. Karlsen
Je pense que Windows n'utilise que ", plutôt que" pour les citations. Cela fonctionnera probablement si vous changez cela. Cependant, vous rencontrerez toujours des problèmes si vous avez des citations intégrées, etc.
Brian
Je pensais qu'il fallait les deux, mais vous avez probablement raison. Je sais que cela fonctionne (au moins dans le shell) avec des guillemets doubles.
Matthew Scharley
+1 c'est le meilleur, Windows XP, l'édition familiale 2007 a bien fonctionné
0

Supposons que nous voulions exécuter votre serveur Web Django (sous Linux) qu'il y ait de l'espace entre votre chemin (chemin = '/home/<you>/<first-path-section> <second-path-section>'), procédez comme suit:

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_)

[ Remarque ]:

  • N'oubliez pas d'accéder à l'autorisation: chmod 755 -R <'yor path'>
  • manage.py est exceutable: chmod +x manage.py
Benyamin Jafari
la source
0

Pour Python 3.7, utilisez subprocess.call . Utilisez une chaîne brute pour simplifier les chemins Windows:

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

Pas besoin de sous-processus, il peut être simplement réalisé par

GitPath = "C: \ Program Files \ Git \ git-bash.exe" # Chemin du fichier d'application dans mycase son GITBASH os.startfile (GitPath)

rajat prakash
la source