คำตอบสำหรับคำถามนี้ขึ้นอยู่กับเวอร์ชันของ Python ที่คุณใช้ วิธีที่ง่ายที่สุดคือการใช้subprocess.check_output
ฟังก์ชั่น:
>>> subprocess.check_output(['ls', '-l'])
b'total 0\n-rw-r--r-- 1 memyself staff 0 Mar 14 11:04 files\n'
check_output
รันโปรแกรมเดียวที่รับอาร์กิวเมนต์เป็นอินพุตเท่านั้น 1stdout
ก็จะส่งกลับผลตรงตามที่พิมพ์ไป หากคุณต้องการเขียนอินพุตให้stdin
ข้ามไปข้างหน้าrun
หรือPopen
ส่วนต่างๆ หากคุณต้องการรันคำสั่งเชลล์ที่ซับซ้อนดูบันทึกย่อshell=True
ที่ท้ายคำตอบนี้
check_output
ฟังก์ชั่นนี้ใช้งานได้กับ Python เกือบทุกรุ่นที่ยังใช้งานอยู่ (2.7+) 2แต่สำหรับเวอร์ชั่นล่าสุดมันไม่ได้เป็นแนวทางที่แนะนำอีกต่อไป
Python เวอร์ชันใหม่ (3.5 หรือสูงกว่า): run
หากคุณกำลังใช้งูหลาม 3.5หรือสูงกว่าและไม่จำเป็นต้องทำงานร่วมกันหลังที่ใหม่run
ฟังก์ชั่นขอแนะนำ มันให้ API ระดับสูงทั่วไปมากสำหรับsubprocess
โมดูล ในการดักจับเอาต์พุตของโปรแกรมให้ส่งsubprocess.PIPE
ค่าสถานะไปยังstdout
อาร์กิวเมนต์คีย์เวิร์ด จากนั้นเข้าถึงstdout
แอตทริบิวต์ของCompletedProcess
วัตถุที่ส่งคืน:
>>> import subprocess
>>> result = subprocess.run(['ls', '-l'], stdout=subprocess.PIPE)
>>> result.stdout
b'total 0\n-rw-r--r-- 1 memyself staff 0 Mar 14 11:04 files\n'
ค่าส่งคืนเป็นbytes
วัตถุดังนั้นหากคุณต้องการสตริงที่เหมาะสมคุณจะต้องใช้decode
มัน สมมติว่ากระบวนการที่เรียกคืนสตริงที่เข้ารหัส UTF-8:
>>> result.stdout.decode('utf-8')
'total 0\n-rw-r--r-- 1 memyself staff 0 Mar 14 11:04 files\n'
ทั้งหมดนี้สามารถบีบอัดให้เป็นหนึ่งซับ:
>>> subprocess.run(['ls', '-l'], stdout=subprocess.PIPE).stdout.decode('utf-8')
'total 0\n-rw-r--r-- 1 memyself staff 0 Mar 14 11:04 files\n'
หากคุณต้องการส่งผ่านข้อมูลไปยังกระบวนการstdin
ให้ส่งbytes
วัตถุไปยังinput
อาร์กิวเมนต์คำหลัก:
>>> cmd = ['awk', 'length($0) > 5']
>>> input = 'foo\nfoofoo\n'.encode('utf-8')
>>> result = subprocess.run(cmd, stdout=subprocess.PIPE, input=input)
>>> result.stdout.decode('utf-8')
'foofoo\n'
คุณสามารถดักจับข้อผิดพลาดโดยผ่านstderr=subprocess.PIPE
(capture to result.stderr
) หรือstderr=subprocess.STDOUT
(capture ไปยังresult.stdout
พร้อมกับเอาต์พุตปกติ) เมื่อความปลอดภัยไม่ได้เป็นกังวลคุณยังสามารถเรียกใช้คำสั่งเชลล์ที่ซับซ้อนมากขึ้นโดยส่งผ่านshell=True
ตามที่อธิบายไว้ในหมายเหตุด้านล่าง
สิ่งนี้เพิ่มความซับซ้อนเพียงเล็กน้อยเมื่อเทียบกับวิธีการทำสิ่งเก่า แต่ฉันคิดว่ามันคุ้มค่ากับการจ่ายเงิน: ตอนนี้คุณสามารถทำอะไรก็ได้ที่คุณต้องทำกับrun
ฟังก์ชั่นเพียงอย่างเดียว
Python เวอร์ชันเก่ากว่า (2.7-3.4): check_output
หากคุณใช้ Python เวอร์ชั่นเก่ากว่าหรือต้องการความเข้ากันได้แบบย้อนหลังคุณอาจใช้check_output
ฟังก์ชั่นตามที่อธิบายไว้ข้างต้นโดยย่อ สามารถใช้งานได้ตั้งแต่ Python 2.7
subprocess.check_output(*popenargs, **kwargs)
มันจะใช้เวลาขัดแย้งกันเป็นPopen
(ดูด้านล่าง) และส่งกลับสตริงที่มีผลลัพธ์ของโปรแกรม จุดเริ่มต้นของคำตอบนี้มีตัวอย่างการใช้ที่ละเอียดยิ่งขึ้น ใน Python 3.5 และสูงกว่าcheck_output
เทียบเท่ากับการดำเนินการrun
กับcheck=True
และstdout=PIPE
และส่งคืนเฉพาะแอstdout
ททริบิวต์
คุณสามารถส่งผ่านstderr=subprocess.STDOUT
เพื่อให้มั่นใจว่าข้อความผิดพลาดที่จะถูกรวมในการส่งออกกลับ - แต่ในบางรุ่นของงูใหญ่ผ่านstderr=subprocess.PIPE
ไปcheck_output
อาจทำให้เกิดการติดตาย เมื่อความปลอดภัยไม่ได้เป็นกังวลคุณยังสามารถเรียกใช้คำสั่งเชลล์ที่ซับซ้อนมากขึ้นโดยส่งผ่านshell=True
ตามที่อธิบายไว้ในหมายเหตุด้านล่าง
หากคุณต้องการไพพ์จากstderr
หรือส่งผ่านอินพุตไปยังกระบวนการcheck_output
จะไม่ขึ้นอยู่กับภารกิจ ดูPopen
ตัวอย่างด้านล่างในกรณีนั้น
แอปพลิเคชั่นที่ซับซ้อน & Python เวอร์ชั่นดั้งเดิม (2.6 และต่ำกว่า): Popen
หากคุณต้องการความเข้ากันได้อย่างลึกล้ำหรือหากคุณต้องการฟังก์ชั่นที่ซับซ้อนมากกว่าที่check_output
มีให้คุณจะต้องทำงานกับPopen
วัตถุโดยตรงซึ่งจะห่อหุ้ม API ระดับต่ำสำหรับกระบวนการย่อย
คอนPopen
สตรัคยอมรับทั้งคำสั่งเดียวโดยไม่มีข้อโต้แย้งหรือรายการที่มีคำสั่งเป็นรายการแรกตามด้วยจำนวนอาร์กิวเมนต์ใด ๆ แต่ละรายการเป็นรายการแยกต่างหากในรายการ shlex.split
สามารถช่วยวิเคราะห์สตริงในรายการที่จัดรูปแบบอย่างเหมาะสม Popen
ออบเจ็กต์ยังยอมรับโฮสต์ของอาร์กิวเมนต์ที่แตกต่างกันสำหรับการจัดการกระบวนการ IO และการกำหนดค่าระดับต่ำ
ในการส่งอินพุตและเอาต์พุตจับภาพcommunicate
เป็นวิธีที่ต้องการเกือบทุกครั้ง ในขณะที่:
output = subprocess.Popen(["mycmd", "myarg"],
stdout=subprocess.PIPE).communicate()[0]
หรือ
>>> import subprocess
>>> p = subprocess.Popen(['ls', '-a'], stdout=subprocess.PIPE,
... stderr=subprocess.PIPE)
>>> out, err = p.communicate()
>>> print out
.
..
foo
ถ้าคุณตั้งค่าstdin=PIPE
, communicate
นอกจากนี้ยังช่วยให้คุณสามารถส่งผ่านข้อมูลในการประมวลผลผ่านstdin
:
>>> cmd = ['awk', 'length($0) > 5']
>>> p = subprocess.Popen(cmd, stdout=subprocess.PIPE,
... stderr=subprocess.PIPE,
... stdin=subprocess.PIPE)
>>> out, err = p.communicate('foo\nfoofoo\n')
>>> print out
foofoo
หมายเหตุคำตอบแอรอนฮอลล์ซึ่งแสดงให้เห็นว่าในบางระบบคุณอาจจำเป็นต้องชุดstdout
, stderr
และstdin
ทุกคนที่จะPIPE
(หรือDEVNULL
) ที่จะได้รับcommunicate
ในการทำงานที่ทุกคน
ในบางกรณีที่หายากคุณอาจต้องใช้การจับภาพเอาต์พุตแบบเรียลไทม์ที่ซับซ้อน คำตอบของVartecแนะนำวิธีไปข้างหน้า แต่วิธีการอื่นนอกจากcommunicate
มีแนวโน้มที่จะหยุดชะงักหากไม่ได้ใช้อย่างระมัดระวัง
shell=True
เช่นเดียวกับทุกฟังก์ชั่นดังกล่าวข้างต้นเมื่อการรักษาความปลอดภัยไม่กังวลคุณสามารถเรียกใช้คำสั่งเชลล์ที่ซับซ้อนมากขึ้นโดยผ่าน
หมายเหตุ
1. การรันคำสั่งเชลล์: shell=True
อาร์กิวเมนต์
โดยปกติแต่ละการเรียกไปrun
, check_output
หรือPopen
คอนสตรัรันโปรแกรมเดียว นั่นหมายความว่าไม่มีท่อทุบตีสไตล์แฟนซี หากคุณต้องการรันคำสั่งเชลล์ที่ซับซ้อนคุณสามารถส่งผ่านshell=True
ซึ่งทั้งสามฟังก์ชั่นสนับสนุน
แต่การทำเช่นนั้นทำให้เกิดความกังวลด้านความปลอดภัย หากคุณกำลังทำอะไรมากกว่าสคริปต์ไฟคุณอาจจะดีกว่าที่จะเรียกแต่ละกระบวนการแยกจากกันและส่งผ่านเอาต์พุตจากแต่ละวิธีเป็นอินพุตไปยังถัดไป
run(cmd, [stdout=etc...], input=other_output)
หรือ
Popen(cmd, [stdout=etc...]).communicate(other_output)
สิ่งล่อใจที่จะเชื่อมต่อท่อโดยตรงนั้นแข็งแกร่ง ต่อต้านมัน มิฉะนั้นคุณอาจจะเห็นการติดตายหรือมีการทำสิ่ง hacky เช่นนี้
2. ข้อควรพิจารณาของ Unicode
check_output
ส่งคืนสตริงใน Python 2 แต่เป็นbytes
วัตถุใน Python 3 มันควรใช้เวลาสักครู่เพื่อเรียนรู้เกี่ยวกับยูนิโค้ดถ้าคุณยังไม่ได้ทำ