ฉันจะรันโปรแกรมจาก Python ได้อย่างไร os.system ล้มเหลวเนื่องจากช่องว่างในเส้นทาง


273

ฉันมีสคริปต์ Python ที่ต้องใช้งานโปรแกรมภายนอก แต่ด้วยเหตุผลบางอย่างล้มเหลว

หากฉันมีสคริปต์ต่อไปนี้:

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

จากนั้นจะล้มเหลวด้วยข้อผิดพลาดต่อไปนี้:

'C: \ Temp \ a' ไม่รู้จักว่าเป็นคำสั่งภายในหรือภายนอกโปรแกรมที่ทำงานได้หรือไฟล์แบตช์

ถ้าฉันหนีโปรแกรมด้วยเครื่องหมายคำพูด:

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

จากนั้นก็ใช้งานได้ อย่างไรก็ตามหากฉันเพิ่มพารามิเตอร์มันจะหยุดทำงานอีกครั้ง:

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

วิธีที่ถูกต้องในการรันโปรแกรมและรอให้โปรแกรมทำงานเสร็จสมบูรณ์คืออะไร? ฉันไม่จำเป็นต้องอ่านผลลัพธ์จากมันเพราะมันเป็นโปรแกรมภาพที่ทำงานแล้วก็ออกไป แต่ฉันต้องรอให้เสร็จ

โปรดทราบว่าการย้ายโปรแกรมไปยังเส้นทางที่ไม่มีระยะห่างไม่ใช่ตัวเลือกเช่นกัน


สิ่งนี้ไม่ทำงาน:

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

หมายเหตุการสลับคำพูดเดี่ยว / คู่

มีหรือไม่มีพารามิเตอร์เพื่อ Notepad ที่นี่มันล้มเหลวพร้อมกับข้อความแสดงข้อผิดพลาด

ชื่อไฟล์ชื่อไดเรกทอรีหรือไวยากรณ์ฉลากปริมาณไม่ถูกต้อง


ใช้สิ่งนี้: os.system(r'C:\temp\"a b c"\Notepad.exe') หรือสิ่งนี้:os.system('C:\\temp\\"a b c"\\Notepad.exe')
chanzerre

สำหรับผู้เยี่ยมชมในอนาคตหากคุณต้องการเรียกใช้แอปที่มีอาร์กิวเมนต์ (ใช้กระบวนการย่อย) คุณต้องแยกข้อโต้แย้งตามช่องว่างและส่งให้ทีละข้อ ตัวอย่างเช่นนี่มาจากไฟล์ bat:"C:\Program Files\GDAL\gdal_translate.exe" -ot byte -of GTIFF -scale -co PHOTOMETRIC=CMYK "cmyk-16.tif" "cmyk-8_out.tif"ตัวอย่างเช่นนี้มาจากไฟล์ค้างคาว:ใน Python มันจะกลายเป็น: ["C:\\Program Files\\GDAL\\gdal_translate.exe", "-ot", "byte", "-scale", "-co", "PHOTOMETRIC=CMYK", "input_cmyk-16.tif", "output_cmyk-8.tif"].
akinuri

คำตอบ:


297

subprocess.callจะหลีกเลี่ยงปัญหาเกี่ยวกับการจัดการกับข้อความของเปลือกหอยต่าง ๆ มันยอมรับรายการแทนที่จะเป็นสตริงดังนั้นข้อโต้แย้งจึงถูกคั่นได้ง่ายกว่า กล่าวคือ

import subprocess
subprocess.call(['C:\\Temp\\a b c\\Notepad.exe', 'C:\\test.txt'])

81
มันง่ายกว่ามากในการใช้สตริงดิบใน windows: r "C: \ Temp \ abc \ Notepad.exe"
PierreBdR

1
ใช่ฟังก์ชั่น os.exec * จะเข้ามาแทนที่กระบวนการปัจจุบันดังนั้นกระบวนการไพ ธ อนของคุณจะไม่ดำเนินการต่อ พวกมันถูกใช้มากขึ้นในระบบยูนิกซ์โดยที่วิธีการทั่วไปสำหรับเชลล์เพื่อเรียกใช้คำสั่งคือ fork () และ exec () ใน child
Brian

