Gọi một lệnh bên ngoài từ Python


4886

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:


4696

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 subprocessvs. systemlà nó là linh hoạt hơn (bạn có thể nhận được stdout, stderrthì "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 subprocessmô-đun thay thế os.system():

Các subprocessmô-đ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 subprocesstà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"])

Có cách nào để sử dụng thay thế biến? IE tôi đã cố gắng thực hiện echo $PATHbằng cách sử dụng call(["echo", "$PATH"]), nhưng nó chỉ lặp lại chuỗi ký tự $PATHthay 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.
Kevin Wheeler

@KevinWheeler Bạn sẽ phải sử dụng shell=Trueđể làm việc đó.
SethMMorton

39
@KevinWheeler Bạn KHÔNG nên sử dụng 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
Murmel

không gọi khối? tức là nếu tôi muốn chạy nhiều lệnh trong một forvò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.
Charlie Parker

4
Nếu bạn muốn tạo một danh sách từ một lệnh với các tham số , một danh sách có thể được sử dụng subprocesskhi nào shell=False, sau đó sử dụng shlex.splitmột cách dễ dàng để thực hiện điều này docs.python.org/2/l Library / shlex.html
Daniel F

2985

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:

  1. 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 .

  1. stream = os.popen("some_command with args")sẽ làm điều tương tự như os.systemngoạ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 .

  2. Các Popenlớp của subprocessmô-đun. Điều này được dự định như là một sự thay thế cho os.popennhư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 .

  3. Các callchức năng từ các subprocessmô-đun. Điều này về cơ bản giống như Popenlớ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 .

  4. Nếu bạn đang dùng Python 3.5 trở lên, bạn có thể sử dụng subprocess.runhà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.

  5. 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 subprocessmô-đ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.


22
Câu trả lời / giải thích tốt đẹp. Làm thế nào là câu trả lời này biện minh cho phương châm của Python như được mô tả trong bài viết này? fastcompany.com/3026446/ hy "Về mặt phong cách, Perl và Python có những triết lý khác nhau. Phương châm nổi tiếng nhất của Perl là" Có nhiều cách để làm điều đó ". Python được thiết kế để có một cách rõ ràng để làm điều đó" Có vẻ như nó phải như vậy Cách khác! Trong Perl tôi chỉ biết hai cách để thực thi lệnh - sử dụng back-tick hoặc open.
Jean

12
Nếu sử dụng Python 3.5+, hãy sử dụng subprocess.run(). docs.python.org/3.5/l Library / sub process.html
phoenix

4
Những gì người ta thường cần biết là những gì được thực hiện với STDOUT và STDERR của tiến trình con, bởi vì nếu chúng bị bỏ qua, trong một số điều kiện (khá phổ biến), cuối cùng tiến trình con sẽ đưa ra một lệnh gọi hệ thống để ghi vào STDOUT (STDERR nữa?) sẽ vượt quá bộ đệm đầu ra được cung cấp cho quy trình bởi HĐH và HĐH sẽ khiến nó bị chặn cho đến khi một số tiến trình đọc từ bộ đệm đó. Vì vậy, với các cách hiện được đề xuất, 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?
Evgeni Sergeev

2
@Pitto có, nhưng đó không phải là những gì được thực hiện bằng ví dụ. Chú ý echophí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 /.
Chris Arndt

6
Điều này được cho là sai cách xung quanh. Hầu hết mọi người chỉ cần 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".
tripleee

358

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 stdoutdữ liệu trong đường ống. Trong thực tế, bạn có thể chỉ cần bỏ qua các tham số đó ( stdout=stderr=) và nó sẽ hoạt động như thế nào os.system().


44
.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,
jfs

1
Bạn có thể giải thích ý của bạn về "nếu không có vấn đề về bộ đệm" không? Nếu khối quy trình chắc chắn, cuộc gọi quy trình con cũng chặn. Điều tương tự cũng có thể xảy ra với ví dụ ban đầu của tôi. Điều gì khác có thể xảy ra đối với bộ đệm?
EmmEff

15
tiến trình con có thể sử dụng bộ đệm khối trong chế độ không tương tác thay vì đệm dòng vì vậy 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)
JFS

