วิธีดำเนินการคำสั่งเชลล์ใน Python โดยใช้วิธีเรียกใช้กระบวนการย่อย

How Execute Shell Commands Python Using Subprocess Run Method



กระบวนการย่อยเป็นโมดูล Python ในตัวที่สามารถใช้เพื่อสร้างกระบวนการใหม่และโต้ตอบกับสตรีมข้อมูลอินพุตและเอาต์พุต พูดง่ายๆ ก็คือ คุณสามารถใช้เพื่อรันคำสั่งเชลล์และรันไบนารีที่ปฏิบัติการได้ ซึ่งปกติจะกระจัดกระจายอยู่ในโฟลเดอร์ bin ต่างๆ ทั่วทั้งระบบไฟล์ Linux คุณยังสามารถระบุพาธแบบเต็มไปยังไบนารีที่ปฏิบัติการได้ และใช้สวิตช์บรรทัดคำสั่งใดๆ ที่เชื่อมโยงกับไบนารี บทความนี้จะอธิบายวิธีใช้โมดูลกระบวนการย่อยและวิธีการเรียกใช้ในแอป Python ตัวอย่างโค้ดทั้งหมดในบทความได้รับการทดสอบด้วย Python 3.8.2 บน Ubuntu 20.04

วิธีการ Subprocess.run

วิธีการ Subprocess.run รับรายการอาร์กิวเมนต์ เมื่อเรียกเมธอด มันจะรันคำสั่งและรอให้กระบวนการเสร็จสิ้น ส่งคืนอ็อบเจ็กต์ CompletedProcess ในตอนท้าย วัตถุ CompletedProcess ส่งคืน stdout, stderr อาร์กิวเมนต์ดั้งเดิมที่ใช้ขณะเรียกใช้เมธอด และโค้ดส่งคืน Stdout หมายถึงสตรีมข้อมูลที่ผลิตโดยคำสั่ง ในขณะที่ stderr หมายถึงข้อผิดพลาดใดๆ ที่เกิดขึ้นระหว่างการดำเนินการของโปรแกรม รหัสส่งคืนที่ไม่ใช่ศูนย์ (รหัสออก) จะหมายถึงข้อผิดพลาดกับคำสั่งที่ดำเนินการในเมธอด subprocess.run







ตัวอย่างที่ 1: เนื้อหาเอาต์พุตของไฟล์ข้อความโดยใช้วิธีการ Subprocess.run

คำสั่งด้านล่างจะแสดงผลเนื้อหาของไฟล์ data.txt โดยถือว่ามีสตริง name=John



นำเข้า กระบวนการย่อย
กระบวนการย่อย.วิ่ง(['แมว', 'data.txt'])

การเรียกใช้โค้ดด้านบนจะส่งคืนผลลัพธ์ต่อไปนี้:



ชื่อ=จอห์น
เสร็จสิ้นกระบวนการ(args=['แมว', 'data.txt'],รหัสส่งคืน=0)

