2011-08-16 35 views
9

Tôi đang sử dụng Perl 5.10.1 trên Ubuntu 11.04. Tôi muốn Perl thực thi một kịch bản lệnh shell và thoát với cùng một mã mà shell script thoát ra. Nhưng điều này không làm việc cho tôi ...Nhận Perl để trả lại mã thoát chính xác

system($runCmd) or die("Failed to run \"$runCmd\": $!"); 

Tôi đã xác nhận rằng chạy "$ runCmd" của chính nó trả về một mã lối ra của 255, nhưng mệnh đề "chết" là không nhận được viện dẫn. Làm cách nào để thoát với mã chính xác hoặc ít nhất là không thành công cho các mã không thành công?

Một yêu cầu nhỏ khác là tôi muốn đầu ra từ $ runCmd được in ra màn hình.

Trả lời

8

perldoc -f die nói, die không cung cấp mã thoát cụ thể (chỉ có mã thoát không phải là mã). Để có được những gì bạn muốn, bạn sẽ cần một cái gì đó như:

my $exit_code=system($runCmd); 

if($exit_code!=0) 
{ 
    print "Command $runCmd failed with an exit code of $exit_code.\n"; 
    exit($exit_code >> 8); 
} 
else 
{ 
    print "Command $runCmd successful!\n"; 
} 
+8

Bạn cần: 'exit ($ exit_code >> 8)'. – ErikR

+0

Tại sao điều đó lại chính xác? –

+3

Giá trị trả về từ 'system()' là một số nguyên mã hóa giá trị thoát của tiến trình con cộng với cờ cho biết quá trình con đã thoát (kết thúc bình thường, bị giết bởi tín hiệu, v.v.) Giá trị được chuyển đến 'thoát () 'chỉ là giá trị thoát. – ErikR

6

Nếu system trả về 255, bạn cần có điều kiện là and.

system trả về số không trên thực hiện thành công. Ngoài ra, die sẽ sửa đổi mã thoát của tập lệnh của bạn. Thay vào đó warn và trả về mã xuất cuối cùng như thế này:

system($cmd) and do { 
    warn "Failed to run $cmd. Exit code is $?"; 
    exit $? >> 8; 
}; 

Để bắt đầu ra của chương trình, sử dụng backtick (`) điều hành:

my $output = `$cmd`; 

if ($?) { 
    warn ...; 
    exit $? >> 8; 
} 

Nhà điều hành backtick chỉ chụp STDOUT, vì vậy cho tất cả các thông báo lỗi (thường đi tới STDERR) để được chụp, sửa đổi $cmd và nối thêm 2>&1 vào nó.

Thông báo sự dịch chuyển trái bằng tám bit trên toàn cầu $?.


Tín đi đến @musiKk: Các perl documentation on system() bang làm thế nào để lấy lại đúng trạng thái thoát thực tế.

+3

Chỉ cần thêm: Bạn phải chuyển giá trị trả về của 'hệ thống' sang số 8 sang phải để trả về giá trị trả về' $ cmd'. (http://perldoc.perl.org/functions/system.html) – musiKk

+0

Cảm ơn, @musiKk. Tôi đã cập nhật câu trả lời của mình cho phù hợp. –

4
system($runCmd) or die("Failed to run \"$runCmd\": $!"); 

Không giống như hầu hết các chức năng Perl, system lợi nhuận sai khi nó thành công và đúng khi nó không thành công. Điều này hoàn toàn ngược lại tôi biết nhưng nó chỉ là nó như thế nào.

Bạn cần "system() và" not "system() hoặc". Và bạn có thể muốn $? không $!, mặc dù điều này đôi khi có thể khó khăn.

Tôi có một ác cảm nhỏ để

system(...)       && die 

vì nó vít lên tất cả phần còn lại của || die 's thường tạo ra một lợi nhuận tăng gấp đôi dọc liên tục trên bên phải, đôi khi tôi viết

system(...) == 0      || die 

sao cho tất cả đều được xếp lại chính xác.

0

Nếu hệ thống() 's lạc hậu dường như làm phiền bạn, bạn luôn có thể làm cho nó dễ chịu hơn bằng cách làm một cái gì đó như:

my $err = system '/something/that/may/not/work'; 
if ($err) { 
    warn "@{[$! || 'undefined error']}\n"; 
    exit $err >> 8; 
} 

của bạn $ runCmd, BTW, nếu nó in ra màn hình (và đây là chạy từ dòng lệnh và bạn chưa chuyển hướng đầu ra, v.v.) sẽ in ra màn hình. Chỉ là CNTT sẽ in nó lên màn hình. Perl sẽ không chịu trách nhiệm về điều đó hoặc biết (hoặc quan tâm) những gì nó đang in. Nếu đó là tất cả những gì bạn muốn, và bạn không muốn phân tích hoặc điều khiển một cách có hệ thống đầu ra của $ runCmd, bạn là vàng. Hãy dùng thử:

perl -e "system 'ls -Fahl'" 

Nó cũng sẽ không ảnh hưởng tới STDOUT của $ runCmd của bạn. Điều đó sẽ đi đến thiết bị đầu cuối của bạn quá. Ví dụ:

$ perl -e "system 'ls -Fahl /dev/null/something' and die qq(fail: $! >> 8 == @{[$! >> 8]})" 
ls: /dev/null/something: Not a directory 
fail: 26205 >> 8 == 102 at -e line 1. 
Các vấn đề liên quan