2010-04-26 28 views
9
#!/usr/bin/env perl 
use warnings; use strict; 
use 5.012; 
use IPC::System::Simple qw(system); 

system('xterm', '-geometry', '80x25-5-5', '-bg', 'green', '&'); 

say "Hello"; 
say "World"; 

tôi đã cố gắng này để chạy xterm-lệnh ở chế độ nền, nhưng nó không hoạt động:Làm cách nào để chạy các lệnh hệ thống Perl trong nền?

Không có đường dẫn tuyệt đối tìm thấy cho vỏ: &

Điều gì sẽ là bên phải cách để làm cho nó hoạt động?

+0

thử nghiệm ở đây dường như sorta làm việc cho tôi. Bạn đang cố gắng để thực hiện? – xenoterracide

+0

là nó phải mở terminal và sau đó in hello world trong terminal? – xenoterracide

+0

hoặc bạn chỉ đang cố thực hiện cuộc gọi không đồng bộ để mở thiết bị đầu cuối? – xenoterracide

Trả lời

19

system chức năng của Perl có hai chế độ:

  1. tham gia một chuỗi đơn và đi qua nó để tiện ích dòng lệnh để cho phép ký tự đặc biệt để được xử lý
  2. tham gia một danh sách các chuỗi, thực hiện chuỗi đầu tiên và chuyển các chuỗi còn lại làm đối số

Trong biểu mẫu đầu tiên, bạn phải cẩn thận để thoát khỏi các ký tự có thể có ý nghĩa đặc biệt đối với trình bao. Dạng thứ hai nói chung là an toàn hơn vì các đối số được truyền trực tiếp đến chương trình đang được thực hiện mà không có trình bao được tham gia.

Trong trường hợp của bạn, bạn dường như đang trộn hai biểu mẫu. Ký tự & chỉ có nghĩa là "bắt đầu chương trình này ở chế độ nền" nếu nó được chuyển vào vỏ. Trong chương trình của bạn, dấu và được chuyển thành đối số thứ 5 cho lệnh xterm.

Như Jakob Kruse đã nói câu trả lời đơn giản là sử dụng dạng chuỗi đơn là system. Nếu bất kỳ đối số nào đến từ một nguồn không đáng tin cậy, bạn phải sử dụng trích dẫn hoặc thoát để làm cho chúng an toàn.

Nếu bạn muốn sử dụng biểu mẫu nhiều đối số, bạn cần phải gọi fork() và sau đó có thể sử dụng exec() thay vì system().

+4

** tldr; ** 'hệ thống (" ./ script.sh $ arg1 &"); 'thay vì' hệ thống ("./ script.sh", "$ arg1", "&");' – Rombus

13

Lưu ý rằng dạng danh sách system đặc biệt ở đó để không xử lý các ký tự như & làm ký tự đại diện shell.

Từ câu trả lời perlfaq8 's để How do I start a process in the background?


(đóng góp bởi brian d Foy)

Không có một cách duy nhất để chạy mã trong nền để bạn không phải chờ đợi để nó kết thúc trước khi chương trình của bạn chuyển sang các tác vụ khác. Quy trình quản lý phụ thuộc vào hệ điều hành cụ thể của bạn, và nhiều kỹ thuật trong perlipc.

Một số module CPAN có thể giúp đỡ, trong đó có IPC::Open2 hoặc IPC::Open3, IPC::Run, Parallel::Jobs, Parallel::ForkManager, POE, Proc::Background, và Win32::Process. Có nhiều mô-đun khác bạn có thể sử dụng, vì vậy hãy kiểm tra các không gian tên đó để biết các tùy chọn khác.

Nếu bạn đang ở trên một hệ thống Unix-like, bạn có thể có thể nhận được ngay với một cuộc gọi hệ thống nơi bạn đặt một & vào phần cuối của lệnh:

system("cmd &") 

Bạn cũng có thể thử sử dụng nĩa , như được mô tả trong perlfunc (mặc dù đây là điều tương tự mà nhiều mô-đun sẽ làm cho bạn).

STDIN, STDOUT, và stderr được chia sẻ

