URL: https://www.opennet.me/cgi-bin/openforum/vsluhboard.cgi
Форум: vsluhforumID9
Нить номер: 9824
[ Назад ]

Исходное сообщение
"как сделать чтобы цикл не останавливался"

Отправлено gorlum300 , 02-Фев-14 16:47 
не так много опыта в кодинге, но попробую обьяснить.
Есть файл "test" куда периодически дописываются новые данные в виде блоков по 3 строки:
var1 frog32
var2 2013-01-014234
var3 "url"
var1 rabit1
var2 2013-01-033122
var3 "url2"
итд
Задача периодически читать этот файл и для новых данных создавать директорию по имени значения следующего после var2, куда записывать текстовый файл с именем после var1 и скачивать файл следующий после var3.

Пока у меня получился следующий скрипт, однако, он создает текстовые файлы всех значений var1 из всего файла в каждой новой директории.
Как бы сделать так, чтобы второй цикл не завершал работу, а как бы приостанавливал, и когда 1й цикл опять создает новую директорию, продолжал просматривать файл с того же места?
Или мб есть другое решение чтобы в каждой директории был только 1 текстовый файл соответствующий своему блоку данных?

#!/bin/bash

DIR1=/home/user/aaa

for i in $(grep var2 $DIR1/test|awk '{print $2}');
do mkdir $i;
cd $i;
   for name in $(grep var1 $DIR1/test|awk '{print $2}'); do
   if [ -f "$DIR1/$i/$name" ];
    then echo have;
    else
   touch $name;
   fi
   done;
   cd $DIR1;
done


Содержание

Сообщения в этом обсуждении
"как сделать чтобы цикл не останавливался"
Отправлено rew , 02-Фев-14 17:44 
Проще запоминать последнюю отработанную строку в файле и при следующем запуске начинать с нее.

"как сделать чтобы цикл не останавливался"
Отправлено gorlum300 , 02-Фев-14 19:16 
хм, а как это можно здесь сделать?

"как сделать чтобы цикл не останавливался"
Отправлено skb7 , 02-Фев-14 22:30 
> хм, а как это можно здесь сделать?

Как мне видится, скрипт должен дергаться по какому-то событию, например по cron'у, или по событию изменения файла. Скрипт должен обрабатывать строки с последней обработанной (в предыдущем запуске скрипта) и до конца файла.

После того как обработали файл, сохранить номер последней обработанной строки:


last_processed_line=$(wc -l file_name | awk '{print $1}')

и сохранить в свой файл (для примера пусть будет "my_file.txt") в /var/tmp/:


echo -n $last_processed_line >/var/tmp/my_file.txt

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


last_processed_line=$(cat /var/tmp/my_file.txt)

Дальше надо вычислить сколько строк не обработано на данный момент:


line_count=$(wc -l file_name | awk '{print $1}')
not_processed_lines=$((line_count - last_processed_line))

Вывести и обработать только необработанные строки:


for dir_name in $(tail -n $not_processed_lines file_name | grep var2 | awk '{print $2}');
    mkdir -p $dir_name
    ....
do
    
done


"как сделать чтобы цикл не останавливался"
Отправлено skb7 , 03-Фев-14 01:08 
Сорри, в последнем куске кода должно быть:

for dir_name in $(tail -n $not_processed_lines file_name | grep var2 | awk '{print $2}'); do
    mkdir -p $dir_name
    ....
done


"как сделать чтобы цикл не останавливался"
Отправлено михалыч , 03-Фев-14 20:53 
>[оверквотинг удален]
> var1 frog32
> var2 2013-01-014234
> var3 "url"
> var1 rabit1
> var2 2013-01-033122
> var3 "url2"
> итд
> Задача периодически читать этот файл и для новых данных создавать директорию по
> имени значения следующего после var2, куда записывать текстовый файл с именем
> после var1 и скачивать файл следующий после var3.

