目錄

名稱

IPC::Cmd - 找到並執行系統命令變得容易

用法

use IPC::Cmd qw[can_run run run_forked];

my $full_path = can_run('wget') or warn 'wget is not installed!';

### commands can be arrayrefs or strings ###
my $cmd = "$full_path -b theregister.co.uk";
my $cmd = [$full_path, '-b', 'theregister.co.uk'];

### in scalar context ###
my $buffer;
if( scalar run( command => $cmd,
                verbose => 0,
                buffer  => \$buffer,
                timeout => 20 )
) {
    print "fetched webpage successfully: $buffer\n";
}


### in list context ###
my( $success, $error_message, $full_buf, $stdout_buf, $stderr_buf ) =
        run( command => $cmd, verbose => 0 );

if( $success ) {
    print "this is what the command printed:\n";
    print join "", @$full_buf;
}

### run_forked example ###
my $result = run_forked("$full_path -q -O - theregister.co.uk", {'timeout' => 20});
if ($result->{'exit_code'} eq 0 && !$result->{'timeout'}) {
    print "this is what wget returned:\n";
    print $result->{'stdout'};
}

### check for features
print "IPC::Open3 available: "  . IPC::Cmd->can_use_ipc_open3;
print "IPC::Run available: "    . IPC::Cmd->can_use_ipc_run;
print "Can capture buffer: "    . IPC::Cmd->can_capture_buffer;

### don't have IPC::Cmd be verbose, ie don't print to stdout or
### stderr when running commands -- default is '0'
$IPC::Cmd::VERBOSE = 0;

描述

IPC::Cmd 允許您在不同平台上運行命令,如果需要,可以互動式地運行,但仍然能夠正常工作。

can_run 函式可以告訴您某個特定二進制文件是否已安裝,如果已安裝,則可以告訴您其所在位置;而 run 函式則可以實際執行您給出的任何命令,並給您清晰的返回值,同時遵循您的冗長設置。

類別方法

$ipc_run_version = IPC::Cmd->can_use_ipc_run( [VERBOSE] )

這是一個實用函式,告訴您是否可使用 IPC::Run。如果傳遞了 verbose 標誌,則在無法找到或加載 IPC::Run 時,它將打印診斷消息。

$ipc_open3_version = IPC::Cmd->can_use_ipc_open3( [VERBOSE] )

這是一個實用函式,告訴您是否可使用 IPC::Open3。如果傳遞了 verbose 標誌,則在無法找到或加載 IPC::Open3 時,它將打印診斷消息。

$bool = IPC::Cmd->can_capture_buffer

這是一個實用函式,告訴您 IPC::Cmd 是否能夠在其當前配置中捕獲緩衝區。

$bool = IPC::Cmd->can_use_run_forked

這是一個實用函式,告訴您 IPC::Cmd 是否能夠在當前平台上提供 run_forked

函式

$path = can_run( PROGRAM );

can_run 函式僅接受一個參數:您希望定位的二進制文件的名稱。 can_run 的工作方式類似於 unix 二進制文件 which 或 bash 命令 type,它通過您的路徑掃描,尋找所需的二進制文件。

whichtype 不同,此函式是跨平台的,例如,在 Win32 上也可以使用。

如果以純量上下文調用它,則如果找到了您要求的二進制文件,它將返回該二進制文件的完整路徑,如果未找到,則返回 undef

如果以列表上下文調用,且全局變量 $INSTANCES 是真值,則它將返回在 PATH 中找到的二進制文件的實例的完整路徑列表,如果未找到,則返回空列表。

$ok | ($ok, $err, $full_buf, $stdout_buff, $stderr_buff) = run( command => COMMAND, [verbose => BOOL, buffer => \$SCALAR, timeout => DIGIT] );

run 函數接受 4 個參數

command

這是要執行的命令。它可以是字符串或數組引用。這是一個必需的參數。

關於命令如何解析及其限制的備註,請參見 "注意事項"

verbose

這控制是否還要將命令的所有輸出打印到 STDOUT/STDERR,或者只應該將其捕獲在緩衝區中(注意:緩衝區需要安裝 IPC::Run,或者您的系統能夠使用 IPC::Open3)。

它將默認為全局設置的 $IPC::Cmd::VERBOSE,默認值為 0。

buffer

這將保存命令的所有輸出。它需要是一個標量的引用。請注意,這將保存 STDOUT 和 STDERR 消息,您無法知道哪個是哪個。如果需要區分這一點,請以列表上下文運行 run 命令並檢查各個緩衝區。

當然,這需要底層調用支持緩衝區。請參見上面關於緩衝區的注釋。

timeout

