Версия для печати темы
Нажмите сюда для просмотра этой темы в оригинальном формате
Форум программистов > Perl: Общие вопросы > Запуск всех скриптов Perl кроме самого себя


Автор: Suppir 25.3.2014, 11:22
Добрый день!

В директории 20 скриптов Perl, их нужно последовательно запускать. Я написал скрипт-пускач, который будет запускать остальные скрипты (кроме себя) в многопоточном режиме.

Код

use threads;
use Thread::Queue;

my $q = Thread::Queue->new();

if ($0 =~ /.+\\(.+)/){$myname = $1}

while(<*.pl>){
    $q -> enqueue($_) if $_ ne $myname;
}

my $thread_limit = 2; 

my @thr = map {
    threads->create(sub {
        while (defined (my $item = $q->dequeue_nb())){
            print "$item\n";
            system($item);
        }
    });
} 1..$thread_limit;
$_->join() for @thr;



Проблема в следующем. Все скрипты выдают какую-то информацию в консоль. И сейчас в консоли "пускача" отображается какая-то белиберда - запускаемые скрипты пишут свою информацию внахлест.

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

Автор: tzirechnoy 25.3.2014, 11:30
Можно.

Автор: Suppir 25.3.2014, 11:31
Как? smile

Автор: Romikgy 25.3.2014, 11:41
переведи вывод в файл 

Автор: Suppir 25.3.2014, 11:42
STDOUT, что-ли?


Ну, я добавил:
Код

open(STDOUT, ">$0.log");


Теперь вместо консоли пишет в файл. Но мне нужно, чтобы пускач писал в консоли, какие именно скрипты он запустил.

Автор: Bulat 25.3.2014, 12:01
Цитата(Suppir @  25.3.2014,  11:42 Найти цитируемый пост)
Но мне нужно, чтобы пускач писал в консоли, какие именно скрипты он запустил.


Код

#!/usr/bin/perl

print $0, "\n";



Автор: Suppir 25.3.2014, 12:15
Куда это прописать?

Менять вывод всех 20 скриптов нет возможности. Нужно именно в пуске все прописать. 

Автор: Bulat 25.3.2014, 12:31
Suppir, считается, что

Код

            print "$item\n";
            system($item);


вот этот print и делает то, что тебе нужно. Но делает ли он это или нет у тебя - не знаю!

Добавлено через 9 минут и 5 секунд
Попробуй закомментировать строку 

Код

system($item);


и посмотри что будет писаться в консоли.

Автор: Romikgy 25.3.2014, 12:47
Код

print "$item\n";
            system($item." > log.txt");

Автор: Suppir 25.3.2014, 12:54
Romikgy, 

из нескольких потоков не может писать в один log.txt, т.к. "файл заблокирован другим процессом".





Добавлено @ 12:56
Цитата(Bulat @ 25.3.2014,  12:31)
Suppir, считается, что

Код

            print "$item\n";
            system($item);


вот этот print и делает то, что тебе нужно. Но делает ли он это или нет у тебя - не знаю!

Добавлено @ 12:40
Попробуй закомментировать строку 

Код

system($item);


и посмотри что будет писаться в консоли.

Я закомментировал строку и получается следующее:
1) не пишется название запущенных скриптов;
2) выводится в консоль та информация, которую выдают запущенные скрипты.

И мне нужно ровно наоборот - чтобы информация от скриптов (что, что в скриптах прописано через Print) не выводилась в консоль и чтобы отображались названия запущенных скриптов. 

Автор: Bulat 25.3.2014, 13:00
Цитата(Suppir @  25.3.2014,  12:54 Найти цитируемый пост)
Я закомментировал строку и получается следующее:
1) не пишется название запущенных скриптов;
2) выводится в консоль та информация, которую выдают запущенные скрипты.


или ты сделал не то, что я тебе написал, или ты врешь!

Код

system($item);


запускает твои скрипты - если ты эту строку закомментировал(а не что-то другое), то у тебя скрипты вообще не должны были бы запускаться!  smile

Добавлено через 1 минуту и 43 секунды
Цитата(Romikgy @  25.3.2014,  12:47 Найти цитируемый пост)
            system($item." > log.txt");


а если 

Код

system($item." > $item.txt");


??

Автор: Suppir 25.3.2014, 13:07
Bulat, я закомментировал строки 
Код

#            print "$item\n";
#           system($item." > log.txt");


Сейчас скрипт выглядит так:

Код

use threads;
use Thread::Queue;

my $q = Thread::Queue->new();