องค์ประกอบแรกของอาร์กิวเมนต์ list คือชื่อของคำสั่งที่จะดำเนินการ องค์ประกอบใดๆ ในรายการที่ตามหลังองค์ประกอบแรกถือเป็นตัวเลือกหรือสวิตช์บรรทัดคำสั่ง คุณสามารถใช้เส้นประเดี่ยวและขีดคู่ได้เช่นกัน เพื่อกำหนดตัวเลือก ตัวอย่างเช่น ในการแสดงรายการไฟล์และโฟลเดอร์ในไดเร็กทอรี โค้ดจะเป็น subprocess.run([ls, -l] ในกรณีส่วนใหญ่ คุณสามารถพิจารณาอาร์กิวเมนต์ที่คั่นด้วยช่องว่างในคำสั่งเชลล์เป็นองค์ประกอบแต่ละรายการใน รายการที่จัดให้กับเมธอด subprocess.run





ตัวอย่างที่ 2: ระงับเอาต์พุตของ Subprocess.run Method

หากต้องการระงับเอาต์พุตของเมธอด subprocess.run คุณจะต้องระบุ stdout=subprocess.DEVNULL และ stderr=subprocess.DEVNULL เป็นอาร์กิวเมนต์เพิ่มเติม

นำเข้า กระบวนการย่อย

กระบวนการย่อย.วิ่ง(['แมว', 'data.txt'],stdout=กระบวนการย่อย.DEVNULL,
stderr=กระบวนการย่อย.DEVNULL)

การรันโค้ดด้านบนจะสร้างผลลัพธ์ต่อไปนี้:



CompletedProcess(args=['cat', 'data.txt'], รหัสส่งคืน=0)

ตัวอย่างที่ 3: จับผลลัพธ์ของวิธีการ Subprocess.run

ในการดักจับเอาต์พุตของเมธอด subprocess.run ให้ใช้อาร์กิวเมนต์เพิ่มเติมชื่อ capture_output=True

นำเข้า กระบวนการย่อย
ผลผลิต= กระบวนการย่อย.วิ่ง(['แมว', 'data.txt'],แคปเจอร์_เอาท์พุต=จริง)
พิมพ์ (ผลผลิต)

การรันโค้ดด้านบนจะสร้างผลลัพธ์ต่อไปนี้:

เสร็จสิ้นกระบวนการ(args=['แมว', 'data.txt'],รหัสส่งคืน=0,
stdout=NS'ชื่อ=จอห์นNS',stderr=NS'')

คุณสามารถเข้าถึงค่า stdout และ stderr แยกกันได้โดยใช้วิธี output.stdout และ output.stderr เอาต์พุตถูกสร้างเป็นลำดับไบต์ หากต้องการรับสตริงเป็นเอาต์พุต ให้ใช้เมธอด output.stdout.decode(utf-8) คุณยังสามารถระบุ text=True เป็นอาร์กิวเมนต์เพิ่มเติมสำหรับการเรียก subprocess.run เพื่อรับเอาต์พุตในรูปแบบสตริง หากต้องการรับรหัสสถานะการออก คุณสามารถใช้วิธี output.returncode

ตัวอย่างที่ 4: เพิ่มข้อยกเว้นความล้มเหลวของคำสั่งที่ดำเนินการโดย Subprocess.run Method

เมื่อต้องการยกข้อยกเว้นเมื่อคำสั่งออกโดยมีสถานะไม่เป็นศูนย์ ให้ใช้อาร์กิวเมนต์ check=True

นำเข้า กระบวนการย่อย
กระบวนการย่อย.วิ่ง(['แมว', 'data.tx'],แคปเจอร์_เอาท์พุต=จริง,ข้อความ=จริง,ตรวจสอบ=จริง)

การรันโค้ดด้านบนจะสร้างผลลัพธ์ต่อไปนี้:

เพิ่ม CalledProcessError (retcode, process.args,
subprocess.CalledProcessError: คำสั่ง '['cat', 'data.tx']'
ส่งคืนสถานะการออกที่ไม่ใช่ศูนย์ 1

ตัวอย่างที่ 5: ส่งสตริงไปยังคำสั่งที่ดำเนินการโดย Subprocess.run Method

คุณสามารถส่งสตริงไปยังคำสั่งที่จะดำเนินการโดยเมธอด subprocess.run โดยใช้อาร์กิวเมนต์ input='string'

นำเข้า กระบวนการย่อย
ผลผลิต= กระบวนการย่อย.วิ่ง(['แมว'], ป้อนข้อมูล='data.txt',แคปเจอร์_เอาท์พุต=จริง,
ข้อความ=จริง,ตรวจสอบ=จริง)
พิมพ์ (ผลผลิต)

การรันโค้ดด้านบนจะสร้างผลลัพธ์ต่อไปนี้:

CompletedProcess(args=['cat'], returncode=0, stdout='data.txt', stderr='')

อย่างที่คุณเห็น โค้ดด้านบนส่งผ่าน data.txt เป็นสตริง ไม่ใช่เป็นออบเจกต์ไฟล์ หากต้องการส่ง data.txt เป็นไฟล์ ให้ใช้อาร์กิวเมนต์ stdin

กับ เปิด('data.txt') เช่นNS:
ผลผลิต= กระบวนการย่อย.วิ่ง(['แมว'],stdin=NS,แคปเจอร์_เอาท์พุต=จริง,
ข้อความ=จริง,ตรวจสอบ=จริง)
พิมพ์ (ผลผลิต)

การรันโค้ดด้านบนจะสร้างผลลัพธ์ต่อไปนี้:

CompletedProcess(args=['cat'], returncode=0, stdout='name=John ', stderr='')

ตัวอย่างที่ 6: ดำเนินการคำสั่งโดยตรงในเชลล์โดยใช้วิธีการ Subprocess.run

เป็นไปได้ที่จะรันคำสั่งโดยตรงในเชลล์ตามที่เป็นอยู่ แทนที่จะใช้สตริงที่แยกในคำสั่งหลักและตัวเลือกที่ตามมา ในการดำเนินการนี้ คุณต้องส่งผ่าน shell=True เป็นอาร์กิวเมนต์เพิ่มเติม อย่างไรก็ตาม สิ่งนี้ไม่สนับสนุนโดยนักพัฒนา python เนื่องจากการใช้ shell=True อาจทำให้เกิดปัญหาด้านความปลอดภัย คุณสามารถอ่านเพิ่มเติมเกี่ยวกับผลกระทบด้านความปลอดภัยจาก ที่นี่ .

นำเข้า กระบวนการย่อย
กระบวนการย่อย.วิ่ง('แมว 'data.txt'',เปลือก=จริง)

การรันโค้ดด้านบนจะสร้างผลลัพธ์ต่อไปนี้:

ชื่อ=จอห์น

บทสรุป

เมธอด subprocess.run ใน Python นั้นค่อนข้างทรงพลัง เนื่องจากช่วยให้คุณเรียกใช้คำสั่งเชลล์ภายในไพธอนได้เอง ซึ่งช่วยในการจำกัดโค้ดทั้งหมดไว้ที่ไพ ธ อนเองโดยไม่จำเป็นต้องมีโค้ดเชลล์สคริปต์เพิ่มเติมในไฟล์แยกกัน อย่างไรก็ตาม การ tokenize คำสั่งเชลล์ในรายการ python อย่างถูกต้องอาจเป็นเรื่องยาก คุณสามารถใช้เมธอด shlex.split() เพื่อสร้างโทเค็นให้กับคำสั่งเชลล์อย่างง่ายได้ แต่ในคำสั่งที่ซับซ้อนและยาวนาน โดยเฉพาะที่มีสัญลักษณ์ไพพ์ shlex ไม่สามารถแยกคำสั่งได้อย่างถูกต้อง ในกรณีเช่นนี้ การดีบักอาจเป็นปัญหาที่ยุ่งยาก คุณสามารถใช้อาร์กิวเมนต์ shell=True เพื่อหลีกเลี่ยงปัญหานี้ แต่มีข้อกังวลด้านความปลอดภัยบางประการที่เกี่ยวข้องกับการดำเนินการนี้