設置命令允許運行的最大時間,使用內置的 alarm() 調用進行中止。如果超時觸發,返回值中的 errorcode 將設置為 IPC::Cmd::TimeOut 類的對象。有關詳細信息,請參見下面的 "錯誤消息" 部分。

默認為 0,表示未設置超時。

run 在標量上下文中調用時將返回一個簡單的 truefalse。在列表上下文中,將返回以下項目的列表

success

一個簡單的布爾值,指示命令是否沒有錯誤地執行。

錯誤訊息

如果返回值的第一個元素(success)為0,則表示發生了一些錯誤。第二個元素是你所請求的命令退出時的錯誤訊息,如果有的話。這通常是$?$@的美化值。詳細內容請參閱perldoc perlvar。如果錯誤是超時,error message將以字符串IPC::Cmd::TimeOut作為前綴,這是超時的類別。

full_buffer

這是一個包含命令產生的所有輸出的陣列參考。請注意,只有在安裝了IPC::Run或者系統能夠使用IPC::Open3時,才會有這些緩衝區,否則該元素將為undef

out_buffer

這是一個包含所有發送到標準輸出的命令產生的輸出的陣列參考。與"full_buffer"中的注意事項相同。

error_buffer

這是一個包含所有發送到標準錯誤的命令產生的輸出的陣列參考。與"full_buffer"中的注意事項相同。

查看下面的"HOW IT WORKS"部分,了解IPC::Cmd在發出命令時如何決定使用哪些模組或函數呼叫。

$hashref = run_forked( COMMAND, { child_stdin => SCALAR, timeout => DIGIT, stdout_handler => CODEREF, stderr_handler => CODEREF} );

run_forked用於執行某個程序或代碼引用,可選擇性地向其提供一些輸入,獲取其返回碼和輸出(分別為stdout和stderr),此外,它允許在程序花費太長時間完成時終止該程序。

run_forked的重要和獨特特點是執行超時,在一開始看起來這似乎是一個相當簡單的任務,但如果你認為你要啟動的程序可能會啟動一些子程序(它們又可能會做同樣的事情,以此類推),這就不是一個簡單的問題。

run_forked被設計為能夠在幾乎任何長時間運行的任務中存活並成功終止,即使在給定的超時期間內出現fork bomb,如果您的系統有資源可以在給定的超時期間內存活下來。

這是通過創建單獨的看門狗進程來實現的,該進程在單獨的進程會話中生成指定的程序並監視它:可選地向其提供輸入,存儲其退出代碼、stdout 和 stderr,如果運行時間超過指定時間,則終止它。

調用需要執行的命令或 coderef,可選地是選項的哈希引用

timeout

在秒中指定命令運行多長時間後,它將被用 SIG_KILL (9) 殺死,這將有效地終止它及其所有子進程(直接或間接)。

child_stdin

指定要傳遞給執行程序的 STDIN 的一些文本。

stdout_handler

從執行程序的 STDOUT 收到一部分數據時調用的子例程的 coderef。

stderr_handler

從執行程序的 STDERR 收到一部分數據時調用的子例程的 coderef。

wait_loop_callback

主等待循環內部調用的子例程的 coderef(當 run_forked 等待外部進程完成或失敗時)。在外部命令基於其輸出終止之前,停止運行外部進程很有用,例如。

  my $r = run_forked("some external command", {
	  'wait_loop_callback' => sub {
          if (condition) {
              kill(1, $$);
          }
	  },
	  'terminate_on_signal' => 'HUP',
	  });

結合 stdout_handlerstderr_handler 允許根據其輸出終止外部命令。也可以作為計時器使用,而不需要使用 alarm(信號)。

請記住,此代碼可能每毫秒被調用一次(取決於外部命令生成的輸出),因此請儘可能使其輕量級。

discard_output

丟棄 run_forked() 返回的標準輸出和標準錯誤的緩衝區。使用此選項,您必須使用 std*_handlers 讀取命令的輸出。對於發送大量輸出的命令很有用。

terminate_on_parent_sudden_death

啟用此選項,如果最初生成的進程(父進程)被殺死或意外死亡,則希望終止所有衍生的進程,而不必等待子進程。

run_forked 將返回具有以下鍵的 HASHREF

exit_code

執行程序的退出代碼。

timeout

程序在被終止之前運行的秒數,如果沒有超時則為 0。

stdout

保存執行命令的標準輸出(如果沒有標準輸出或使用discard_output時為空字符串;它始終被定義!)

stderr

保存執行命令的標準錯誤(如果沒有標準錯誤或使用discard_output時為空字符串;它始終被定義!)

merged

將執行命令的標準輸出和錯誤合併為一個流(如果根本沒有輸出或使用discard_output時為空字符串;它始終被定義!)

err_msg

在出現錯誤時保存一些說明。

$q = QUOTE