Похоже как на менеджер закачек файлов по запросу.
Попробовал на perl
Вроде взлетает и летит ))
Но есть подводные камни ((
какие файлы закачиваются - большие, маленькие?
проверять на обрыв закачки?
что будет если закачка прервётся?

#!/usr/bin/perl

use strict;
use warnings;


my ($usr, $dir, $url);

# корневая директория
my $r_dir = "/tmp";
# дополняемый файл
my $file = "/tmp/txt";

open FH, $file or die "can't open $file: $!";

for (;;) {
    exit if (stat(FH))[3] == 0;

    while (<FH>) {
        chomp;

        if (/var1/) {
            s/^var1\s(.*)$/$1/;
            $usr = $1;
        }

        if (/var2/) {
            s/^var2\s(.*)$/$1/;
            $dir = $1;
        }

        if (/var3/) {
            s/^var3\s(.*)$/$1/;
            $url = $1;

            # название файла для закачки
            my $out = $url;
            # обрезаем его  - из "http://ya.ru" получаем ya.ru
            $out =~ s|.*/(.*)\"|$1|;

            mkdir "$r_dir/$dir";
            `touch "$r_dir/$dir/$usr"`;
            `wget -O "$r_dir/$dir/$out" $url`;
        }
    }

    sleep "1";
    seek (FH, 0, 1);
}

Лучше было бы писать в дополняемый файл строки массивчиками
user date url
типа
frog32 2013-01-014234 "url"
было бы гораздо надёжнее его потрошить


"как сделать чтобы цикл не останавливался"
Отправлено gorlum300 , 03-Фев-14 23:06 
спасибо! похоже начинает работать, однако, у меня выдает ошибки в этом месте:
            $out =~ s|.*/(.*)\"|$1|;

            mkdir "$r_dir/$dir";
            `touch "$r_dir/$dir/$usr"`;
           `wget -O "$r_dir/$dir/$out" $url`;
---
Global symbol "$out" requires explicit package name at ./workp.pl line 38.
Global symbol "$out" requires explicit package name at ./workp.pl line 42.

я вот неуверен, что это значит?

> какие файлы закачиваются - большие, маленькие?
> проверять на обрыв закачки?
> что будет если закачка прервётся?

закачиваются небольшие файлы по 50-500kb.
в идеале, конечно, нужно попробовать добавить вторую попытку скачать, и в случае если закачка не идет(идет не до конца), создавать файл с именем типа warning в директории куда скачиваются файлы.

> Лучше было бы писать в дополняемый файл строки массивчиками
> user date url
> типа
> frog32 2013-01-014234 "url"
> было бы гораздо надёжнее его потрошить

Сейчас потестируем рабочий вариант и если будет стабильно работать, то это будет не важно.
Но тем не менее, расскажите, почему будет надежнее?


"как сделать чтобы цикл не останавливался"
Отправлено михалыч , 04-Фев-14 12:23 
> Но тем не менее, расскажите, почему будет надежнее?

А потому, что будет не просто всем сёстрам по серьгам, а
будет конкретным сёстрам конкретные серьги.

user1 2013-01-014234 http://ya.ru
user2 2013-01-033122 http://google.ru

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

#!/usr/bin/perl

use strict;
use warnings;


my ($usr, $dir, $url, $out);

# корневая директория
my $r_dir = "/tmp";

# дополняемый файл вида разделён пробелами
# user1 date url
# user2 date url
my $file = "/tmp/txt";

open FH, $file or die "can't open $file: $!";

for (;;) {
    # вываливаемся если дополняемый файл вдруг удалили или он исчез ))
    exit if (stat(FH))[3] == 0;

    while (<FH>) {
        chomp;

        # разбиваем входную строку split'ом по пробелам и складывем в массив
        my @str = split(" ", $_);

        $usr = $str[0]; # название юзера
        $dir = $str[1]; # директория по дате и времени
        $url = $str[2]; # линк для закачки файла

        $out = $url;             # выходной файл для записи в него загрузки через wget
        $out =~ s|^.*/(.*)$|$1|; # обрезаем его, делаем из http://ya.ru только ya.ru

        # создаём директорию по дате
        mkdir "$r_dir/$dir";
        # создаём файл по имени юзера
        `touch "$r_dir/$dir/$usr"`;

        # путь к исполняемому файлу wget и параметры закачки
        # wget -q (тихий режим) -t 1 (1 повтор при неудаче) -O сохранить в файл
        my $wget = "/usr/bin/wget -q -t 1 -O \"$r_dir/$dir/$out\" $url";
        # если загрузка неудачна - удаляем выходной файл и создаем файл warning
        unlink "$r_dir/$dir/$out" and `touch "$r_dir/$dir/warning"` if system $wget;
    }
    # спать. спать.. спать... ))
    sleep "1";
    # читаем файл до конца, сбрасываем флаг EOF
    seek (FH, 0, 1);
}

Закачиваете странички или файлы?
Кто или что формирует дополняемый файл?


"как сделать чтобы цикл не останавливался"
Отправлено gorlum300 , 04-Фев-14 14:55 
закачиваются файлы.
файл со списком имен и урлов формируется другим скриптом.
я его немного переделал и теперь он формирует данные в виде:

user1 2013-01-014234 http://ya.ru http://google.com
user2 2013-01-013311 http://ya2.ru http://google2.com

добавился еще один урл
Неуверен насколько правильно, но я добавил закачку второго урла в код, выдает ошибки но все работает:

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


my ($usr, $dir, $url, $url2, $out, $out2);


my $r_dir = "~/Downloads";


my $file = "~/Downloads/txt";

open FH, $file or die "can't open $file: $!";

for (;;) {

    exit if (stat(FH))[3] == 0;

    while (<FH>) {
        chomp;

        my @str = split(" ", $_);

        $usr = $str[0];
        $dir = $str[1];
        $url = $str[2];
        $url2 = $str[3];

        $out = $url;
        $out =~ s|^.*/(.*)$|$1|;
        $out2 = $url2;
        $out2 =~ s|^.*/(.*)$|$1|;


        mkdir "$r_dir/$dir";

        `touch "$r_dir/$dir/$usr"`;

        my $wget = "wget -q -t 1 -O \"$r_dir/$dir/$out\" $url";
        my $wget1 = "wget -q -t 1 -O \"$r_dir/$dir/$out2\" $url2";
        unlink "$r_dir/$dir/$out" and `touch "$r_dir/$dir/warning"` if system $wget;
        unlink "$r_dir/$dir/$out2" and `touch "$r_dir/$dir/warning-big"` if system $wget1;
    }

    sleep "1";

    seek (FH, 0, 1);
exit;
}

ошибки вида:
Use of uninitialized value $out in substitution (s///) at ./work2.pl line 31, <FH> line 3.
Use of uninitialized value $out2 in substitution (s///) at ./work2.pl line 33, <FH> line 3.
Use of uninitialized value $dir in concatenation (.) or string at ./work2.pl line 36, <FH> line 3.
Use of uninitialized value $dir in concatenation (.) or string at ./work2.pl line 38, <FH> line 3.
Use of uninitialized value $usr in concatenation (.) or string at ./work2.pl line 38, <FH> line 3.
Use of uninitialized value $dir in concatenation (.) or string at ./work2.pl line 40, <FH> line 3.
Use of uninitialized value $out in concatenation (.) or string at ./work2.pl line 40, <FH> line 3.
Use of uninitialized value $url in concatenation (.) or string at ./work2.pl line 40, <FH> line 3.
Use of uninitialized value $dir in concatenation (.) or string at ./work2.pl line 41, <FH> line 3.
Use of uninitialized value $out2 in concatenation (.) or string at ./work2.pl line 41, <FH> line 3.
Use of uninitialized value $url2 in concatenation (.) or string at ./work2.pl line 41, <FH> line 3.
wget: missing URL
Usage: wget [OPTION]... [URL]...

Просто интересно - насколько это критично?


"как сделать чтобы цикл не останавливался"
Отправлено михалыч , 04-Фев-14 16:41 
>[оверквотинг удален]
> Use of uninitialized value $usr in concatenation (.) or string at ./work2.pl line 38, <FH> line 3.
> Use of uninitialized value $dir in concatenation (.) or string at ./work2.pl line 40, <FH> line 3.
> Use of uninitialized value $out in concatenation (.) or string at ./work2.pl line 40, <FH> line 3.
> Use of uninitialized value $url in concatenation (.) or string at ./work2.pl line 40, <FH> line 3.
> Use of uninitialized value $dir in concatenation (.) or string at ./work2.pl line 41, <FH> line 3.
> Use of uninitialized value $out2 in concatenation (.) or string at ./work2.pl line 41, <FH> line 3.
> Use of uninitialized value $url2 in concatenation (.) or string at ./work2.pl line 41, <FH> line 3.
> wget: missing URL
> Usage: wget [OPTION]... [URL]...
> Просто интересно - насколько это критично?

не критично
это в результате попытки использовать неинициализированные переменные, нужно сделать проверку на существование $dir, $out, $url
видимо попадаются строки только с юзером без dir и/или url типа
user
user dir

#!/usr/bin/perl

use strict;
use warnings;


my ($usr, $dir, $url, $url2, $out, $out2);

# корневая директория
my $r_dir = "/tmp";

# дополняемый файл вида разделён пробелами
# user1 date url url2
# user2 date url url2
my $file = "/tmp/txt";

open FH, $file or die "can't open $file: $!";

for (;;) {
    # вываливаемся если дополняемый файл вдруг удалили или он исчез ))
    exit if (stat(FH))[3] == 0;

    while (<FH>) {
        chomp;

        # разбиваем входную строку split'ом по пробелам и складывем в массив
        my @str = split(" ", $_);

        $usr = $str[0]; # название юзера
        $dir = $str[1]; # директория по дате и времени
        $url = $str[2]; # линк для закачки файла
        $url2= $str[3]; # линк для закачки файла

        # если нет $usr или $dir дальнейшее безсмысленно, переходим к следующей строке
        next if !defined $usr or !defined $dir;

        # если нет $url и $url2 дальнейшее безсмысленно, переходим к следующей строке
        next if !defined $url and !defined $url2;

        # создаём директорию по дате
        mkdir "$r_dir/$dir";
        # создаём файл по имени юзера
        `touch "$r_dir/$dir/$usr"`;

        # если переменная $url определена - делаем вещи
        if (defined $url) {
            $out = $url;             # выходной файл для записи в него загрузки через wget
            $out =~ s|^.*/(.*)$|$1|; # обрезаем его, делаем из http://ya.ru только ya.ru

            # путь к исполняемому файлу wget и параметры закачки
            # wget -q (тихий режим) -t 1 (1 повтор при неудаче) -O сохранить в файл
            my $wget = "/usr/local/bin/wget -q -t 1 -O \"$r_dir/$dir/$out\" $url";
            # если загрузка неудачна - удаляем выходной файл и создаем файл warning
            unlink "$r_dir/$dir/$out" and `touch "$r_dir/$dir/warning"` if system $wget;
        }

        # если переменная $url2 определена - делаем вещи
        if (defined $url2) {
            $out2 = $url2;            # выходной файл для записи в него загрузки через wget
            $out2 =~ s|^.*/(.*)$|$1|; # обрезаем его, делаем из http://ya.ru только ya.ru

            # путь к исполняемому файлу wget и параметры закачки
            # wget -q (тихий режим) -t 1 (1 повтор при неудаче) -O сохранить в файл
            my $wget2 = "/usr/local/bin/wget -q -t 1 -O \"$r_dir/$dir/$out2\" $url2";
            # если загрузка неудачна - удаляем выходной файл и создаем файл warning2
            unlink "$r_dir/$dir/$out2" and `touch "$r_dir/$dir/warning2"` if system $wget2;
        }
    }
    # спать. спать.. спать... ))
    sleep "1";
    # читаем файл до конца, сбрасываем флаг EOF
    seek (FH, 0, 1);
}


Есть ещё чо пожевать? ))

"как сделать чтобы цикл не останавливался"
Отправлено gorlum300 , 04-Фев-14 21:37 
блин, спасибо большое! оно действительно работает!:)
Еще я сейчас заметил, что в случае если в дополняемом файле значение $dir для нескольких юзеров одинаковое (это таймстемп) то все складывается в одну директорию.

те если например:
user1 2013-01-014234 http://ya.ru
user2 2013-01-014234 http://google.ru

то все летит в папку 2013-01-014234
я думаю как бы сделать проверку для одинаковых имен и в случае если такое уже есть, то создавать такое же, но с дополнением (напр., 2013-01-014234-duble)
что-то вроде:

        if (-d "$dir")
        { print "dublicate";
        mkdir "$r_dir/$dir";
        rename "$r_dir/$dir","$r_dir/$dir,duble";
       `touch $r_dir/$dir,duble/$usr"`;


"как сделать чтобы цикл не останавливался"
Отправлено михалыч , 04-Фев-14 22:36 
>[оверквотинг удален]
> то все летит в папку 2013-01-014234
> я думаю как бы сделать проверку для одинаковых имен и в случае
> если такое уже есть, то создавать такое же, но с дополнением
> (напр., 2013-01-014234-duble)
> что-то вроде:
>         if (-d "$dir")
>         { print "dublicate";
>         mkdir "$r_dir/$dir";
>         rename "$r_dir/$dir","$r_dir/$dir,duble";
>        `touch $r_dir/$dir,duble/$usr"`;

имя пользователя уникально?
ну так сразу создавать директорию
mkdir "$r_dir/$dir-$usr";
ну и дальше по коду поправить


"как сделать чтобы цикл не останавливался"
Отправлено михалыч , 05-Фев-14 05:21 
> имя пользователя уникально?
> ну так сразу создавать директорию
> mkdir "$r_dir/$dir-$usr";
> ну и дальше по коду поправить

sed -i ".bak" 's|/$dir|/$dir-$usr|g' work.pl