Как использовать несколько файлов одновременно с помощью Bash - PullRequest
1 голос
/ 29 ноября 2010

У меня есть Perl-скрипт, который используется для обработки некоторых файлов данных из данного каталога.Я написал ниже скрипт bash, чтобы найти последний обновленный файл в данном каталоге и обработать этот файл.

cd $data_dir
find \( -type f -mtime -1 \) -exec ./script.pl {} \;

Иногда пользователь копировал несколько файлов в каталог данных и, следовательно, предыдущий пропускал.Сценарий Perl выполняет только последний обновленный файл.Подскажите, пожалуйста, как это исправить, используя bash-скрипт.

Ответы [ 3 ]

3 голосов
/ 29 ноября 2010

Попробуйте

cd $data_dir
find \( -type f -mtime -1 \) -exec ./script.pl {} +

Обратите внимание на завершение -exec с + против вашего \;

со страницы руководства

-exec команда {} +
Этот вариант действия -exec запускает указанную команду для выбранных файлов, но командная строка создается путем добавления каждого выбранного имени файла в конце;

Теперь, когда у вас есть одно или несколько имен файлов, переданных в ваш Perl-скрипт, вы можете изменить свой Perl-скрипт для перебора каждого переданного имени файла.

1 голос
/ 29 ноября 2010

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

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

Использование любого из параметров -atime / -ctime / -mtime приведет к дублированию, если вы запустите свой скрипт дважды за указанный период,или пропустите некоторые файлы, если они не были выполнены в нужное время.Сложность синхронизации использования этих опций для чего-то подобного не так проста.

Я могу предложить несколько альтернатив:

a) Использовать три каталога вместо одного: входящий / обработка /сделанный/.Ваши пользователи должны иметь возможность только помещать файлы во входящие /.Вы перемещаете туда любые файлы для обработки / с помощью простого mv incoming/* processing/ перед запуском сценария Perl.Затем вы перемещаете их из обработки / в готовый / когда все закончится.

На мой взгляд, это самое простое и лучшее решение, и оно используется почтовыми серверами и т. Д. При решении этой проблемы.Если бы я был вами, и не было никаких особых обстоятельств, мешающих вам сделать это, я бы прекратил читать здесь.

b) У вашего сценария поиска touch специальный файл (например, .timestamp, возможно, вдругой каталог, так что ваши пользователи не будут вмешиваться), когда это будет сделано.Это позволит вашему сценарию запомнить последний раз, когда он был запущен.Затем используйте

find \( -cnewer .timestamp -o -newer .timestamp \) -type f -exec ./script.pl '{}' ';'

, чтобы запустить скрипт perl для каждого файла.Вы должны изменить свой Perl-скрипт, чтобы он мог запускаться повторно с разными именами файлов каждый раз.Если вы можете изменить его так, чтобы он принимал несколько файлов за один раз, вы также можете запустить его с

find \( -cnewer .timestamp -o -newer .timestamp \) -type f -exec ./script.pl '{}' +

, что сведет к минимуму количество процессов ./script.pl.Будьте внимательны при первом запуске сценария поиска, когда отсутствует файл .timestamp.Хорошим решением было бы просто проигнорировать это, не используя - * более новые опции в этом случае.Также имейте в виду, что существует условие состязания, когда файлы, добавленные после запуска поиска, но до прикосновения к метке времени, не будут обрабатываться.

c) В качестве варианта (b) ваш скрипт должен обновить метку временисо временем обработанного файла, который был создан / изменен совсем недавно.Это сложно, потому что find не может самостоятельно упорядочить вывод.Вы можете использовать обертку вокруг вашего Perl-скрипта для обработки этого:

#!/bin/bash

for i in "$@"; do
    find "$i" \( -cnewer .timestamp -o -newer .timestamp \) -exec touch -r '{}' .timestamp ';'
done

./script.pl "$@"

Это обновит временную метку, если она вызывается для обработки файла с более новым mtime или ctime, минимизируя (но не устраняя) гонкусостояние.Однако это несколько неловко - неизбежно, так как опция bash [[-nt, кажется, только проверяет mtime.Возможно, было бы лучше, если бы ваш скрипт perl обрабатывал это сам по себе.

d) Пусть ваш скрипт хранит где-нибудь каждое обработанное имя файла и его временные метки, а затем пропускает дубликаты.Это позволило бы вам просто передать все файлы в каталоге и позволить ему разобраться в беспорядке.Довольно сложно, хотя ...

e) Поскольку вы используете Linux, вы можете взглянуть на inotify и пакет инструментов inotify - в частности, инструмент inotifywait.С небольшим количеством сценариев это позволит вам обрабатывать файлы по мере их добавления в каталог:

inotifywait -e MOVED_TO -e CLOSE_WRITE -m -r testd/ | grep --line-buffered -e MOVED_TO -e CLOSE_WRITE | while read d e f; do ./script.pl "$f"; done

Это не имеет условий гонки, если ваши пользователи не создают / копируют / перемещают любые каталоги , а не только файлы.

0 голосов
/ 29 ноября 2010

Скрипт perl будет выполняться только для файла, который ему дает find. Возможно, вам следует удалить опцию -mtime -1 из команды find, чтобы она подхватила все файлы в каталоге?

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...