返回在此平台上用於引用字符串的字符。在大多數系統上,這通常是'(單引號),但某些系統使用不同的引號。例如,Win32使用"(雙引號)。

您可以像下面這樣使用它

use IPC::Cmd qw[run QUOTE];
my $cmd = q[echo ] . QUOTE . q[foo bar] . QUOTE;

這確保foo bar被視為一個字符串,而不是echo函數的兩個獨立參數。

HOW IT WORKS

run將嘗試使用以下邏輯執行您的命令

全局變量

IPC::Cmd的行為可以通過更改以下全局變量來修改

$IPC::Cmd::VERBOSE

這個控制 IPC::Cmd 是否將來自命令的任何輸出列印到螢幕上。默認值為 0。

$IPC::Cmd::USE_IPC_RUN

此變數控制當可用且適用時,IPC::Cmd 是否嘗試使用 IPC::Run。

$IPC::Cmd::USE_IPC_OPEN3

此變數控制當可用且適用時,IPC::Cmd 是否嘗試使用 IPC::Open3。默認值為 true。

$IPC::Cmd::WARN

此變數控制是否應該發出運行時警告,例如明確要求的 IPC::* 模塊無法加載的失敗。

默認為 true。關閉此功能需自擔風險。

$IPC::Cmd::INSTANCES

此變數控制當以列表上下文調用時,can_run 是否返回路徑中找到的二進制文件的所有實例。

默認為 false,設為 true 以啟用所描述的行為。

$IPC::Cmd::ALLOW_NULL_ARGS

此變數控制 run 是否會刪除在命令參數中找到的任何空/空值參數。

默認為 false,因此將刪除空參數。設為 true 以允許它們。

Caveats

空白和 IPC::Open3 / system()

當使用 IPC::Open3 或 system 時,如果將字符串作為命令參數提供,則假定它已適當逃脫。您可以使用 QUOTE 常量作為可移植的引號字符(請參見上文)。但是,如果提供數組引用,則適用特殊規則。

如果您的命令包含特殊字符(< > | &),則在執行命令之前將其內部化,以避免這些特殊字符被逃脫並作為參數傳遞而不是保留其特殊含義。

但是,如果命令包含包含空格的參數,將命令內部化將失去空格的意義。因此,如果命令以數組引用形式傳遞且包含特殊字符,IPC::Cmd 將對命令中包含空格的任何參數進行引用。

空格和IPC::Run

當使用 IPC::Run 時,如果您將字符串作為 command 參數提供,則該字符串將根據空格進行拆分,以確定命令的各個元素。儘管這通常只會做您想做的事,但如果您的文件或命令中包含空格,則可能會出現問題。

如果您不希望發生這種情況,您應該提供一個數組引用,其中您命令的所有部分已經分開。但是請注意,如果這些部分中有額外或多餘的空格,則解析器或底層代碼可能無法正確解釋它,並且可能會導致錯誤。

例子:以下代碼

gzip -cdf foo.tar.gz | tar -xf -

應該傳遞為

"gzip -cdf foo.tar.gz | tar -xf -"

或者為

['gzip', '-cdf', 'foo.tar.gz', '|', 'tar', '-xf', '-']

但要注意不要將其傳遞為,例如

['gzip -cdf foo.tar.gz', '|', 'tar -xf -']

因為這將導致如上述描述的問題。

IO 重定向

目前解析命令中的 IO 重定向太複雜了。但是,對於捕獲 STDOUT 或 STDERR,有一個解決方法,因為您可以檢查您的緩衝區中的內容。

交錯 STDOUT/STDERR

無論是 IPC::Run 還是 IPC::Open3 都無法交錯 STDOUT 和 STDERR。對於程序的短暫輸出突發情況,例如這個示例,

for ( 1..4 ) {
    $_ % 2 ? print STDOUT $_ : print STDERR $_;
}

IPC::[Run|Open3] 首先將讀取所有的 STDOUT,然後讀取所有的 STDERR,這意味著輸出看起來像是 STDOUT 上的 '13',STDERR 上的 '24',而不是

1
2
3
4

這已經在 rt.cpan.org 記錄為 bug #37532: 無法交錯 STDOUT 和 STDERR。

參見

IPC::RunIPC::Open3

致謝

感謝 James Mastros 和 Martijn van der Streek 幫助使 IPC::Open3 表現得很好。

感謝 Petya Kohts 提供 run_forked 代碼。

錯誤報告

請將錯誤或其他問題報告給 <bug-ipc-cmd@rt.cpan.org>。

作者

原作者:Jos Boumans <kane@cpan.org>。目前的維護者:Chris Williams <bingos@cpan.org>。

版權

此程式庫屬於自由軟體,您可以按照 Perl 本身的相同條款進行重新分發和/或修改。