4
vấn đề đệm chỉ quan trọng nếu bạn muốn đầu ra trong thời gian thực và không áp dụng cho mã của bạn mà không in bất cứ điều gì cho đến khi tất cả dữ liệu được nhận
jfs

3
Câu trả lời này đã ổn cho thời gian của nó, nhưng chúng ta không nên đề xuất Popencho 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.
tripleee

230

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ỏ.


tôi nhận thấy một "sự giải quyết" có thể xảy ra với việc phát triển các ứng dụng py2exe trong pydev + nhật thực. tôi đã có thể nói rằng kịch bản chính không bị tách ra vì cửa sổ đầu ra của nhật thực không kết thúc; ngay cả khi tập lệnh thực thi để hoàn thành, nó vẫn đang chờ trả về. nhưng, khi tôi cố gắng biên dịch thành một tệp thực thi py2exe, hành vi dự kiến ​​sẽ xảy ra (chạy các quy trình như tách ra, sau đó thoát). tôi không chắc chắn, nhưng tên thực thi không còn trong danh sách quy trình nữa. cách này hiệu quả cho tất cả các cách tiếp cận (os.system ("start *"), os.spawnl với os.P_DETACH, các chương trình con, v.v.)
marana

1
bạn cũng có thể cần cờ CREATE_NEW_PROCESS_GROUP. Xem Popen chờ quá trình con ngay cả khi đứa trẻ ngay lập tức chấm dứt
jfs

5
Sau đây là không chính xác: "[o] n windows (win xp), quá trình cha mẹ sẽ không kết thúc cho đến khi longtask.py hoàn thành công việc của nó". Cha mẹ sẽ thoát bình thường, nhưng cửa sổ bàn điều khiển (ví dụ conhost.exe) chỉ đóng khi quá trình đính kèm cuối cùng thoát ra và đứa trẻ có thể đã thừa hưởng bàn điều khiển của cha mẹ. Thiết DETACHED_PROCESStrong creationflagstrá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).
Eryk CN

1
Tôi không có nghĩa là thực hiện như một quá trình tách rời là không chính xác. Điều đó nói rằng, bạn có thể cần phải đặt tay cầm tiêu chuẩn thành tệp, đường ống hoặc os.devnulldo 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ổ.
Eryk CN

1
không có cách nào để biết quá trình chạy hệ điều hành trong nền?
Charlie Parker

152
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ự.


6
Không biết tôi có ý gì gần một thập kỷ trước (kiểm tra ngày!), Nhưng nếu tôi phải đoán, thì sẽ không có xác nhận nào được thực hiện.
nhanh nhẹn

1
Điều này bây giờ sẽ chỉ ra subprocessnhư 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.
tripleee

1
Lưu ý dấu thời gian của anh chàng này: câu trả lời "đúng" có 40 lần số phiếu và là câu trả lời số 1.
nhanh nhẹn

Một giải pháp hiệu quả với tôi khi chạy công cụ NodeJS.
Nikolay Shindarov

148

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'])

Nếu bạn muốn tạo một danh sách từ một lệnh với các tham số , một danh sách có thể được sử dụng subprocesskhi nào shell=False, sau đó sử dụng shlex.splitmộ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 )
Daniel F

6
Điều này là không chính xác: " nó thoát vỏ cho bạn và do đó an toàn hơn nhiều ". quy trình con không thực hiện thoát shell, quy trình con không truyền lệnh của bạn qua shell, do đó không cần thoát shell.
Lie Ryan

144
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.


10
popen không được ủng hộ trong quá trình con .
Fox Wilson

