Сброс ответвления к повисшему объекту фиксации ее старой подсказки является, конечно, лучшим решением, потому что это восстанавливает предыдущее состояние, не расходуя усилия. Но если Вы, оказывается, потеряли те фиксации (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], можно перестроить историю в в значительной степени любая форма безотносительно .
Весело проводят время.:-)
Вместо потоков и `` используйте:
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
См. perlipc (межпроцессное взаимодействие), чтобы узнать о некоторых вещах, которые вы можете сделать. Открытие по конвейеру и IPC :: Open3 удобны.
да, можно.
while (<STDIN>) { print "Line: $_"; }
Проблема в том, что некоторые приложения не выводят информацию построчно, а обновляют одну строку до завершения. Это твой случай?
Вот он с кодом 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 для получения дополнительной информации
Я использую эту подпрограмму и метод для регистрации моих внешних команд. Это называется так:
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; }
}
Обратные кавычки и оператор qx // оба блокируются до тех пор, пока -процесс заканчивается. Вам нужно открыть сценарии bash на канале. Если вам нужно, чтобы они были неблокирующими, откройте их как дескрипторы файлов, используя open2 или open3, если необходимо, затем поместите дескрипторы в select () и подождите, пока они станут читаемыми.
Я только что столкнулся с аналогичной проблемой - - У меня был очень долгий процесс (служба, которая могла работать неделями), которую я открыл с qx //. Проблема заключалась в том, что выходные данные этой программы в конечном итоге превысили ограничения памяти (около 2,5 Гбайт на моей архитектуре). Я решил это, открыв подкоманду на конвейере, а затем сохранив только последние 1000 строк вывода. При этом я заметил, что форма qx // печатает вывод только после завершения команды, но форма конвейера смогла распечатать вывод, как это произошло.
У меня нет кода под рукой, но если вы можете подожди до завтра, я опубликую то, что сделал.
Самый простой способ запустить дочерний процесс с полным контролем над его вводом и выводом - это модуль IPC :: Open2
(или IPC :: Open3
], если вы также хотите захватить STDERR), но проблема, если вы хотите иметь дело с несколькими одновременно, или особенно если вы хотите сделать это в графическом интерфейсе, - это блокировка. Если вы просто наберете тип <$ fh>
read, он будет заблокирован до тех пор, пока вы не введете ввод, потенциально заклинив весь пользовательский интерфейс. Если дочерний процесс интерактивен, это еще хуже, потому что вы легко можете заблокировать его, когда и дочерний процесс, и родительский процесс ждут ввода от другого. Вы можете написать свой собственный цикл select
и выполнять неблокирующий ввод-вывод, но это того не стоит. Я предлагаю использовать POE
, POE :: Wheel ::