не так много опыта в кодинге, но попробую обьяснить.
Есть файл "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
Проще запоминать последнюю отработанную строку в файле и при следующем запуске начинать с нее.
хм, а как это можно здесь сделать?
> хм, а как это можно здесь сделать?Как мне видится, скрипт должен дергаться по какому-то событию, например по 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
Сорри, в последнем куске кода должно быть:
for dir_name in $(tail -n $not_processed_lines file_name | grep var2 | awk '{print $2}'); do
mkdir -p $dir_name
....
done
>[оверквотинг удален]
> 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"
было бы гораздо надёжнее его потрошить
спасибо! похоже начинает работать, однако, у меня выдает ошибки в этом месте:
$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"
> было бы гораздо надёжнее его потрошитьСейчас потестируем рабочий вариант и если будет стабильно работать, то это будет не важно.
Но тем не менее, расскажите, почему будет надежнее?
> Но тем не менее, расскажите, почему будет надежнее?А потому, что будет не просто всем сёстрам по серьгам, а
будет конкретным сёстрам конкретные серьги.user1 2013-01-014234 http://ya.ru
user2 2013-01-033122 http://google.ruПрочитал строку, а в ней сразу указано какому юзеру что и куда.
Значения в строке файла должны быть разделены пробелами,
url для закачки без кавычек.#!/usr/bin/perluse 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);
}Закачиваете странички или файлы?
Кто или что формирует дополняемый файл?
закачиваются файлы.
файл со списком имен и урлов формируется другим скриптом.
я его немного переделал и теперь он формирует данные в виде: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]...Просто интересно - насколько это критично?
>[оверквотинг удален]
> 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/perluse 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);
}
Есть ещё чо пожевать? ))
блин, спасибо большое! оно действительно работает!:)
Еще я сейчас заметил, что в случае если в дополняемом файле значение $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"`;
>[оверквотинг удален]
> то все летит в папку 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";
ну и дальше по коду поправить
> имя пользователя уникально?
> ну так сразу создавать директорию
> mkdir "$r_dir/$dir-$usr";
> ну и дальше по коду поправитьsed -i ".bak" 's|/$dir|/$dir-$usr|g' work.pl