Sự khác biệt giữa backticks, hệ thống và exec của Perl là gì?


237

Ai đó có thể vui lòng giúp tôi? Trong Perl, sự khác biệt giữa:

exec "command";

system("command");

print `command`;

Có những cách khác để chạy lệnh shell?


8
Gần như là một bản sao chính xác của stackoverflow.com/questions/797127/ , ngoại trừ cái này có exec và cái kia có ống.
Michael Myers

Câu trả lời:


268

thực hiện

thực hiện một lệnh và không bao giờ trở lại . Nó giống như một returntuyên bố trong một chức năng.

Nếu lệnh không được tìm thấy exectrả về false. Nó không bao giờ trả về true, bởi vì nếu lệnh được tìm thấy thì nó không bao giờ trả về cả. Ngoài ra còn có không có điểm trong trở lại STDOUT, STDERRhoặc trạng thái thoát của lệnh. Bạn có thể tìm tài liệu về nó trong perlfunc, bởi vì nó là một chức năng.

hệ thống

thực thi một lệnh và tập lệnh Perl của bạn được tiếp tục sau khi lệnh kết thúc.

Giá trị trả về là trạng thái thoát của lệnh. Bạn có thể tìm tài liệu về nó trong perlfunc.

backticks

như systemthực thi một lệnh và tập lệnh perl của bạn được tiếp tục sau khi lệnh kết thúc.

Ngược lại với systemgiá trị trả về là STDOUTcủa lệnh. qx//tương đương với backticks. Bạn có thể tìm tài liệu về nó trong perlop, bởi vì không giống như systemexecnó là một toán tử.


Những cách khác

Những gì còn thiếu ở trên là một cách để thực thi lệnh không đồng bộ. Điều đó có nghĩa là tập lệnh perl của bạn và lệnh của bạn chạy đồng thời. Điều này có thể được thực hiện với open. Nó cho phép bạn đọc STDOUT/ STDERRvà ghi vào STDINlệnh của bạn. Nó phụ thuộc vào nền tảng.

Ngoài ra còn có một số mô-đun có thể dễ dàng thực hiện nhiệm vụ này. Có IPC::Open2IPC::Open3IPC::Run, cũng như Win32::Process::Createnếu bạn đang ở trên cửa sổ.


1
Tôi nghĩ bạn có nghĩa là s / perlcunc / perlfunc / ... cũng là tài liệu perlipc đi sâu về việc mở ống.
ephemient

7
perlcunc, có lẽ đây sẽ là tên nick mới của tôi ;-)
Ludwig Weinzierl

8
Đối với bản ghi, backticks và qx [] cũng cư trú $? (giá trị trả về của hệ điều hành).
jjohn

167

Trong tôi sử dụng chung system, open, IPC::Open2, hoặc IPC::Open3tùy thuộc vào những gì tôi muốn làm. Các qx//nhà điều hành, trong khi đơn giản, là quá hạn chế về tính năng của nó sẽ được bên ngoài rất hữu ích của hacks nhanh chóng. Tôi tìm openđến nhiều hơn.

system: chạy một lệnh và đợi cho nó trở lại

Sử dụng systemkhi bạn muốn chạy một lệnh, không quan tâm đến đầu ra của nó và không muốn tập lệnh Perl làm bất cứ điều gì cho đến khi lệnh kết thúc.

#doesn't spawn a shell, arguments are passed as they are
system("command", "arg1", "arg2", "arg3");

hoặc là

#spawns a shell, arguments are interpreted by the shell, use only if you
#want the shell to do globbing (e.g. *.txt) for you or you want to redirect
#output
system("command arg1 arg2 arg3");

qx//hoặc `` : chạy một lệnh và bắt STDOUT của nó

Sử dụng qx//khi bạn muốn chạy một lệnh, ghi lại những gì nó ghi vào STDOUT và không muốn tập lệnh Perl làm bất cứ điều gì cho đến khi lệnh kết thúc.

#arguments are always processed by the shell

#in list context it returns the output as a list of lines
my @lines = qx/command arg1 arg2 arg3/;

#in scalar context it returns the output as one string
my $output = qx/command arg1 arg2 arg3/;

exec: thay thế quy trình hiện tại bằng quy trình khác.

Sử dụng execcùng với forkkhi bạn muốn chạy một lệnh, không quan tâm đến đầu ra của nó và không muốn đợi nó trở lại. systemthực sự chỉ là

sub my_system {
    die "could not fork\n" unless defined(my $pid = fork);
    return waitpid $pid, 0 if $pid; #parent waits for child
    exec @_; #replace child with new process
}