1
วิธี windows สำหรับสิ่งนี้คือตระกูล os.spawn ซึ่งสามารถใช้แทนได้ กระบวนการย่อยนั้นสามารถพกพาได้มากกว่าและมีความยืดหยุ่นในการควบคุมกระบวนการ (การจับภาพอินพุต / เอาต์พุต ฯลฯ ) ดังนั้นจึงเป็นที่ต้องการ
Brian

6
@PierreBdr: มีกรณีที่ rawstrings จะไม่ทำงาน: ที่ที่คุณต้องการสแลชต่อท้าย เช่น r'c: \ foo \ bar \ ' ที่จริงแล้วมันอาจดีกว่าที่จะใช้เครื่องหมายทับซ้ายแทน เหล่านี้ได้รับการยอมรับทั่วหน้าต่าง API (แม้ว่าจะไม่ได้เสมอโดยคำสั่งเชลล์ (เช่นสำเนา))
ไบรอัน

1
สำหรับ python> = 3.5 subprocess.callควรแทนที่ด้วยsubprocess.run docs.python.org/3/library/subprocess.html#older-high-level-api
gbonetti

67

นี่คือวิธีที่แตกต่างในการทำมัน

หากคุณใช้ Windows การกระทำดังต่อไปนี้เช่นการคลิกสองครั้งที่ไฟล์ใน Explorer หรือให้ชื่อไฟล์เป็นอาร์กิวเมนต์สำหรับคำสั่ง DOS "เริ่มต้น" ไฟล์จะถูกเปิดด้วยแอปพลิเคชันใด ๆ (ถ้ามี) ส่วนขยายที่เกี่ยวข้อง .

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

ตัวอย่าง:

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

สิ่งนี้จะเปิด textfile.txt ด้วย Notepad หาก Notepad เชื่อมโยงกับไฟล์. txt


1
มีฟังก์ชั่นที่เทียบเท่ากับระบบ * nix หรือไม่?
Romeno

@Romeno: คุณสามารถลอง: webbrowser.open("textfile.txt")มันควรจะเปิดโปรแกรมแก้ไขข้อความ ดูเพิ่มเติม"เริ่มต้นโปรแกรมที่สองด้วยตัวเองราวกับว่าฉันเพิ่ง 'ดับเบิลคลิกที่มัน'."
jfs

ในการตั้งค่าของฉัน textfile.txt ต้องอยู่ในเครื่องหมายคำพูดเช่น:os.startfile('path\to\textfile.txt')
thdoan

34

Python ใช้เครื่องหมายอัญประกาศนอกสุดและ Windows เชลล์จะไม่เห็นราคา ตามที่กล่าวไว้ข้างต้น Windows จะเข้าใจเฉพาะเครื่องหมายคำพูดคู่ Python จะแปลงฟอร์เวิร์ดสแลชเป็นแบ็กสแลชบน Windows ดังนั้นคุณสามารถใช้ได้

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

Python ใช้งาน 'ซึ่งผ่าน "C: //Temp/abc/Notepad.exe" (เป็นพา ธ ของ Windows ไม่ต้องใช้แบ็กสแลชสองครั้ง) ไปยัง CMD.EXE


1
นี่ดูเหมือนดีที่สุดในสถานการณ์เช่นos.system('curl URL > file')ที่ฉันต้องการเห็นตัววัดความคืบหน้าของ cURL สำหรับไฟล์ขนาดใหญ่จริงๆ
Zach Young

ถ้าตัวอักษรตัวแรกหลังจากเครื่องหมายมีความหมายพิเศษ (เช่น\t, \nฯลฯ ) แล้วที่ทับขวาโดยเฉพาะอย่างยิ่งจะต้องเป็นสองเท่า การเป็นพา ธ ของ Windows ไม่มีส่วนเกี่ยวข้องกับมัน
Ethan Furman

1
โปรดทราบว่าหากคุณใช้os.system()บน Windows หน้าต่าง cmd จะเปิดและยังคงเปิดอยู่จนกว่าคุณจะปิดกระบวนการที่เริ่มต้น IMHO os.startfile()ดีกว่าที่จะใช้
thdoan

