2010-11-19 30 views
8

Tôi đang sử dụng cuộc gọi hệ thống để thực hiện một số tác vụShell nào sử dụng hệ thống Perl()?

system('myframework mycode'); 

nhưng nó vẫn thiếu các biến môi trường bị thiếu. Các biến môi trường này được đặt tại bash shell của tôi (từ nơi tôi chạy mã Perl).

Tôi đang làm gì sai?

Cuộc gọi system có tạo một vỏ hoàn toàn mới (không có cài đặt biến môi trường) không? Làm thế nào tôi có thể tránh điều đó?

Trả lời

17

Thật phức tạp. Perl không nhất thiết phải gọi một trình bao. Perldoc nói:

Nếu chỉ có một đối số vô hướng, lập luận được kiểm tra cho metacharacters vỏ, và nếu có bất kỳ, toàn bộ đối số được truyền đến lệnh shell của hệ thống để phân tích cú pháp (đây là/bin/sh -c trên nền tảng Unix, nhưng khác nhau trên các nền tảng khác). Nếu không có siêu ký tự shell trong đối số, nó được chia thành các từ và được truyền trực tiếp đến execvp, điều này hiệu quả hơn.

Vì vậy, nó thực sự trông giống như bạn sẽ có các đối số được chuyển ngay đến execvp. Hơn nữa, cho dù trình bao nạp tệp .bashrc, .profile hoặc .bash_profile của bạn phụ thuộc vào việc trình bao có tương tác hay không. Có khả năng là không, nhưng bạn có thể kiểm tra như this.

3

hệ thống() cuộc gọi/bin/sh làm vỏ. Nếu bạn đang ở trên một hộp hơi khác nhau như ARM nó sẽ là tốt để đọc trang người đàn ông cho gia đình exec của cuộc gọi - hành vi mặc định. Bạn có thể gọi .profile của bạn nếu bạn cần, vì hệ thống() có một lệnh

system(" . myhome/me/.profile && /path/to/mycommand") 
0

thử system("echo \$SHELL"); trên hệ thống của bạn.

+1

Điều này là sai. Cuộc gọi 'system' KHÔNG tôn trọng $ SHELL theo bất kỳ cách nào, hình dạng hoặc hình thức nào. Xem câu trả lời của Matt Kane – DVK

3

Nếu bạn không muốn gọi một vỏ, gọi system với một danh sách:

system 'mycommand', 'arg1', '...'; 
system qw{mycommand arg1 ...}; 

Nếu bạn muốn có một vỏ đặc biệt, gọi nó một cách rõ ràng:

system "/path/to/mysh -c 'mycommand arg1 ...'"; 
4

Tôi nghĩ rằng nó không phải câu hỏi về sự lựa chọn vỏ, vì biến môi trường là luôn luôn được thừa kế bởi các quy trình con trừ khi được dọn sạch một cách rõ ràng. Bạn có chắc chắn đã xuất các biến của mình không? này sẽ làm việc:

$ A=5 perl -e 'system(q{echo $A});' 
5 
$ 

này sẽ làm việc quá:

$ export A=5 
$ perl -e 'system(q{echo $A});' 
5 
$ 

này sẽ không:

$ A=5 
$ perl -e 'system(q{echo $A});' 

$ 
1

Tôi sai lầm với các biến môi trường được đặt cho kịch bản của tôi về nơi tôi this post cần biến env $ DBUS_SESSION_BUS_ADDRESS để được đặt, nhưng nó sẽ không khi tôi gọi kịch bản là root. Bạn có thể đọc qua điều đó, nhưng cuối cùng bạn có thể kiểm tra xem liệu% ENV có chứa các biến cần thiết của bạn và nếu không thêm chúng.

Từ perlvar

%ENV 
    $ENV{expr} 
      The hash %ENV contains your current environment. Setting a value in "ENV" changes 
      the environment for any child processes you subsequently fork() off. 

Vấn đề của tôi là tôi đã chạy kịch bản dưới sudo và điều đó đã không giữ lại tất cả các biến env của người dùng của tôi, bạn đang chạy các kịch bản dưới sudo hoặc như một số người dùng khác, nói www-data (apache)?

đơn giản kiểm tra:

[email protected]:~$ perl -e 'print $ENV{q/MY_ENV_VARIABLE/} . "\n"' 

và nếu điều đó không làm việc thì bạn sẽ cần phải thêm nó vào% ENV ở phía trên cùng của kịch bản của bạn.

2

Tôi đã vật lộn trong 2 ngày làm việc về điều này. Trong trường hợp của tôi, các biến môi trường được đặt đúng theo linux nhưng không phải là Cygwin.

Từ mkb's trả lời Tôi nghĩ xem man perlrun và đề cập đến biến có tên là PERL5SHELL. Sau đây sau đó giải quyết vấn đề:

$ENV{PERL5SHELL} = "sh"; 

Như thường là trường hợp - tất cả tôi thực sự có thể nói là "nó hoạt động đối với tôi", mặc dù các tài liệu không ngụ ý rằng điều này có thể là một giải pháp hợp lý:

Có thể được đặt thành một trình bao thay thế mà perl phải sử dụng nội bộ để thực thi lệnh "backtick" hoặc hệ thống().

Nếu vỏ được sử dụng bởi perl không ngầm kế thừa các biến môi trường thì chúng sẽ không được đặt cho bạn.

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