Bạn cũng có thể muốn đọc waitpidperlipchướng dẫn sử dụng.

open: chạy một quy trình và tạo một đường ống đến STDIN hoặc STDERR của nó

Sử dụng openkhi bạn muốn ghi dữ liệu vào STDIN của quy trình hoặc đọc dữ liệu từ STDOUT của quy trình (nhưng không phải cả hai cùng một lúc).

#read from a gzip file as if it were a normal file
open my $read_fh, "-|", "gzip", "-d", $filename
    or die "could not open $filename: $!";

#write to a gzip compressed file as if were a normal file
open my $write_fh, "|-", "gzip", $filename
    or die "could not open $filename: $!";

IPC :: Open2 : chạy một quy trình và tạo một đường ống cho cả STDIN và STDOUT

Sử dụng IPC::Open2khi bạn cần đọc và ghi vào STDIN và STDOUT của một tiến trình.

use IPC::Open2;

open2 my $out, my $in, "/usr/bin/bc"
    or die "could not run bc";

print $in "5+6\n";

my $answer = <$out>;

IPC :: Open3 : chạy một quy trình và tạo một đường ống đến STDIN, STDOUT và STDERR

sử dụng IPC::Open3khi bạn cần nắm bắt cả ba xử lý tệp tiêu chuẩn của quy trình. Tôi sẽ viết một ví dụ, nhưng nó hoạt động chủ yếu giống như cách IPC :: Open2 thực hiện, nhưng với một thứ tự hơi khác với các đối số và xử lý tệp thứ ba.


Rất nhiều thông tin và cập nhật câu trả lời. Cảm ơn @ chas-owens
Jassi

IPC :: Open3 ở mức quá thấp cho hầu hết các mục đích sử dụng. IPC :: Run3 và IPC :: Run thường phù hợp hơn nhiều.
ikegami

17

Hãy để tôi trích dẫn các hướng dẫn đầu tiên:

thực thi perldoc () :

Hàm exec thực thi một lệnh hệ thống và không bao giờ trả về - sử dụng hệ thống thay vì exec nếu bạn muốn nó trả về

hệ thống perldoc () :

Thực hiện chính xác điều tương tự như DANH SÁCH điều hành, ngoại trừ việc một ngã ba được thực hiện trước và quy trình cha mẹ chờ quá trình con hoàn thành.

Ngược lại với execsystem , backticks không cung cấp cho bạn giá trị trả về mà là STDOUT được thu thập.

perldoc `String` :

Một chuỗi (có thể) được nội suy và sau đó được thực thi như một lệnh hệ thống với / bin / sh hoặc tương đương. Shell ký tự, đường ống và chuyển hướng sẽ được vinh danh. Đầu ra tiêu chuẩn được thu thập của lệnh được trả về ; lỗi tiêu chuẩn không bị ảnh hưởng.


Lựa chọn thay thế:

Trong các trường hợp phức tạp hơn, nơi bạn muốn tìm nạp STDOUT, STDERR hoặc mã trả về, bạn có thể sử dụng các mô-đun tiêu chuẩn nổi tiếng như IPC :: Open2IPC :: Open3 .

Thí dụ:

use IPC::Open2;
my $pid = open2(\*CHLD_OUT, \*CHLD_IN, 'some', 'cmd', 'and', 'args');
waitpid( $pid, 0 );
my $child_exit_status = $? >> 8;

Cuối cùng, IPC :: Chạy từ CPAN cũng đáng để xem


3
Đây là một phản ứng thô lỗ. Bạn nên cố gắng để có ích mà không có sự tức giận.
Shane C. Mason

1
Tôi nghĩ rằng anh ta chỉ đang tham chiếu đến ol 'RTFM: P
v3.

thực ra không có nghĩa là thô lỗ;) đã loại bỏ từ f, để tránh mọi hiểu lầm khác
Benedikt Waldvogel

2
Tôi chắc chắn đã không giải thích nó là thô lỗ. Brusque, có thể, nhưng đây không phải là một câu hỏi rất thông minh đòi hỏi một câu trả lời chu đáo.
ephemient

11

Sự khác biệt giữa backticks của Perl ( `) systemvà là execgì?

exec -> exec "command"; ,
system -> system("command"); and 
backticks -> print `command`;

exec

execthực thi một lệnh và không bao giờ nối lại tập lệnh Perl. Đó là một kịch bản như một returntuyên bố là một chức năng.

Nếu lệnh không được tìm thấy, exectrả về false. Nó không bao giờ trả về true, bởi vì nếu lệnh được tìm thấy, nó sẽ không bao giờ trả về. Ngoài ra còn có không có điểm trong trở lại STDOUT, STDERRhoặc trạng thái thoát của lệnh. Bạn có thể tìm tài liệu về nó trong perlfunc , bởi vì nó là một hàm.

Ví dụ:

#!/usr/bin/perl
print "Need to start exec command";
my $data2 = exec('ls');
print "Now END exec command";
print "Hello $data2\n\n";

Trong đoạn mã trên, có ba printcâu lệnh, nhưng do để execlại tập lệnh, chỉ có câu lệnh in đầu tiên được thực thi. Ngoài ra, execđầu ra lệnh không được gán cho bất kỳ biến nào.

Ở đây, chỉ bạn mới nhận được đầu ra của printcâu lệnh đầu tiên và thực hiện lslệnh trên tiêu chuẩn.

system

systemthực thi một lệnh và tập lệnh Perl của bạn được nối lại sau khi lệnh kết thúc. Giá trị trả về là trạng thái thoát của lệnh. Bạn có thể tìm tài liệu về nó trong perlfunc .

Ví dụ:

#!/usr/bin/perl
print "Need to start system command";
my $data2 = system('ls');
print "Now END system command";
print "Hello $data2\n\n";

Trong mã trên, có ba printtuyên bố. Khi tập lệnh được nối lại sau systemlệnh, cả ba câu lệnh in được thực thi.

Ngoài ra, kết quả của việc chạy system được gán cho data2, nhưng giá trị được gán là 0(mã thoát từ ls).

Ở đây, bạn nhận được đầu ra của printcâu lệnh đầu tiên , sau đó là câu lslệnh, tiếp theo là đầu ra của hai printcâu lệnh cuối cùng trên tiêu chuẩn.

backticks ( `)

Giống như system, việc bao quanh một lệnh trong backticks thực thi lệnh đó và tập lệnh Perl của bạn được nối lại sau khi lệnh kết thúc. Ngược lại system, giá trị trả về là STDOUTcủa lệnh. qx//tương đương với backticks. Bạn có thể tìm tài liệu về nó trong perlop , vì không giống như hệ thống và exec, nó là một toán tử.

Ví dụ:

#!/usr/bin/perl
print "Need to start backticks command";
my $data2 = `ls`;
print "Now END system command";
print "Hello $data2\n\n";

Trong đoạn mã trên, có ba printcâu lệnh và cả ba câu lệnh đang được thực thi. Đầu ra của lssẽ không được tiêu chuẩn hóa trực tiếp, nhưng được gán cho biến data2và sau đó được in bằng câu lệnh in cuối cùng.


Giải thích tốt nhất với ví dụ. Cảm ơn rất nhiều.
Arslan Anwar

2

Sự khác biệt giữa 'exec' và 'system' là exec thực hiện thay thế chương trình hiện tại của bạn bằng 'lệnh' và KHÔNG BAO GIỜ quay trở lại chương trình của bạn. mặt khác, hệ thống sẽ rẽ nhánh và chạy 'lệnh' và trả về cho bạn trạng thái thoát của 'lệnh' khi chạy xong. Dấu kiểm phía sau chạy 'lệnh' và sau đó trả về một chuỗi biểu thị tiêu chuẩn của nó (bất cứ điều gì nó sẽ được in ra màn hình)

Bạn cũng có thể sử dụng popen để chạy các lệnh shell và tôi nghĩ rằng có một mô-đun shell - 'use shell' cho phép bạn truy cập rõ ràng vào các lệnh shell điển hình.

Hy vọng rằng làm rõ nó cho bạn.


Có lẽ ý bạn là use Shell;( search.cpan.org/dist/Shell/Shell.pm )? Nó không được cài đặt rộng rãi, cũng không phải là áp dụng đối với các câu hỏi, tôi nghĩ ...
ephemient

1
Phần cuối cùng của câu hỏi của anh là "có nhiều cách khác để chạy các lệnh shell nữa không - Shell là một cách khác để chạy các lệnh shell.
Shane C. Mason

2
Các tài liệu nói rõ "Gói này được bao gồm như một trường hợp hiển thị, minh họa một vài tính năng của Perl. Nó không nên được sử dụng cho các chương trình sản xuất. Mặc dù nó cung cấp một giao diện đơn giản để có được đầu ra tiêu chuẩn của các lệnh tùy ý, có thể tốt hơn cách để đạt được những gì bạn cần. "
Chas. Owens

2
Một lần nữa, nó trả lời câu hỏi của anh ấy về 'có cách nào khác không'
Shane C. Mason

Những cách xấu, không được hỗ trợ không nên được đưa ra mà không có cảnh báo rằng chúng xấu và không được hỗ trợ.
Chas. Owens
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.