2012-07-17 68 views
21

我需要運行與系統()在Perl外殼命令的輸出。例如,捕獲的Perl系統()

system('ls')

系統調用將打印到標準輸出,但我想輸出捕捉到一個變量,這樣我可以做進一步處理我的Perl代碼。

+1

不要使用系統,請使用open()和管道。 – 2012-07-17 01:41:42

+0

你能舉個例子嗎?謝謝! – Dagang 2012-07-17 01:42:20

+1

'perldoc -f open' – 2012-07-17 02:27:57

回答

32

這就是反引號是。從perldoc perlfaq8

爲什麼我不能得到一個命令與system()輸出?

你混淆的system()和反引號(``)的目的。 system() 運行一個命令並返回退出狀態信息(作爲16位值: ,低7位是進程死亡信號,如果有的話,高8位是實際的退出值)。反引號(``)運行命令 並返回它發送到標準輸出。

my $exit_status = system("mail-users"); 
my $output_string = `ls`; 

詳情請參閱perldoc perlop

12

IPC::Run是我最喜歡這樣的任務模塊。非常強大和靈活,對於小型案例也非常簡單。

use IPC::Run 'run'; 

run [ "command", "arguments", "here" ], ">", \my $stdout; 

# Now $stdout contains output 
+3

I我們一直在尋找一種簡單的方法來通過命令參數而不使用shell插值,並從所謂的命令中捕獲stdout。優秀的答案,謝謝! – 2013-12-30 10:59:01

3

只需使用類似來砸例如:

$variable=`some_command some args`; 

多數民衆贊成。 通知,你會不會在輸出看到任何印刷到標準輸出,因爲這會被重定向到變量。 除了您已準備好答案之外,此示例對與用戶交互的命令不可用。對,你可以使用類似這樣使用shell命令的堆棧:

$variable=`cat answers.txt|some_command some args`; 

answers.txt文件中,你應該準備回答所有的some_command正常工作。

我知道這不是編程的最佳方式:)但這是如何實現目標的最簡單方法,特別適用於bash程序員。

當然,如果輸出較大(ls與子目錄),你不應該一次獲得所有的輸出。通過同樣的方式讀取命令,當你閱讀regullar文件:

open CMD,'-|','your_command some args' or die [email protected]; 
my $line; 
while (defined($line=<CMD>)) { 
    print $line; #or push @table,$line or do whatewer what you want processing line by line 
} 
close CMD; 

附加處理長命令輸出,無需額外的bash調用擴展的解決方案:

my @CommandCall=qw(find/-type d); #some example single command 
my $commandSTDOUT; #file handler 
my $pid=open($commandSTDOUT),'-|'); #there will be implict fork! 
if ($pid) { 
    #parent side 
    my $singleLine; 
    while(defined($singleline=<$commandSTDOUT>)) { 
     chomp $line; #typically we don't need EOL 
     do_some_processing_with($line); 
    }; 
    close $commandSTDOUT; #in this place $? will be set for capture 
    $exitcode=$? >> 8; 
    do_something_with_exit_code($exitcode); 
} else { 
    #child side, there you really calls a command 
    open STDERR, '>>&', 'STDOUT'; #redirect stderr to stdout if needed, it works only for child, remember about fork 
    exec(@CommandCall); #at this point child code is overloaded by external command with parameters 
    die "Cannot call @CommandCall"; #error procedure if call will fail 
} 

如果使用過程那樣,你將捕獲所有程序輸出,並且您可以逐行執行所有處理。祝你好運:)

1

我想運行system()而不是backtacks,因爲我想看到rsync --progress的輸出。但是,我還想捕獲輸出以防出現錯誤,具體取決於返回值。 (這是用於備份腳本)。這是我現在使用的:

use File::Temp qw(tempfile); 
use Term::ANSIColor qw(colored colorstrip); 



sub mysystem { 
    my $cmd = shift; #"rsync -avz --progress -h $fullfile $copyfile"; 
    my ($fh, $filename) = tempfile(); 
    # http://stackoverflow.com/a/6872163/2923406 
    # I want to have rsync progress output on the terminal AND capture it in case of error. 
    # Need to use pipefail because 'tee' would be the last cmd otherwise and hence $? would be wrong. 
    my @cmd = ("bash", "-c", "set -o pipefail && $cmd 2>&1 | tee $filename"); 
    my $ret = system(@cmd); 
    my $outerr = join('', <$fh>); 
    if ($ret != 0) { 
     logit(colored("ERROR: Could not execute command: $cmd", "red")); 
     logit(colored("ERROR: stdout+stderr = $outerr", "red")); 
     logit(colored("ERROR: \$? = $?, \$! = $!", "red")); 
    } 
    close $fh; 
    system("rm $filename"); 
    return $ret; 
} 

# and logit() is sth like: 
sub logit { 
    my $s = shift; 
    my ($logsec,$logmin,$loghour,$logmday,$logmon,$logyear,$logwday,$logyday,$logisdst)=localtime(time); 
    $logyear += 1900; 
    my $logtimestamp = sprintf("%4d-%02d-%02d %02d:%02d:%02d",$logyear,$logmon+1,$logmday,$loghour,$logmin,$logsec); 
    my $msg = "$logtimestamp $s\n"; 
    print $msg; 
    open LOG, ">>$LOGFILE"; 
    print LOG colorstrip($msg); 
    close LOG; 
} 
+0

你爲什麼要調用system(「rm $ filename」)?你有內部程序取消鏈接$ filename,它沒有額外的調用sh或bash解釋器。 – Znik 2018-02-02 12:38:35