Как я могу считать вывод из внешних команд в режиме реального времени в Perl?

Сброс ответвления к повисшему объекту фиксации ее старой подсказки является, конечно, лучшим решением, потому что это восстанавливает предыдущее состояние, не расходуя усилия. Но если Вы, оказывается, потеряли те фиксации (f.ex., потому что Вы собрали "мусор" свой репозиторий тем временем, или это - новый клон), можно всегда повторно основывать ответвление снова. Ключ к этому эти --onto переключатель.

Let’s говорят, что у Вас было ответвление темы, образно названное topic, что Вы отклонились master, когда подсказка master была эти 0deadbeef фиксация. В какой-то момент, в то время как на эти topic ответвление, Вы сделали git rebase master. Теперь Вы хотите отменить это. Here’s, как:

git rebase --onto 0deadbeef master topic

Это возьмет все фиксации на topic, что aren’t на master и воспроизводят их сверху [1 110].

С [1 111], можно перестроить историю в в значительной степени любая форма безотносительно .

Весело проводят время.:-)

5
задан brian d foy 7 August 2009 в 03:19
поделиться

7 ответов

Вместо потоков и `` используйте:

 open my $fh, '-|', 'some_program --with-options';

Таким образом откройте несколько дескрипторов файлов (столько программ, которые вам нужно запустить), а затем используйте IO :: Select для опроса данных от них.

Упрощенный пример.

Предположим, у меня есть сценарий оболочки, который выглядит следующим образом:

=> cat test.sh
#!/bin/bash
for i in $( seq 1 5 )
do
    sleep 1
    echo "from $$ : $( date )"
done

его вывод может выглядеть так:

=> ./test.sh
from 26513 : Fri Aug  7 08:48:06 CEST 2009
from 26513 : Fri Aug  7 08:48:07 CEST 2009
from 26513 : Fri Aug  7 08:48:08 CEST 2009
from 26513 : Fri Aug  7 08:48:09 CEST 2009
from 26513 : Fri Aug  7 08:48:10 CEST 2009

Теперь давайте напишем multi-test.pl :

#!/usr/bin/perl -w
use strict;
use IO::Select;

my $s = IO::Select->new();

for (1..2) {
    open my $fh, '-|', './test.sh';
    $s->add($fh);
}

while (my @readers = $s->can_read()) {
    for my $fh (@readers) {
        if (eof $fh) {
            $s->remove($fh);
            next;
        }
        my $l = <$fh>;
        print $l;
    }
}

Как видите, нет ни вилок, ни потоков. И вот как это работает:

=> time ./multi-test.pl
from 28596 : Fri Aug  7 09:05:54 CEST 2009
from 28599 : Fri Aug  7 09:05:54 CEST 2009
from 28596 : Fri Aug  7 09:05:55 CEST 2009
from 28599 : Fri Aug  7 09:05:55 CEST 2009
from 28596 : Fri Aug  7 09:05:56 CEST 2009
from 28599 : Fri Aug  7 09:05:56 CEST 2009
from 28596 : Fri Aug  7 09:05:57 CEST 2009
from 28599 : Fri Aug  7 09:05:57 CEST 2009
from 28596 : Fri Aug  7 09:05:58 CEST 2009
from 28599 : Fri Aug  7 09:05:58 CEST 2009

real    0m5.128s
user    0m0.060s
sys     0m0.076s
8
ответ дан 18 December 2019 в 10:47
поделиться

См. perlipc (межпроцессное взаимодействие), чтобы узнать о некоторых вещах, которые вы можете сделать. Открытие по конвейеру и IPC :: Open3 удобны.

2
ответ дан 18 December 2019 в 10:47
поделиться

да, можно.

while (<STDIN>) { print "Line: $_"; }

Проблема в том, что некоторые приложения не выводят информацию построчно, а обновляют одну строку до завершения. Это твой случай?

1
ответ дан 18 December 2019 в 10:47
поделиться

Вот он с кодом GTK2 для отображения индикаторов выполнения.

#!/usr/bin/perl
use strict;
use warnings;

use Glib qw/TRUE FALSE/;
use Gtk2 '-init';

my $window = Gtk2::Window->new('toplevel');
$window->set_resizable(TRUE);
$window->set_title("command runner");

my $vbox = Gtk2::VBox->new(FALSE, 5);
$vbox->set_border_width(10);
$window->add($vbox);
$vbox->show;

# Create a centering alignment object;
my $align = Gtk2::Alignment->new(0.5, 0.5, 0, 0);
$vbox->pack_start($align, FALSE, FALSE, 5);
$align->show;

# Create the Gtk2::ProgressBar and attach it to the window reference.
my $pbar = Gtk2::ProgressBar->new;
$window->{pbar} = $pbar;
$align->add($pbar);
$pbar->show;

# Add a button to exit the program.
my $runbutton = Gtk2::Button->new("Run");
$runbutton->signal_connect_swapped(clicked => \&runCommands, $window);
$vbox->pack_start($runbutton, FALSE, FALSE, 0);

# This makes it so the button is the default.
$runbutton->can_default(TRUE);

# This grabs this button to be the default button. Simply hitting the "Enter"
# key will cause this button to activate.
$runbutton->grab_default;
$runbutton->show;

