Отображение прогресса при выполнении команды system () в Perl - PullRequest
7 голосов
/ 07 июля 2010

У меня есть сценарий Perl, который выполняет некоторые задачи, одна из которых заключается в вызове system команды для "tar -cvf file.tar.....".

Это часто может занять некоторое время, поэтому я бы хотел, чтобы командная строкаэхо-индикатор прогресса, что-то вроде #, эхо-отображение на экране, пока идет вызов system.

Я немного покопался и наткнулся на fork.Это лучший путь?Можно ли отключить команду system, а затем создать цикл while, который проверяет состояние $pid, возвращаемого вилкой?

Я также видел ссылки на waitpid .... Я думаю, мне нужно использовать это тоже.

fork system("tar ... ")
while ( forked process is still active) {
    print #
    sleep 1
}

Я лаю не на том дереве?

Большое спасибо Джон

Ответы [ 6 ]

7 голосов
/ 07 июля 2010

В Perl есть хорошая конструкция, называемая «труба открывается». Вы можете узнать больше об этом, набрав perldoc -f open в приглашении оболочки.

# Note the use of a list for passing the command. This avoids
# having to worry about shell quoting and related errors.
open(my $tar, '-|', 'tar', 'zxvf', 'test.tar.gz', '-C', 'wherever') or die ...;

Вот фрагмент, показывающий пример:

  open(my $tar, '-|', 'tar', ...) or die "Could not run tar ... - $!";
  while (<$tar>) {
       print ".";
  }
  print "\n";
  close($tar);

Замените print "." на что-то, что печатает хэш-метку каждые 10-100 строк или около того, чтобы получить хорошую шкалу.

6 голосов
/ 07 июля 2010

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

use POSIX qw(:sys_wait_h);
$|++;

defined(my $pid = fork) or die "Couldn't fork: $!";

if (!$pid) { # Child
  exec('long_running_command', @args) 
    or die "Couldn't exec: $!";
} else { # Parent
  while (! waitpid($pid, WNOHANG)) {
    print ".";
    sleep 1;
  }
  print "\n";
}

Хотя, возможно, он может иметь больше возможностей для проверки ошибок, и может на самом деле быть чем-то лучше уже на CPAN. Proc :: Background кажется многообещающим для абстрагирования такой работы, но я не уверен, насколько она надежна.

2 голосов
/ 01 апреля 2011
$|++;    
open(my $tar, 'tar ... |') or die "Could not run tar ... - $!";
      while ($file=<$tar>) {
           print "$file";
      }
      print "\n";
      close($tar);

Печатает имена файлов, полученные от tar.

1 голос
/ 07 июля 2010

Для отображения прогресса во время длительной задачи вы найдете Term :: ProgressBar полезной - она ​​выполняет описанную вами функцию «печати # через экран».

1 голос
/ 07 июля 2010

Я бы попробовал что-то вроде этого

open my $tar, "tar -cvf file.tar..... 2>&/dev/null |"
    or die "can't fork: $!";
my $i = 0;
while (<$tar>) {
    if( i++ % 1000 == 0 ) print;
} 
close $tar or die "tar error: $! $?";
0 голосов
/ 11 января 2016

Расширение того, что предоставил Хоббс, если вы хотите получить данные от дочернего процесса обратно в родительский процесс, вам необходим внешний канал.Я закончил тем, что использовал tempfs, потому что это было просто, как файл, но не помещал хиты ввода-вывода на диск.

** Важно ** Вам необходимо выйти из дочернего процесса, потому что в противном случае это «дочерний» процесспродолжите по тому же сценарию, и вы получите двойные операторы print.Таким образом, в приведенном ниже примере foreach (@stdoutput) произойдет два раза, несмотря на то, что он присутствует в сценарии только один раз.

$shm_id = time;  #get unique name for file - example "1452463743"
$shm_file = "/dev/shm/$shm_id.tmp";   #set filename in tempfs
$| = 1;  #suffering from buffering
print ("Activity Indicator: "); #No new line here
defined(my $pid = fork) or die "Couldn't fork: $!";
if (!$pid) { # Child
    @stdoutput=`/usr/home/script.pl -o $parameter`; #get output of external command
    open (SHM, ">$shm_file");
    foreach (@stdoutput) {
        print SHM ("$_");  #populate file in tempfs
    }
    close (SHM);        
    exit;  #quit the child process (will not kill parent script)
} else { # Parent
    while (! waitpid($pid, WNOHANG)) {
    print ("\#");  # prints a progress bar
        sleep 5;
    }
}
print ("\n"); #finish up bar and go to new line
open (SHM, "$shm_file");
    @stdoutput = <SHM>;  #Now open the file and read it. Now array is in parent
close (SHM);
unlink ($shm_file);  #deletes the tempfs file
chomp(@stdoutput);
foreach (@stdoutput) {
    print ("$_\n");  #print results of external script
}
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...