1
อย่าลืมimport os
Besi


19

อย่างน้อยใน Windows 7 และ Python 3.1 os.systemใน Windows ต้องการให้บรรทัดคำสั่งอ้างสองครั้งหากมีช่องว่างในพา ธ ไปยังคำสั่ง ตัวอย่างเช่น:

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

ตัวอย่างในโลกแห่งความจริงที่ทำให้ฉันนิ่งงันได้คือการโคลนไดรฟ์ใน VirtualBox subprocess.callวิธีการแก้ปัญหาข้างต้นใช้งานไม่ได้เนื่องจากปัญหาสิทธิการเข้าถึงบางอย่าง แต่เมื่อฉันอ้างคำสั่งสองครั้งos.systemก็มีความสุข:

  TheCommand = '\"\"C:\\Program Files\\Sun\\VirtualBox\\VBoxManage.exe\" ' \
                 + ' clonehd \"' + OrigFile + '\" \"' + NewFile + '\"\"'
  os.system(TheCommand)

นั่นมัน! ฉันจะไปsubprocessแต่บางครั้งos.systemและos.popen(...).read()ก็เร็วกว่าที่จะพิมพ์ BTW คุณไม่จำเป็นต้องหลีกเลี่ยงการใส่เครื่องหมายคำพูดคู่ใน single เช่น'""C:\\Temp\\a b c\\Notepad.exe""'จะทำ
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

และดูเหมือนว่าไม่จำเป็นต้องมีการอ้างถึงด้วยวิธีนี้เช่น win32api.WinExec ('pythonw.exe d: \ web2py \ web2py.py -K welcome') เริ่มตัวจัดตารางเวลา web2py ในพื้นหลัง
Tim Richardson

@ ราอูลและมันจะยกเว้นข้อโต้แย้งสำหรับปฏิบัติการ? ดังนั้นหากคุณต้องการให้ Notepad เปิดไฟล์หรือแยกกัน?
sayth


3

ฉันสงสัยว่ามันเป็นปัญหาเดียวกับเมื่อคุณใช้ทางลัดใน Windows ... ลองสิ่งนี้:

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

ขออภัยที่ใช้งานไม่ได้ตอบคำถามเพื่อแก้ไขสิ่งนี้
Lasse V. Karlsen

ผมคิดว่าหน้าต่างเพียงใช้" มากกว่า 'สำหรับข้อความนี้อาจจะทำงานถ้าคุณเปลี่ยนนี้ แต่คุณจะใช้ยังคงเป็นปัญหาที่มีราคาถ้าคุณมีการฝังตัว ฯลฯ ..
ไบรอัน

ฉันคิดว่ามันใช้ทั้งคู่ แต่คุณอาจจะถูก ฉันรู้ว่ามันใช้งานได้ (ในเปลือก atleast) ด้วยเครื่องหมายคำพูดคู่
Matthew Scharley

+1 นี่คือสิ่งที่ดีที่สุด windows XP รุ่นบ้าน 2007 ทำงานได้ดี

0

สมมติว่าเราต้องการเรียกใช้เว็บเซิร์ฟเวอร์ Django ของคุณ (ใน Linux) ว่ามีช่องว่างระหว่างเส้นทางของคุณ (path = '/home/<you>/<first-path-section> <second-path-section>') ดังนั้นให้ทำดังนี้:

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

[ หมายเหตุ ]:

  • อย่าลืมเข้าถึงการอนุญาต: chmod 755 -R <'yor path'>
  • manage.py เป็นที่ยอมรับได้: chmod +x manage.py

0

สำหรับงูหลาม 3.7 ใช้subprocess.call ใช้สตริงดิบเพื่อทำให้เส้นทาง Windows ง่ายขึ้น:

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

0

ไม่ต้องใช้กระบวนการย่อยสามารถทำได้โดยง่าย

GitPath = "ไฟล์ C: \ Program \ Git \ git-bash.exe" # พา ธ ของไฟล์แอปพลิเคชันใน mycase ของ GITBASH os.startfile (GitPath)

โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.