Làm thế nào để bạn gọi một lệnh bên ngoài (như thể tôi đã gõ nó vào shell Unix hoặc dấu nhắc lệnh Windows) từ trong tập lệnh Python?
Làm thế nào để bạn gọi một lệnh bên ngoài (như thể tôi đã gõ nó vào shell Unix hoặc dấu nhắc lệnh Windows) từ trong tập lệnh Python?
Câu trả lời:
Nhìn vào mô đun quy trình con trong thư viện tiêu chuẩn:
import subprocess
subprocess.run(["ls", "-l"])
Ưu điểm của subprocess
vs. system
là nó là linh hoạt hơn (bạn có thể nhận được stdout
, stderr
thì "thật" mã trạng thái, xử lý lỗi tốt hơn, vv ...).
Các tài liệu chính thức khuyến nghị các subprocess
mô-đun thay thế os.system()
:
Các
subprocess
mô-đun cung cấp cơ sở vật chất mạnh mẽ hơn để đẻ trứng quy trình mới và lấy kết quả của họ; sử dụng mô-đun đó tốt hơn là sử dụng chức năng này [os.system()
].
Phần Thay thế các Hàm cũ bằng phần Mô đun quy trình con trong subprocess
tài liệu có thể có một số công thức nấu ăn hữu ích.
Đối với các phiên bản Python trước 3.5, hãy sử dụng call
:
import subprocess
subprocess.call(["ls", "-l"])
shell=True
để làm việc đó.
shell=True
, vì mục đích này Python đi kèm với os.path.Exandvars . Trong trường hợp của bạn, bạn có thể viết : os.path.expandvars("$PATH")
. @SethMMorton vui lòng xem xét lại nhận xét của bạn -> Tại sao không sử dụng shell = True
for
vòng lặp, làm thế nào để tôi làm điều đó mà không chặn tập lệnh python của tôi? Tôi không quan tâm đến đầu ra của lệnh mà tôi chỉ muốn chạy nhiều lệnh.
subprocess
khi nào shell=False
, sau đó sử dụng shlex.split
một cách dễ dàng để thực hiện điều này docs.python.org/2/l Library / shlex.html
Dưới đây là tóm tắt về các cách gọi chương trình bên ngoài và ưu điểm và nhược điểm của từng chương trình:
os.system("some_command with args")
chuyển lệnh và đối số đến trình bao hệ thống của bạn. Điều này là tốt bởi vì bạn thực sự có thể chạy nhiều lệnh cùng một lúc theo cách này và thiết lập đường ống và chuyển hướng đầu vào / đầu ra. Ví dụ:
os.system("some_command < input_file | another_command > output_file")
Tuy nhiên, trong khi điều này thuận tiện, bạn phải xử lý thủ công thoát các ký tự shell như dấu cách, v.v. Mặt khác, điều này cũng cho phép bạn chạy các lệnh đơn giản là các lệnh shell chứ không thực sự là các chương trình bên ngoài. Xem tài liệu .
stream = os.popen("some_command with args")
sẽ làm điều tương tự như os.system
ngoại trừ việc nó cung cấp cho bạn một đối tượng giống như tệp mà bạn có thể sử dụng để truy cập đầu vào / đầu ra tiêu chuẩn cho quy trình đó. Có 3 biến thể khác của popen mà tất cả đều xử lý i / o hơi khác nhau. Nếu bạn truyền mọi thứ dưới dạng một chuỗi, thì lệnh của bạn được truyền vào shell; nếu bạn vượt qua chúng dưới dạng một danh sách thì bạn không cần phải lo lắng về việc thoát khỏi bất cứ điều gì. Xem tài liệu .
Các Popen
lớp của subprocess
mô-đun. Điều này được dự định như là một sự thay thế cho os.popen
nhưng có nhược điểm là hơi phức tạp hơn một chút do tính toàn diện của nó. Ví dụ: bạn nói:
print subprocess.Popen("echo Hello World", shell=True, stdout=subprocess.PIPE).stdout.read()
thay vì:
print os.popen("echo Hello World").read()
nhưng thật tuyệt khi có tất cả các tùy chọn ở đó trong một lớp thống nhất thay vì 4 hàm popen khác nhau. Xem tài liệu .
Các call
chức năng từ các subprocess
mô-đun. Điều này về cơ bản giống như Popen
lớp và nhận tất cả các đối số giống nhau, nhưng nó chỉ đơn giản là đợi cho đến khi lệnh hoàn thành và cung cấp cho bạn mã trả về. Ví dụ:
return_code = subprocess.call("echo Hello World", shell=True)
Xem tài liệu .
Nếu bạn đang dùng Python 3.5 trở lên, bạn có thể sử dụng subprocess.run
hàm mới , giống như ở trên nhưng thậm chí linh hoạt hơn và trả về một CompletedProcess
đối tượng khi lệnh kết thúc thực thi.
Mô-đun os cũng có tất cả các chức năng fork / exec / spawn mà bạn có trong chương trình C, nhưng tôi không khuyên bạn nên sử dụng chúng trực tiếp.
Các subprocess
mô-đun có lẽ nên là những gì bạn sử dụng.
Cuối cùng, xin lưu ý rằng đối với tất cả các phương thức mà bạn chuyển lệnh cuối cùng sẽ được shell thực thi dưới dạng chuỗi và bạn có trách nhiệm thoát khỏi nó. Có những tác động bảo mật nghiêm trọng nếu bất kỳ phần nào của chuỗi mà bạn vượt qua không thể được tin cậy hoàn toàn. Ví dụ: nếu người dùng đang nhập một số / bất kỳ phần nào của chuỗi. Nếu bạn không chắc chắn, chỉ sử dụng các phương pháp này với hằng số. Để cung cấp cho bạn một gợi ý về các hàm ý, hãy xem xét mã này:
print subprocess.Popen("echo %s " % user_input, stdout=PIPE).stdout.read()
và tưởng tượng rằng người dùng nhập vào một cái gì đó "mẹ tôi không yêu tôi && rm -rf /" có thể xóa toàn bộ hệ thống tập tin.
open
.
subprocess.run()
. docs.python.org/3.5/l Library / sub process.html
subprocess.run(..)
chính xác thì "Điều này không bắt được thiết bị xuất chuẩn hoặc thiết bị xuất chuẩn theo mặc định". bao hàm, ngụ ý? Điều gì về subprocess.check_output(..)
và STDERR?
echo
phía trước của chuỗi được truyền đến Popen
? Vì vậy, lệnh đầy đủ sẽ được echo my mama didnt love me && rm -rf /
.
subprocess.run()
hoặc anh chị của nó subprocess.check_call()
et al. Đối với những trường hợp không đủ, xem subprocess.Popen()
. os.popen()
có lẽ không nên đề cập gì cả, hoặc đến ngay cả sau khi "hack mã fork / exec / spawn của riêng bạn".
Thực hiện điển hình:
import subprocess
p = subprocess.Popen('ls', shell=True, stdout=subprocess.PIPE, stderr=subprocess.STDOUT)
for line in p.stdout.readlines():
print line,
retval = p.wait()
Bạn có thể tự do làm những gì bạn muốn với stdout
dữ liệu trong đường ống. Trong thực tế, bạn có thể chỉ cần bỏ qua các tham số đó ( stdout=
và stderr=
) và nó sẽ hoạt động như thế nào os.system()
.
.readlines()
đọc tất cả các dòng cùng một lúc, nó chặn cho đến khi quá trình con thoát ra (đóng phần cuối của đường ống). Để đọc trong thời gian thực (nếu không có vấn đề về bộ đệm), bạn có thể:for line in iter(p.stdout.readline, ''): print line,
p.stdout.readline()
(lưu ý: không s
ở cuối) sẽ không thấy bất kỳ dữ liệu nào cho đến khi đứa trẻ điền vào bộ đệm. Nếu đứa trẻ không tạo ra nhiều dữ liệu thì đầu ra sẽ không ở trong thời gian thực. Xem lý do thứ hai trong Q: Tại sao không sử dụng một đường ống (popen ())? . Một số biện pháp khắc phục được cung cấp trong câu trả lời này (Pexpect, pty, stdbuf)
Popen
cho các nhiệm vụ đơn giản. Điều này cũng không cần thiết chỉ định shell=True
. Hãy thử một trong những subprocess.run()
câu trả lời.
Một số gợi ý về việc tách tiến trình con khỏi lệnh gọi (bắt đầu tiến trình con ở chế độ nền).
Giả sử bạn muốn bắt đầu một nhiệm vụ dài từ tập lệnh CGI. Đó là, quy trình con nên sống lâu hơn quy trình thực thi tập lệnh CGI.
Ví dụ cổ điển từ tài liệu mô đun quy trình con là:
import subprocess
import sys
# Some code here
pid = subprocess.Popen([sys.executable, "longtask.py"]) # Call subprocess
# Some more code here
Ý tưởng ở đây là bạn không muốn đợi trong dòng 'gọi quy trình con' cho đến khi longtask.py kết thúc. Nhưng không rõ điều gì xảy ra sau dòng 'một số mã nữa ở đây' từ ví dụ.
Nền tảng mục tiêu của tôi là FreeBSD, nhưng sự phát triển là trên Windows, vì vậy tôi đã gặp vấn đề trên Windows trước tiên.
Trên Windows (Windows XP), quy trình cha mẹ sẽ không hoàn thành cho đến khi longtask.py hoàn thành công việc. Nó không phải là những gì bạn muốn trong một kịch bản CGI. Vấn đề không cụ thể đối với Python; trong cộng đồng PHP các vấn đề là như nhau.
Giải pháp là chuyển cờ DETACHED_PROCESS cho quá trình tạo cờ cho hàm CreatProcess bên dưới trong API Windows. Nếu bạn đã cài đặt pywin32, bạn có thể nhập cờ từ mô-đun win32 Process, nếu không, bạn nên tự xác định nó:
DETACHED_PROCESS = 0x00000008
pid = subprocess.Popen([sys.executable, "longtask.py"],
creationflags=DETACHED_PROCESS).pid
/ * CẬP NHẬT 2015.10.27 @eryksun trong một bình luận bên dưới ghi chú, rằng cờ chính xác về mặt ngữ nghĩa là CREATE_NEW_CONSOLE (0x00000010) * /
Trên FreeBSD, chúng tôi có một vấn đề khác: khi quá trình cha kết thúc, nó cũng hoàn thành các tiến trình con. Và đó cũng không phải là điều bạn muốn trong kịch bản CGI. Một số thí nghiệm cho thấy vấn đề dường như nằm ở việc chia sẻ sys.stdout. Và giải pháp làm việc là như sau:
pid = subprocess.Popen([sys.executable, "longtask.py"], stdout=subprocess.PIPE, stderr=subprocess.PIPE, stdin=subprocess.PIPE)
Tôi chưa kiểm tra mã trên các nền tảng khác và không biết lý do của hành vi trên FreeBSD. Nếu ai biết, xin vui lòng chia sẻ ý tưởng của bạn. Googling khi bắt đầu các quá trình nền trong Python vẫn chưa làm sáng tỏ.
DETACHED_PROCESS
trong creationflags
tránh được điều này bằng cách ngăn chặn các con từ thừa kế hoặc tạo ra một giao diện điều khiển. Thay vào đó, nếu bạn muốn có một giao diện điều khiển mới, hãy sử dụng CREATE_NEW_CONSOLE
(0x00000010).
os.devnull
do một số chương trình bảng điều khiển thoát với lỗi khác. Tạo một giao diện điều khiển mới khi bạn muốn tiến trình con tương tác với người dùng đồng thời với tiến trình cha. Sẽ thật khó hiểu khi cố gắng làm cả hai trong một cửa sổ.
import os
os.system("your command")
Lưu ý rằng điều này là nguy hiểm, vì lệnh không được làm sạch. Tôi để nó cho bạn google để tìm tài liệu liên quan về các mô-đun 'os' và 'sys'. Có một loạt các hàm (exec * và spawn *) sẽ làm những việc tương tự.
subprocess
như là một giải pháp linh hoạt và di động hơn một chút. Chạy các lệnh bên ngoài dĩ nhiên là không thể truy cập được (bạn phải đảm bảo lệnh có sẵn trên mọi kiến trúc bạn cần hỗ trợ) và chuyển đầu vào của người dùng vì lệnh bên ngoài vốn không an toàn.
Tôi khuyên bạn nên sử dụng mô-đun quy trình con thay vì os.system vì nó thoát vỏ cho bạn và do đó an toàn hơn nhiều.
subprocess.call(['ping', 'localhost'])
subprocess
khi nào shell=False
, sau đó sử dụng shlex.split
một cách dễ dàng để thực hiện điều này docs.python.org/2/l Library / shlex.html # shlex.split ( đó là cách được đề xuất theo tài liệu docs.python.org/2/l Library / sub process.html # popen-constructor )
import os
cmd = 'ls -al'
os.system(cmd)
Nếu bạn muốn trả về kết quả của lệnh, bạn có thể sử dụng os.popen
. Tuy nhiên, điều này không được chấp nhận vì phiên bản 2.6 có lợi cho mô đun quy trình con , mà các câu trả lời khác đã được đề cập tốt.
Có rất nhiều thư viện khác nhau cho phép bạn gọi các lệnh bên ngoài bằng Python. Đối với mỗi thư viện tôi đã đưa ra một mô tả và hiển thị một ví dụ về cách gọi lệnh bên ngoài. Lệnh tôi sử dụng làm ví dụ là ls -l
(liệt kê tất cả các tệp). Nếu bạn muốn tìm hiểu thêm về bất kỳ thư viện nào tôi đã liệt kê và liên kết tài liệu cho từng thư viện.
Nguồn:
Đây là tất cả các thư viện:
Hy vọng rằng điều này sẽ giúp bạn đưa ra quyết định sử dụng thư viện nào :)
quy trình con
Quá trình con cho phép bạn gọi các lệnh bên ngoài và kết nối chúng với các ống đầu vào / đầu ra / lỗi của chúng (stdin, stdout và stderr). Sub process là lựa chọn mặc định để chạy các lệnh, nhưng đôi khi các mô-đun khác tốt hơn.
subprocess.run(["ls", "-l"]) # Run command
subprocess.run(["ls", "-l"], stdout=subprocess.PIPE) # This will run the command and return any output
subprocess.run(shlex.split("ls -l")) # You can also use the shlex library to split the command
hệ điều hành
os được sử dụng cho "chức năng phụ thuộc hệ điều hành". Nó cũng có thể được sử dụng để gọi các lệnh bên ngoài bằng os.system
và os.popen
(Lưu ý: Ngoài ra còn có một quy trình con.popen). os sẽ luôn chạy shell và là một thay thế đơn giản cho những người không cần hoặc không biết cách sử dụng subprocess.run
.
os.system("ls -l") # run command
os.popen("ls -l").read() # This will run the command and return any output
sh
sh là một giao diện quy trình con cho phép bạn gọi các chương trình như thể chúng là các hàm. Điều này rất hữu ích nếu bạn muốn chạy một lệnh nhiều lần.
sh.ls("-l") # Run command normally
ls_cmd = sh.Command("ls") # Save command as a variable
ls_cmd() # Run command as if it were a function
trực tràng
plumbum là một thư viện cho các chương trình Python "giống như kịch bản". Bạn có thể gọi các chương trình như các chức năng như trong sh
. Plumbum rất hữu ích nếu bạn muốn chạy một đường ống mà không có vỏ.
ls_cmd = plumbum.local("ls -l") # get command
ls_cmd() # run command
khai thác
khai thác cho phép bạn sinh ra các ứng dụng con, kiểm soát chúng và tìm các mẫu trong đầu ra của chúng. Đây là một sự thay thế tốt hơn cho quy trình con cho các lệnh mong đợi một tty trên Unix.
pexpect.run("ls -l") # Run command as normal
child = pexpect.spawn('scp foo user@example.com:.') # Spawns child application
child.expect('Password:') # When this is the output
child.sendline('mypassword')
sợi vải
vải là một thư viện Python 2.5 và 2.7. Nó cho phép bạn thực hiện các lệnh shell cục bộ và từ xa. Fabric là cách thay thế đơn giản để chạy các lệnh trong trình bao an toàn (SSH)
fabric.operations.local('ls -l') # Run command as normal
fabric.operations.local('ls -l', capture = True) # Run command and receive output
phái viên
Đặc phái viên được gọi là "quy trình con người". Nó được sử dụng như một trình bao bọc tiện lợi xung quanh subprocess
mô-đun.
r = envoy.run("ls -l") # Run command
r.std_out # get output
lệnh
commands
chứa các hàm bao bọc cho os.popen
, nhưng nó đã bị xóa khỏi Python 3 vì đây subprocess
là một lựa chọn tốt hơn.
Việc chỉnh sửa được dựa trên bình luận của JF Sebastian.
Tôi luôn luôn sử dụng fabric
cho những thứ này như:
from fabric.operations import local
result = local('ls', capture=True)
print "Content:/n%s" % (result, )
Nhưng đây có vẻ là một công cụ tốt: sh
(Giao diện quy trình con Python) .
Nhìn vào một ví dụ:
from sh import vgdisplay
print vgdisplay()
print vgdisplay('-v')
print vgdisplay(v=True)
Kiểm tra thư viện Python "khai thác", quá.
Nó cho phép kiểm soát tương tác các chương trình / lệnh bên ngoài, thậm chí ssh, ftp, telnet, v.v. Bạn chỉ có thể gõ một cái gì đó như:
child = pexpect.spawn('ftp 192.168.0.24')
child.expect('(?i)name .*: ')
child.sendline('anonymous')
child.expect('(?i)password')
Sử dụng mô đun quy trình con (Python 3):
import subprocess
subprocess.run(['ls', '-l'])
Đây là cách tiêu chuẩn được đề nghị. Tuy nhiên, các tác vụ phức tạp hơn (đường ống, đầu ra, đầu vào, v.v.) có thể tẻ nhạt để xây dựng và viết.
Lưu ý trên phiên bản Python: Nếu bạn vẫn đang sử dụng Python 2, sub process.call hoạt động theo cách tương tự.
ProTip: shlex.split có thể giúp bạn phân tích cú pháp lệnh cho run
, call
và khác subprocess
chức năng trong trường hợp bạn không muốn (hoặc bạn có thể không!) Cung cấp cho họ dưới hình thức danh sách:
import shlex
import subprocess
subprocess.run(shlex.split('ls -l'))
Nếu bạn không quan tâm đến sự phụ thuộc bên ngoài, hãy sử dụng plumbum :
from plumbum.cmd import ifconfig
print(ifconfig['wlan0']())
Nó là subprocess
gói tốt nhất . Đó là nền tảng chéo, tức là nó hoạt động trên cả hai hệ thống giống Windows và Unix. Cài đặt bằng pip install plumbum
.
Một thư viện phổ biến khác là sh :
from sh import ifconfig
print(ifconfig('wlan0'))
Tuy nhiên, sh
đã bỏ hỗ trợ Windows, vì vậy nó không còn tuyệt vời như trước đây. Cài đặt bằng pip install sh
.
Nếu bạn cần đầu ra từ lệnh bạn đang gọi, sau đó bạn có thể sử dụng subprocess.check_output (Python 2.7+).
>>> subprocess.check_output(["ls", "-l", "/dev/null"])
'crw-rw-rw- 1 root root 1, 3 Oct 18 2007 /dev/null\n'
Cũng lưu ý tham số shell .
Nếu shell là
True
, lệnh được chỉ định sẽ được thực thi thông qua shell. Điều này có thể hữu ích nếu bạn đang sử dụng Python chủ yếu cho luồng điều khiển nâng cao mà nó cung cấp trên hầu hết các hệ thống và vẫn muốn truy cập thuận tiện vào các tính năng vỏ khác như ống vỏ, ký tự đại diện tên tệp, mở rộng biến môi trường và mở rộng ~ đến nhà của người dùng danh mục. Tuy nhiên, lưu ý rằng Python chính nó cung cấp triển khai của nhiều vỏ giống như tính năng (đặc biệt làglob
,fnmatch
,os.walk()
,os.path.expandvars()
,os.path.expanduser()
, vàshutil
).
check_output
yêu cầu một danh sách chứ không phải là một chuỗi. Nếu bạn không dựa vào khoảng trắng được trích dẫn để thực hiện cuộc gọi của mình hợp lệ, cách đơn giản nhất, dễ đọc nhất để thực hiện việc này là subprocess.check_output("ls -l /dev/null".split())
.
Đây là cách tôi chạy các lệnh của tôi. Mã này có mọi thứ bạn cần khá nhiều
from subprocess import Popen, PIPE
cmd = "ls -l ~/"
p = Popen(cmd , shell=True, stdout=PIPE, stderr=PIPE)
out, err = p.communicate()
print "Return code: ", p.returncode
print out.rstrip(), err.rstrip()
subprocess.run
là cách tiếp cận được đề xuất kể từ Python 3.5 nếu mã của bạn không cần duy trì khả năng tương thích với các phiên bản Python trước đó. Nó phù hợp hơn và cung cấp tính dễ sử dụng tương tự như Envoy. (Mặc dù đường ống không đơn giản như vậy. Xem câu hỏi này để biết cách .)
Dưới đây là một số ví dụ từ tài liệu .
Chạy một quá trình:
>>> subprocess.run(["ls", "-l"]) # Doesn't capture output
CompletedProcess(args=['ls', '-l'], returncode=0)
Tăng khi chạy thất bại:
>>> subprocess.run("exit 1", shell=True, check=True)
Traceback (most recent call last):
...
subprocess.CalledProcessError: Command 'exit 1' returned non-zero exit status 1
Đầu ra chụp:
>>> subprocess.run(["ls", "-l", "/dev/null"], stdout=subprocess.PIPE)
CompletedProcess(args=['ls', '-l', '/dev/null'], returncode=0,
stdout=b'crw-rw-rw- 1 root root 1, 3 Jan 23 16:23 /dev/null\n')
Tôi khuyên bạn nên thử Envoy . Đó là một trình bao bọc cho quy trình con, lần lượt nhằm mục đích thay thế các mô-đun và chức năng cũ hơn. Đặc phái viên là quy trình con người.
Ví dụ sử dụng từ README :
>>> r = envoy.run('git config', data='data to pipe in', timeout=2)
>>> r.status_code
129
>>> r.std_out
'usage: git config [options]'
>>> r.std_err
''
Công cụ ống xung quanh quá:
>>> r = envoy.run('uptime | pbcopy')
>>> r.command
'pbcopy'
>>> r.status_code
0
>>> r.history
[<Response 'uptime'>]
os.system
là OK, nhưng loại ngày. Nó cũng không an toàn lắm. Thay vào đó, hãy thử subprocess
. subprocess
không gọi sh trực tiếp và do đó an toàn hơn os.system
.
Nhận thêm thông tin ở đây .
subprocess
không loại bỏ tất cả các vấn đề bảo mật và có một số vấn đề rắc rối của riêng nó.
Gọi một lệnh bên ngoài trong Python
Đơn giản, sử dụng subprocess.run
, trả về một CompletedProcess
đối tượng:
>>> import subprocess
>>> completed_process = subprocess.run('python --version')
Python 3.6.1 :: Anaconda 4.4.0 (64-bit)
>>> completed_process
CompletedProcess(args='python --version', returncode=0)
Kể từ Python 3.5, tài liệu khuyến nghị sub process.run :
Cách tiếp cận được đề xuất để gọi các quy trình con là sử dụng hàm run () cho tất cả các trường hợp sử dụng mà nó có thể xử lý. Đối với các trường hợp sử dụng nâng cao hơn, giao diện Popen nằm bên dưới có thể được sử dụng trực tiếp.
Đây là một ví dụ về cách sử dụng đơn giản nhất có thể - và nó thực hiện chính xác như đã hỏi:
>>> import subprocess
>>> completed_process = subprocess.run('python --version')
Python 3.6.1 :: Anaconda 4.4.0 (64-bit)
>>> completed_process
CompletedProcess(args='python --version', returncode=0)
run
Chờ lệnh kết thúc thành công, sau đó trả về một CompletedProcess
đối tượng. Thay vào đó, nó có thể tăng TimeoutExpired
(nếu bạn đưa ra một timeout=
đối số) hoặc CalledProcessError
(nếu thất bại và bạn vượt qua check=True
).
Như bạn có thể suy ra từ ví dụ trên, stdout và stderr đều được dẫn đến thiết bị xuất chuẩn và stderr của riêng bạn theo mặc định.
Chúng ta có thể kiểm tra đối tượng trả về và xem lệnh đã được đưa ra và mã trả về:
>>> completed_process.args
'python --version'
>>> completed_process.returncode
0
Nếu bạn muốn chụp đầu ra, bạn có thể chuyển subprocess.PIPE
đến phần thích hợp stderr
hoặc stdout
:
>>> cp = subprocess.run('python --version',
stderr=subprocess.PIPE,
stdout=subprocess.PIPE)
>>> cp.stderr
b'Python 3.6.1 :: Anaconda 4.4.0 (64-bit)\r\n'
>>> cp.stdout
b''
(Tôi thấy thú vị và hơi phản cảm khi thông tin phiên bản được đưa vào thiết bị xuất chuẩn thay vì thiết bị xuất chuẩn.)
Người ta có thể dễ dàng chuyển từ cung cấp một chuỗi lệnh thủ công (như câu hỏi gợi ý) sang cung cấp một chuỗi được xây dựng theo chương trình. Đừng xây dựng chuỗi theo lập trình. Đây là một vấn đề bảo mật tiềm năng. Tốt hơn là giả sử bạn không tin tưởng đầu vào.
>>> import textwrap
>>> args = ['python', textwrap.__file__]
>>> cp = subprocess.run(args, stdout=subprocess.PIPE)
>>> cp.stdout
b'Hello there.\r\n This is indented.\r\n'
Lưu ý, chỉ args
nên được thông qua vị trí.
Đây là chữ ký thực trong nguồn và như được hiển thị bởi help(run)
:
def run(*popenargs, input=None, timeout=None, check=False, **kwargs):
Các popenargs
và kwargs
được trao cho các Popen
nhà xây dựng. input
có thể là một chuỗi byte (hoặc unicode, nếu chỉ định mã hóa hoặc universal_newlines=True
) sẽ được dẫn đến stdin của quy trình con.
Các tài liệu mô tả timeout=
và check=True
tốt hơn tôi có thể:
Đối số hết thời gian được chuyển đến Popen.c truyền thông (). Nếu hết thời gian, quá trình con sẽ bị giết và chờ đợi. Ngoại lệ TimeoutExpired sẽ được nêu lại sau khi quá trình con kết thúc.
Nếu kiểm tra là đúng và quá trình thoát với mã thoát khác không, ngoại lệ CalledProcessError sẽ được đưa ra. Các thuộc tính của ngoại lệ đó chứa các đối số, mã thoát và thiết bị xuất chuẩn và thiết bị xuất chuẩn nếu chúng bị bắt.
và ví dụ check=True
này tốt hơn một ví dụ tôi có thể nghĩ ra:
>>> subprocess.run("exit 1", shell=True, check=True) Traceback (most recent call last): ... subprocess.CalledProcessError: Command 'exit 1' returned non-zero exit status 1
Đây là một chữ ký mở rộng, như được đưa ra trong tài liệu:
subprocess.run(args, *, stdin=None, input=None, stdout=None, stderr=None, shell=False, cwd=None, timeout=None, check=False, encoding=None, errors=None)
Lưu ý rằng điều này chỉ ra rằng chỉ có danh sách args được thông qua vị trí. Vì vậy, vượt qua các đối số còn lại là đối số từ khóa.
Khi sử dụng Popen
thay thế? Tôi sẽ đấu tranh để tìm trường hợp sử dụng chỉ dựa trên các đối số. Popen
Tuy nhiên, việc sử dụng trực tiếp sẽ cung cấp cho bạn quyền truy cập vào các phương thức của nó, bao gồm poll
, 'send_signal', 'chấm dứt' và 'chờ đợi'.
Đây là Popen
chữ ký như được đưa ra trong nguồn . Tôi nghĩ rằng đây là sự đóng gói chính xác nhất của thông tin (trái ngược với help(Popen)
):
def __init__(self, args, bufsize=-1, executable=None,
stdin=None, stdout=None, stderr=None,
preexec_fn=None, close_fds=_PLATFORM_DEFAULT_CLOSE_FDS,
shell=False, cwd=None, env=None, universal_newlines=False,
startupinfo=None, creationflags=0,
restore_signals=True, start_new_session=False,
pass_fds=(), *, encoding=None, errors=None):
Nhưng nhiều thông tin hơn là các Popen
tài liệu :
subprocess.Popen(args, bufsize=-1, executable=None, stdin=None, stdout=None, stderr=None, preexec_fn=None, close_fds=True, shell=False, cwd=None, env=None, universal_newlines=False, startupinfo=None, creationflags=0, restore_signals=True, start_new_session=False, pass_fds=(), *, encoding=None, errors=None)
Thực hiện một chương trình con trong một quy trình mới. Trên POSIX, lớp sử dụng hành vi giống như os.execvp () để thực thi chương trình con. Trên Windows, lớp sử dụng hàm Windows CreatProcess (). Các đối số cho Popen như sau.
Hiểu các tài liệu còn lại trên Popen
sẽ được để lại như một bài tập cho người đọc.
shell=True
hoặc (tốt hơn nữa) truyền lệnh dưới dạng danh sách.
Ngoài ra còn có Plumbum
>>> from plumbum import local
>>> ls = local["ls"]
>>> ls
LocalCommand(<LocalPath /bin/ls>)
>>> ls()
u'build.py\ndist\ndocs\nLICENSE\nplumbum\nREADME.rst\nsetup.py\ntests\ntodo.txt\n'
>>> notepad = local["c:\\windows\\notepad.exe"]
>>> notepad() # Notepad window pops up
u'' # Notepad window is closed by user, command returns
Sử dụng:
import os
cmd = 'ls -al'
os.system(cmd)
os - Mô-đun này cung cấp một cách di động sử dụng chức năng phụ thuộc hệ điều hành.
Đối với các os
chức năng nhiều hơn , đây là tài liệu.
Nó có thể đơn giản như sau:
import os
cmd = "your command"
os.system(cmd)
Tôi khá thích shell_command vì sự đơn giản của nó. Nó được xây dựng trên đỉnh của mô-đun quy trình con.
Đây là một ví dụ từ tài liệu:
>>> from shell_command import shell_call
>>> shell_call("ls *.py")
setup.py shell_command.py test_shell_command.py
0
>>> shell_call("ls -l *.py")
-rw-r--r-- 1 ncoghlan ncoghlan 391 2011-12-11 12:07 setup.py
-rw-r--r-- 1 ncoghlan ncoghlan 7855 2011-12-11 16:16 shell_command.py
-rwxr-xr-x 1 ncoghlan ncoghlan 8463 2011-12-11 16:17 test_shell_command.py
0
Có một sự khác biệt ở đây mà không được đề cập trước đây.
subprocess.Popen
thực thi <lệnh> dưới dạng một quy trình con. Trong trường hợp của tôi, tôi cần thực thi tệp <a> cần liên lạc với chương trình khác, <b>.
Tôi đã thử quá trình con, và thực hiện đã thành công. Tuy nhiên, <b> không thể giao tiếp với <a>. Mọi thứ đều bình thường khi tôi chạy cả hai từ thiết bị đầu cuối.
Thêm một điều nữa: (LƯU Ý: kwrite hoạt động khác với các ứng dụng khác. Nếu bạn thử cách bên dưới với Firefox, kết quả sẽ không giống nhau.)
Nếu bạn cố gắng os.system("kwrite")
, chương trình sẽ đóng băng cho đến khi người dùng đóng kwrite. Để khắc phục điều đó tôi đã cố gắng thay thế os.system(konsole -e kwrite)
. Chương trình thời gian này tiếp tục chảy, nhưng kwrite đã trở thành quy trình con của giao diện điều khiển.
Bất cứ ai cũng chạy kwrite không phải là một quy trình con (tức là trong màn hình hệ thống, nó phải xuất hiện ở cạnh ngoài cùng bên trái của cây).
os.system
không cho phép bạn lưu trữ kết quả, vì vậy nếu bạn muốn lưu trữ kết quả trong một số danh sách hoặc một cái gì đó, một subprocess.call
tác phẩm.
Tôi có xu hướng sử dụng quy trình con cùng với shlex (để xử lý thoát chuỗi được trích dẫn):
>>> import subprocess, shlex
>>> command = 'ls -l "/your/path/with spaces/"'
>>> call_params = shlex.split(command)
>>> print call_params
["ls", "-l", "/your/path/with spaces/"]
>>> subprocess.call(call_params)
Không biết xấu hổ, tôi đã viết một thư viện cho việc này: P https://github.com/houqp/shell.py
Về cơ bản, đây là một trình bao bọc cho popen và shlex. Nó cũng hỗ trợ các lệnh đường ống để bạn có thể xâu chuỗi các lệnh dễ dàng hơn trong Python. Vì vậy, bạn có thể làm những việc như:
ex('echo hello shell.py') | "awk '{print $2}'"
Trong Windows, bạn chỉ có thể nhập các subprocess
mô-đun và chạy các lệnh bên ngoài bằng cách gọi subprocess.Popen()
, subprocess.Popen().communicate()
và subprocess.Popen().wait()
như dưới đây:
# Python script to run a command line
import subprocess
def execute(cmd):
"""
Purpose : To execute a command and return exit status
Argument : cmd - command to execute
Return : exit_code
"""
process = subprocess.Popen(cmd, shell=True, stdout=subprocess.PIPE, stderr=subprocess.PIPE)
(result, error) = process.communicate()
rc = process.wait()
if rc != 0:
print "Error: failed to execute command:", cmd
print error
return result
# def
command = "tasklist | grep python"
print "This process detail: \n", execute(command)
Đầu ra:
This process detail:
python.exe 604 RDP-Tcp#0 4 5,660 K
Trong Linux, trong trường hợp bạn muốn gọi một lệnh bên ngoài sẽ thực thi độc lập (sẽ tiếp tục chạy sau khi tập lệnh python chấm dứt), bạn có thể sử dụng một hàng đợi đơn giản làm bộ đệm nhiệm vụ hoặc lệnh at
Một ví dụ với bộ đệm nhiệm vụ:
import os
os.system('ts <your-command>')
Ghi chú về bộ đệm tác vụ ( ts
):
Bạn có thể đặt số lượng quy trình đồng thời được chạy ("vị trí") với:
ts -S <number-of-slots>
Cài đặt ts
không yêu cầu quyền quản trị. Bạn có thể tải xuống và biên dịch nó từ nguồn đơn giản make
, thêm nó vào đường dẫn của bạn và bạn đã hoàn thành.
ts
không phải là tiêu chuẩn cho bất kỳ bản phân phối nào tôi biết, mặc dù con trỏ đến at
rất hữu ích. Có lẽ bạn cũng nên đề cập đến batch
. Như những nơi khác, os.system()
khuyến nghị có lẽ ít nhất nên đề cập đó subprocess
là sự thay thế được đề nghị.
Bạn có thể sử dụng Popen và sau đó bạn có thể kiểm tra trạng thái của quy trình:
from subprocess import Popen
proc = Popen(['ls', '-l'])
if proc.poll() is None:
proc.kill()
Kiểm tra quy trình con.Popen .
Để tìm nạp id mạng từ neutron OpenStack :
#!/usr/bin/python
import os
netid = "nova net-list | awk '/ External / { print $2 }'"
temp = os.popen(netid).read() /* Here temp also contains new line (\n) */
networkId = temp.rstrip()
print(networkId)
Đầu ra của nova net-list
+--------------------------------------+------------+------+
| ID | Label | CIDR |
+--------------------------------------+------------+------+
| 431c9014-5b5d-4b51-a357-66020ffbb123 | test1 | None |
| 27a74fcd-37c0-4789-9414-9531b7e3f126 | External | None |
| 5a2712e9-70dc-4b0e-9281-17e02f4684c9 | management | None |
| 7aa697f5-0e60-4c15-b4cc-9cb659698512 | Internal | None |
+--------------------------------------+------------+------+
Đầu ra của bản in (networkId)
27a74fcd-37c0-4789-9414-9531b7e3f126
os.popen()
vào năm 2016. Tập lệnh Awk có thể dễ dàng được thay thế bằng mã Python gốc.
echo $PATH
bằng cách sử dụngcall(["echo", "$PATH"])
, nhưng nó chỉ lặp lại chuỗi ký tự$PATH
thay vì thực hiện bất kỳ thay thế nào. Tôi biết tôi có thể nhận được biến môi trường PATH, nhưng tôi tự hỏi liệu có cách nào dễ dàng để lệnh hoạt động chính xác như thể tôi đã thực hiện nó trong bash không.