Bạn cũng có thể lưu kết quả của mình bằng lệnh gọi os.system, vì nó hoạt động giống như vỏ UNIX, ví dụ như os.system ('ls -l> test2.txt')
Stefan Gruenwald

97

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.systemos.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 subprocessmô-đun.

r = envoy.run("ls -l") # Run command
r.std_out # get output

lệnh

commandschứa các hàm bao bọc cho os.popen, nhưng nó đã bị xóa khỏi Python 3 vì đây subprocesslà 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.


74

Tôi luôn luôn sử dụng fabriccho 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)

73

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

70

Với thư viện chuẩn

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, callvà khác subprocesschứ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'))

Với sự phụ thuộc bên ngoài

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à subprocessgó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.


69

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


1
Lưu ý rằng check_outputyê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()).
Bruno Bronosky

56

Đâ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()

3
Tôi nghĩ nó có thể chấp nhận được đối với các lệnh được mã hóa cứng, nếu nó tăng khả năng đọc.
Adam Matan

54

Cập nhật:

subprocess.runlà 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')

Câu trả lời gốc:

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'>]


36

os.systemlà OK, nhưng loại ngày. Nó cũng không an toàn lắm. Thay vào đó, hãy thử subprocess. subprocesskhô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 .


2
Mặc dù tôi đồng ý với khuyến nghị chung, subprocesskhô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ó.
tripleee

36

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)

Tại sao?

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)

runChờ 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

Đầu ra

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 stderrhoặ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.)

Vượt qua một danh sách lệnh

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ỉ argsnên được thông qua vị trí.

Chữ ký đầy đủ

Đâ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 popenargskwargsđược trao cho các Popennhà xây dựng. inputcó 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=check=Truetố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=Truenà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

Chữ ký mở rộng

Đâ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.

Popen

Khi sử dụng Popenthay thế? Tôi sẽ đấu tranh để tìm trường hợp sử dụng chỉ dựa trên các đối số. PopenTuy 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à Popenchữ 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 Popentà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 Popensẽ được để lại như một bài tập cho người đọc.


Một ví dụ đơn giản về giao tiếp hai chiều giữa một quy trình chính và một quy trình con có thể được tìm thấy ở đây: stackoverflow.com/a/52841475/1349673
James Hirschorn

Ví dụ đầu tiên có lẽ nên có shell=Truehoặc (tốt hơn nữa) truyền lệnh dưới dạng danh sách.
ba

33

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

28

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 oschức năng nhiều hơn , đây là tài liệu.


2
nó cũng không được dùng nữa sử dụng quy trình con
Corey Goldberg

28

Nó có thể đơn giản như sau:

import os
cmd = "your command"
os.system(cmd)

1
Điều này không chỉ ra nhược điểm, được giải thích chi tiết hơn nhiều trong PEP-324 . Các tài liệu cho os.systemrõ ràng đề nghị tránh nó có lợi cho subprocess.
tripleee

25

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

24

Có một sự khác biệt ở đây mà không được đề cập trước đây.

subprocess.Popenthự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).


1
Ý bạn là gì khi "Bất cứ ai chạy kwrite không phải là một quy trình con" ?
Peter Mortensen

23

os.systemkhô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.calltác phẩm.


22

subprocess.check_callthuận tiện nếu bạn không muốn kiểm tra giá trị trả về. Nó ném một ngoại lệ trên bất kỳ lỗi nào.


22

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)

17

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}'"

16

Trong Windows, bạn chỉ có thể nhập các subprocessmô-đun và chạy các lệnh bên ngoài bằng cách gọi subprocess.Popen(), subprocess.Popen().communicate()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

15

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

  1. 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>

  2. Cài đặt tskhô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.


1
tskhô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 atrấ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 đó subprocesslà sự thay thế được đề nghị.
tripleee

15

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 .


15

Để 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

Bạn không nên đề xuất 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.
tripleee
Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.