Cả hai quá trình chính và một background (những "đứa trẻ" quá trình) chia sẻ cùng một STDIN, STDOUT và stderr filehandles. Nếu cả hai cố gắng truy cập chúng cùng một lúc, những điều kỳ lạ có thể xảy ra. Bạn có thể muốn đóng hoặc mở lại những thứ này cho đứa trẻ. Bạn có thể giải quyết vấn đề này bằng cách mở một đường ống (xem mở trong perlfunc) nhưng trên một số hệ thống, điều này có nghĩa là tiến trình con không thể sống lâu hơn với cha mẹ. Tín hiệu Bạn sẽ phải nắm bắt tín hiệu SIGCHLD và có thể SIGPIPE. SIGCHLD được gửi khi quá trình nền kết thúc. SIGPIPE được gửi khi bạn viết cho một tập tin có quá trình con đã đóng (một SIGPIPE chưa được khai thác có thể khiến chương trình của bạn âm thầm chết). Đây không phải là vấn đề với hệ thống ("cmd &").

Zombies

Bạn phải chuẩn bị để "gặt hái" quá trình con khi nó kết thúc.

$SIG{CHLD} = sub { wait }; 

$SIG{CHLD} = 'IGNORE'; 

Bạn cũng có thể sử dụng một ngã ba đôi. Bạn ngay lập tức chờ() cho con đầu tiên của bạn, và daemon init sẽ chờ() cho cháu của bạn sau khi nó thoát.

unless ($pid = fork) { 
    unless (fork) { 
     exec "what you really wanna do"; 
     die "exec failed!"; 
    } 
    exit 0; 
} 
waitpid($pid, 0); 

Xem các ký hiệu khác trong perlipc để biết các ví dụ khác về mã để thực hiện việc này. Zombies không phải là vấn đề với hệ thống ("prog &").

0

Đây không hoàn toàn là giải thích cho Perl. Vấn đề tương tự ở dưới C và các ngôn ngữ khác.

Đầu tiên hiểu những gì các hệ thống lệnh nào:

  1. Forks
  2. Dưới sự kêu gọi tiến trình con exec
  3. Quá trình cha mẹ đang chờ tiến trình con chia hai để kết thúc

Không quan trọng nếu bạn vượt qua nhiều đối số hoặc một đối số. Sự khác biệt là, với nhiều đối số, lệnh được thực hiện trực tiếp.Với một đối số, lệnh được bọc bởi lớp vỏ, và cuối cùng là thực hiện như:

/bin/sh -c your_command_with_redirections_and_ambersand 

Khi bạn vượt qua một lệnh như some_command par1 par2 &, sau đó giữa người diễn giải Perl và lệnh là sh hoặc bash quá trình được sử dụng làm trình bao bọc và đang chờ kết quả là some_command. Tập lệnh của bạn đang đợi trình thông dịch trình bao và không cần thêm waitpid vì chức năng của hệ thống của Perl là sẽ làm điều đó cho bạn.

Khi bạn muốn thực hiện cơ chế này trực tiếp trong kịch bản của bạn, bạn nên:

  1. Sử dụng ngã ba chức năng. Xem ví dụ: http://users.telenet.be/bartl/classicperl/fork/all.html
  2. Trong điều kiện trẻ em (if), hãy sử dụng chức năng exec. Người dùng của bạn tương tự với hệ thống, xem hướng dẫn sử dụng. Chú ý, exec làm cho chương trình con/nội dung/dữ liệu bao trùm bởi lệnh được thực hiện.
  3. Trong điều kiện gốc (nếu, ngã ba thoát với số không khác), bạn sử dụng waitpid, sử dụng pid được trả về bởi hàm fork.

Đây là lý do tại sao bạn có thể chạy quá trình trong nền. Tôi hy vọng điều này là đơn giản.

Ví dụ đơn giản nhất:

if (my $pid = fork) { #exits 0 = false for child process, at this point is brain split 
    # parent ($pid is process id of child) 
    # Do something what you want, asynchronously with executed command 
    waitpid($pid); # Wait until child ends 
    # If you don't want to, don't wait. Your process ends, and then the child process will be relinked 
    # from your script to INIT process, and finally INIT will assume the child finishing. 
    # Alternatively, you can handle the SIGCHLD signal in your script 
} 
else { 
    # Child 
    exec('some_command arg1 arg2'); #or exec('some_command','arg1','arg2'); 
    #exit is not needed, because exec completely overwrites the process content 
} 
+0

cảm ơn bạn Peter đã sửa chữa rất tốt:) – Znik

Các vấn đề liên quan