# Add a button to exit the program.
my $closebutton = Gtk2::Button->new("Close");
$closebutton->signal_connect_swapped(clicked => sub { $_[0]->destroy;Gtk2->main_quit; }, $window);
$vbox->pack_start($closebutton, FALSE, FALSE, 0);

$closebutton->show;

$window->show;

Gtk2->main;

sub pbar_increment {
    my ($pbar, $amount) = @_;

    # Calculate the value of the progress bar using the
    # value range set in the adjustment object
    my $new_val = $pbar->get_fraction() + $amount;

    $new_val = 0.0 if $new_val > 1.0;

    # Set the new value
    $pbar->set_fraction($new_val);
}

sub runCommands {
        use IO::Select;

        my $s = IO::Select->new();

        for (1..2) {
            open my $fh, '-|', './test.sh';
            $s->add($fh);
        }

        while (my @readers = $s->can_read()) {
            for my $fh (@readers) {
                if (eof $fh) {
                    $s->remove($fh);
                    next;
                }
                my $l = <$fh>;
                print $l;
                pbar_increment($pbar, .25) if $l =~ /output/;
            }
        }
    }

см. документацию perl GTK2 для получения дополнительной информации

1
ответ дан 18 December 2019 в 10:47
поделиться

Я использую эту подпрограмму и метод для регистрации моих внешних команд. Это называется так:

open($logFileHandle, "mylogfile.log");

logProcess($logFileHandle, "ls -lsaF", 1, 0); #any system command works

close($logFileHandle);

и вот подпрограммы:

#******************************************************************************
# Sub-routine: logProcess()
#      Author: Ron Savage
#        Date: 10/31/2006
# 
# Description:
# This sub-routine runs the command sent to it and writes all the output from
# the process to the log.
#******************************************************************************
sub logProcess
   {
   my $results;

   my ( $logFileHandle, $cmd, $print_flag, $no_time_flag ) = @_;
   my $logMsg;
   my $debug = 0;

   if ( $debug ) { logMsg($logFileHandle,"Opening command: [$cmd]", $print_flag, $no_time_flag); }
   if ( open( $results, "$cmd |") )
      {
      while (<$results>)
         {
         chomp;
         if ( $debug ) { logMsg($logFileHandle,"Reading from command: [$_]", $print_flag, $no_time_flag); }
         logMsg($logFileHandle, $_, $print_flag, $no_time_flag);
         }

      if ( $debug ) { logMsg($logFileHandle,"closing command.", $print_flag, $no_time_flag); }
      close($results);
      }
   else
      {
      logMsg($logFileHandle, "Couldn't open command: [$cmd].")
      }
   }

#******************************************************************************
# Sub-routine: logMsg()
#      Author: Ron Savage
#        Date: 10/31/2006
# 
# Description:
# This sub-routine prints the msg and logs it to the log file during the 
# install process.
#******************************************************************************
sub logMsg
   {
   my ( $logFileHandle, $msg, $print_flag, $time_flag ) = @_;
   if ( !defined($print_flag) ) { $print_flag = 1; }
   if ( !defined($time_flag) ) { $time_flag = 1; }

   my $logMsg;

   if ( $time_flag ) 
      { $logMsg = "[" . timeStamp() . "] $msg\n"; }
   else 
      { $logMsg = "$msg\n"; } 

   if ( defined($logFileHandle)) { print $logFileHandle $logMsg; }

   if ( $print_flag ) { print $logMsg; }
   }
1
ответ дан 18 December 2019 в 10:47
поделиться

Обратные кавычки и оператор qx // оба блокируются до тех пор, пока -процесс заканчивается. Вам нужно открыть сценарии bash на канале. Если вам нужно, чтобы они были неблокирующими, откройте их как дескрипторы файлов, используя open2 или open3, если необходимо, затем поместите дескрипторы в select () и подождите, пока они станут читаемыми.

Я только что столкнулся с аналогичной проблемой - - У меня был очень долгий процесс (служба, которая могла работать неделями), которую я открыл с qx //. Проблема заключалась в том, что выходные данные этой программы в конечном итоге превысили ограничения памяти (около 2,5 Гбайт на моей архитектуре). Я решил это, открыв подкоманду на конвейере, а затем сохранив только последние 1000 строк вывода. При этом я заметил, что форма qx // печатает вывод только после завершения команды, но форма конвейера смогла распечатать вывод, как это произошло.

У меня нет кода под рукой, но если вы можете подожди до завтра, я опубликую то, что сделал.

3
ответ дан 18 December 2019 в 10:47
поделиться

Самый простой способ запустить дочерний процесс с полным контролем над его вводом и выводом - это модуль IPC :: Open2 (или IPC :: Open3 ], если вы также хотите захватить STDERR), но проблема, если вы хотите иметь дело с несколькими одновременно, или особенно если вы хотите сделать это в графическом интерфейсе, - это блокировка. Если вы просто наберете тип <$ fh> read, он будет заблокирован до тех пор, пока вы не введете ввод, потенциально заклинив весь пользовательский интерфейс. Если дочерний процесс интерактивен, это еще хуже, потому что вы легко можете заблокировать его, когда и дочерний процесс, и родительский процесс ждут ввода от другого. Вы можете написать свой собственный цикл select и выполнять неблокирующий ввод-вывод, но это того не стоит. Я предлагаю использовать POE , POE :: Wheel ::

0
ответ дан 18 December 2019 в 10:47
поделиться
Другие вопросы по тегам:

Похожие вопросы: