เรียกใช้ bash script จากภายใน python


114

ฉันมีปัญหากับรหัสต่อไปนี้:

callBash.py:

import subprocess
print "start"
subprocess.call("sleep.sh")
print "end"

sleep.sh:

sleep 10

ฉันต้องการให้พิมพ์ "สิ้นสุด" หลังจาก 10 วินาที (ฉันรู้ว่านี่เป็นตัวอย่างที่โง่ฉันสามารถนอนใน python ได้ แต่ไฟล์ sleep.sh ธรรมดานี้เป็นเพียงการทดสอบ)


ฉันลองใช้ด้วย "$! bin / bash; sleep 10;"
user1638145

ไม่ชัดเจนว่านักแสวงหานี้พยายามถามปัญหาอะไร แต่คำถามน่าจะยังคงอยู่เนื่องจากมีการคาดเดาที่ดีมากหรือน้อยเป็นคำตอบ อาจค้นหาข้อผิดพลาดเฉพาะของคุณและ / หรืออ่านคำถามที่เกี่ยวข้องเช่นstackoverflow.com/questions/4256107/…
tripleee

คำตอบ:


96

การทำให้ sleep.sh ทำงานได้และเพิ่มshell=Trueในรายการพารามิเตอร์ (ตามที่แนะนำในคำตอบก่อนหน้านี้) ก็ใช้ได้ คุณอาจต้องเพิ่ม./หรือเส้นทางอื่นที่เหมาะสมทั้งนี้ขึ้นอยู่กับเส้นทางการค้นหา (กล่าวคือเปลี่ยน"sleep.sh"เป็น"./sleep.sh".)

shell=Trueพารามิเตอร์ไม่จำเป็น (ภายใต้ระบบ Posix เช่น Linux) ถ้าบรรทัดแรกของสคริปต์ทุบตีเป็นเส้นทางไปยังเปลือกที่; ตัวอย่างเช่น#!/bin/bash.


52

หากsleep.shมี shebang #!/bin/shและมีการอนุญาตไฟล์ที่เหมาะสมให้รันchmod u+rx sleep.shเพื่อให้แน่ใจและอยู่ใน$PATHรหัสของคุณควรทำงานตามที่เป็นอยู่

import subprocess

rc = subprocess.call("sleep.sh")

หากสคริปต์ไม่ได้อยู่ใน PATH ให้ระบุเส้นทางแบบเต็มเช่นหากอยู่ในไดเร็กทอรีการทำงานปัจจุบัน:

from subprocess import call

rc = call("./sleep.sh")

หากสคริปต์ไม่มี shebang คุณต้องระบุshell=True:

rc = call("./sleep.sh", shell=True)

หากสคริปต์ไม่มีสิทธิ์ในการเรียกใช้งานและคุณไม่สามารถเปลี่ยนแปลงได้เช่นการรันos.chmod('sleep.sh', 0o755)คุณสามารถอ่านสคริปต์เป็นไฟล์ข้อความและส่งสตริงไปยังsubprocessโมดูลแทน:

with open('sleep.sh', 'rb') as file:
    script = file.read()
rc = call(script, shell=True)

35

จริงๆแล้วคุณต้องเพิ่มshell=Trueอาร์กิวเมนต์:

subprocess.call("sleep.sh", shell=True)

แต่ระวัง -

คำเตือนการเรียกใช้เชลล์ระบบด้วยเชลล์ = True อาจเป็นอันตรายต่อความปลอดภัยหากรวมกับอินพุตที่ไม่น่าเชื่อถือ ดูคำเตือนภายใต้อาร์กิวเมนต์ที่ใช้บ่อยสำหรับรายละเอียด

แหล่งที่มา


1
จะไม่ทำงานหากsleep.shไม่ได้อยู่ในไฟล์PATH. และถ้ามันอยู่ในเส้นทางและมี Shebang ที่ถูกต้องคุณก็ไม่จำเป็นต้องshell=Trueใช้ ดูคำตอบของฉัน
jfs

19

หากมีคนกำลังมองหาการเรียกสคริปต์ที่มีข้อโต้แย้ง

import subprocess

val = subprocess.check_call("./script.sh '%s'" % arg, shell=True)

อย่าลืมแปลง args เป็นสตริงก่อนส่งผ่านโดยใช้ str (arg)

สามารถใช้เพื่อส่งผ่านอาร์กิวเมนต์ได้มากเท่าที่ต้องการ:

subprocess.check_call("./script.ksh %s %s %s" % (arg1, str(arg2), arg3), shell=True)

12

ตรวจสอบให้แน่ใจว่าsleep.shมีสิทธิ์ในการดำเนินการและเรียกใช้ด้วยshell=True:

#!/usr/bin/python

import subprocess
print "start"
subprocess.call("./sleep.sh", shell=True)
print "end"

ดังนั้นมันจึงเป็นเปลือก = จริงฉันพลาด คุณช่วยอธิบายได้ไหมว่าทำไมการตั้งค่า #! bin / bash ในบรรทัดแรกของ sh scricpt จึงไม่เพียงพอ
user1638145

4
ข้อผิดพลาดในการเป็นผู้ที่ขาดหายไป #!bin/bash ทำงานตามที่ฉันทราบในคำตอบ /#!/bin/bash
James Waldby - jwpat7

10

หาก chmod ไม่ทำงานให้คุณลองด้วย

import os
os.system('sh script.sh')
#you can also use bash instead of sh

ทดสอบโดยฉันขอบคุณ


os.systemเอกสารเฉพาะแนะนำให้หลีกเลี่ยงมันในความโปรดปรานของsubprocess(วันนี้subprocess.run()) หากคุณไม่สามารถsubprocessไปทำงานได้โอกาสที่คุณจะมีปัญหาos.system()เช่นกัน
tripleee

3

การเพิ่มคำตอบเนื่องจากฉันถูกนำไปที่นี่หลังจากถามวิธีเรียกใช้ bash script จาก python คุณได้รับข้อผิดพลาดOSError: [Errno 2] file not foundหากสคริปต์ของคุณใช้พารามิเตอร์ ตัวอย่างเช่นสมมติว่าสคริปต์ของคุณใช้เวลาในพารามิเตอร์ sleep time: subprocess.call("sleep.sh 10")จะไม่ทำงานคุณต้องส่งผ่านเป็นอาร์เรย์:subprocess.call(["sleep.sh", 10])


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