if ($0 =~ /.+\\(.+)/){$myname = $1}

while(<*.pl>){
    $q -> enqueue($_) if $_ ne $myname;
}

my $thread_limit = 2; 

my @thr = map {
    threads->create(sub {
        while (defined (my $item = $q->dequeue_nb())){
#            print "$item\n";
#           system($item." > log.txt");
            system($item);
        }
    });
} 1..$thread_limit;
$_->join() for @thr;



Он работает неправильно: в консоль перенаправляется вывод со всех скриптов (вперемешку), а названия запущенных скриптов не отображаются.

Добавлено через 1 минуту
Понятно, что если закомментировать
Код

system($item);

, то ни один скрипт вообще не запустится.

Добавлено через 2 минуты и 58 секунд
Цитата(Bulat @  25.3.2014,  13:00 Найти цитируемый пост)
а если 

код Perl
1:
system($item." > $item.txt");
?? 



Ну, получится 20-лог файлов с именами скриптов. Но дело в том, что и сейчас эти 20 скриптов создают 20-лог файлов с различной информацией. Зачем мне еще что-то писать.

Нужно только запускать параллельно эти 20 скриптов и выводить в консоль, какие скрипты запущены - вот и все. 

Автор: Bulat 25.3.2014, 13:13
Suppir, вообще-то я тебе писал совсем другое, но по закону Мерфи...  smile 

Код

use threads;
use Thread::Queue;
my $q = Thread::Queue->new();
if ($0 =~ /.+\\(.+)/){$myname = $1}
while(<*.pl>){
    $q -> enqueue($_) if $_ ne $myname;
}
my $thread_limit = 2; 
my @thr = map {
    threads->create(sub {
        while (defined (my $item = $q->dequeue_nb())){
            print "$item\n";
#           system($item." > log.txt");
#            system($item);
        }
    });
} 1..$thread_limit;
$_->join() for @thr;


Так можно проверить вывод в консоль названия запускаемых скриптов,

Если оное происходит - значит то, что ты хочешь уже делается! Нужно лишь маленько изменить сам запуск скриптов!  smile 

Автор: Suppir 25.3.2014, 13:23
Bulat, 

если оставить строчку
Код

print "$item\n";


то в консоль выводятся названия скриптов. Это правильно.

Проблема в другом. Если мы запустим скрипты строчкой

Код

system($item);


то эти скрипты начинают наперебой  писать свою информацию в консоль пускача. То есть запускаемые потоки передают свой STDOUT в консоль пускача. Переделывать все скрипты нет возможности. Нужно отредактировать пускач таким образом, чтобы он отображал только названия запускаемых скриптов и не выводит их STDOUT в свою консоль.

Автор: Bulat 25.3.2014, 13:26
если ось юниксовая, то попробуй

Код

system($item." > /dev/null");


P.S. я больше предпочитаю форки, но вроде как и с тредами должно работать!  smile 

Автор: Suppir 25.3.2014, 13:32
Нет, виндовс стоит.


Еще есть такой вариант. Чтобы скрипт пускач запускал скрипты Perl в отдельных окнах. И пусть они там себе в консоль выводят, что хотят. Такой вариант возможен?


Автор: Bulat 25.3.2014, 13:36
Цитата(Suppir @  25.3.2014,  13:32 Найти цитируемый пост)
Нет, виндовс стоит.


Если виндовс, то делай

Код

system($item." > $item.txt");


самое оптимальное решение, которое не принесет за собой другие проблемы!  smile 

Автор: Suppir 25.3.2014, 13:42
К сожалению, не оптимальное. Каждый скрипт выдает log-файл. А теперь он еще и создает лишние txt-файлы.

Разве что стирать потом эти файлы в конце работы скрипта...

Добавлено через 3 минуты и 45 секунд
Короче, изменил код на следующий:

Код

use threads;
use Thread::Queue;

my $q = Thread::Queue->new();

if ($0 =~ /.+\\(.+)/){$myname = $1}

while(<*.pl>){
    $q -> enqueue($_) if $_ ne $myname;
}

my $thread_limit = 2; 

my @thr = map {
    threads->create(sub {
        while (defined (my $item = $q->dequeue_nb())){
            print "$item\n";
            system($item." > $item.temp")
        }
    });
} 1..$thread_limit;
$_->join() for @thr;

while(<*.temp>){unlink}


В файлы $item.temp пишется вывод STDOUT скриптов, а в конце скрипта пускач подчищает за собой эти темповые файлы.

Автор: Bulat 25.3.2014, 13:47
Цитата(Suppir @  25.3.2014,  13:42 Найти цитируемый пост)
К сожалению, не оптимальное. Каждый скрипт выдает log-файл. А теперь он еще и создает лишние txt-файлы.

Разве что стирать потом эти файлы в конце работы скрипта... 


Ок. Если придумаешь надежное решение под виндовс по твоим требованиям - меня в соавторы!  smile 

Автор: Suppir 25.3.2014, 13:50
Договорились smile

Автор: tzirechnoy 25.3.2014, 15:45
Цитата
Как?  


Например, 
Код
open(my $LOG, "-|",$item);
while (<$LOG>) { };

Автор: Romikgy 25.3.2014, 16:59
Код

system($item." > $item.temp && del $item.temp ")

Автор: alezzz 25.3.2014, 19:18
А почему вывод перенаправляется с созданием нового файла? Может system($item." >> out.temp"), такой вариант не будет под windows блочить файл? А вообще действительно нехватает /dev/null smile

Еще можно вместо system использовать `` (qx//). Тут вывод в консоль не должен попадать.

Автор: Romikgy 25.3.2014, 22:30
Цитата(alezzz @  25.3.2014,  18:18 Найти цитируемый пост)
 /dev/null

linux - /dev/null
windows - null

Автор: alezzz 26.3.2014, 00:03
Цитата(Romikgy @  25.3.2014,  22:30 Найти цитируемый пост)
windows - null

действительно есть, только nul, с одной "l"

Автор: Suppir 26.3.2014, 09:12
А может быть кто знает, как изящней вот это написать?

Код

if ($0 =~ /.+\\(.+)/){$myname = $1}


то есть получить имя скрипта без его пути. Например: c:/программы/test.pl - нужно получить "test.pl".

Автор: Bulat 26.3.2014, 09:20
Suppir, сдается мне, что это строчка под юникс писалась!  smile 

А если попробовать исправить вот так:

Код

if ($0 =~ /.+\/(.+)/){$myname = $1}

Автор: Suppir 26.3.2014, 10:27
Да нет, все под Windows написано и работает.

Я думал, может есть какая волшебная переменная для получения названия скрипта без его пути. 

Автор: Romikgy 26.3.2014, 10:31
Код

use File::Basename;
my $fname = basename($path);


Автор: tzirechnoy 26.3.2014, 10:41
Цитата
А может быть кто знает, как изящней вот это написать?


Никак. Написать это изящно -- невозможно. И не потому, что регэкспы сложные или модулей нет, а потому, что пытаться отфильтровать себя по имени -- это само посебе кривость и плохо сказывается на переносимости. Это в общем мне интуитивно-очевидно, но и так я за пять минут наткнулся на три нюанса: другие слэшы в linux, необходимость под linux  запускать ./subscript.pl по причине отсутствие . в $PATH, привычка запускать perl runner.pl, которая тожэ привела к поломке.

Правильнее -- создать поддиректорию, куда положыть либо сам запускающий скрипт, либо наоборот тех, кого нужно выполнить.

Автор: Bulat 26.3.2014, 10:43
Цитата(Suppir @  26.3.2014,  10:27 Найти цитируемый пост)
Я думал, может есть какая волшебная переменная для получения названия скрипта без его пути.  

у меня на linux $0 - дает как раз название скрипта без пути, как оно работает под виндовс - не знаю, под рукой нету!  smile 

Автор: arto 26.3.2014, 16:33
( split "[\\\\/]", $0 )[-1];

Автор: Suppir 26.3.2014, 20:31
у меня на linux $0 - дает как раз название скрипта без пути, как оно работает под виндовс - не знаю, под рукой нету!  

Windows дает полный путь по $0.

Добавлено через 1 минуту и 28 секунд
 другие слэшы в linux, 

С этими сдешами беда. Я пишу одновременно на c#, perl и AutoIt. Везде приходится по-разному писать smile Хотя c#, вроде, и так, и эдак понимает.

Добавлено через 1 минуту и 47 секунд
arto, 
шутку юмора заценил smile

Добавлено через 3 минуты и 32 секунды
В общем, я попробовал позапускать скрипты в многопоточном режиме. На двухядерном процессоре E7300 преимущество в 1,5 - 2 раза по сравнению с последовательным запуском. Думаю, что на i5 или i7 преимущество будет в 3 - 4 и более раз. 

Powered by Invision Power Board (http://www.invisionboard.com)
© Invision Power Services (http://www.invisionpower.com)