Тема : [?] Проверка обновлений и их "раскидывание" по папкам


shr_eax  04-11-2007 18:34
Дано:
Есть раздел FISH в котором постоянно добавляются (иногда и удаляются) файлы и папки (конкретно - вручную отбираемые файлы со спутниковой рыбалки).

Требуется:
Периодически проверяя содержимое раздела FISH, создавать в другом разделе FISH_NEW структуру каталогов и символические ссылки на вновь появляющиеся файлы и папки из раздела FISH.
В FISH_NEW новые папки и файлы должны помещаться в корневые папки вида "ГГ-ММ-ДД" (т.е. папка - значение текущей даты) и соответственно отбираться по критерию "то что появилось с последней проверки на текущий момент".

Есть ли готовые решения данной задачи?

Если нет (скорее всего), то я написал небольшой shell-скрипт с использованием find+sort/comm/awk и хранением списка файлов в текстовом виде. Но есть проблема - comm срабатывает на различие строк с привязкой к их позициям. Требуется утилита (или скрипт) которые бы убирали строки из первого файла, которые есть во втором.

redflag  05-11-2007 01:08
Требуется утилита (или скрипт) которые бы убирали строки из первого файла, которые есть во втором.
не без помощи bash cookbook получилось вот такое решение

$ cat left
record_01
record_02.left only
record_03
record_05.differ
record_06
record_07
record_08
record_09
record_10
$ cat right
cat right
record_01
record_02
record_04
record_05
record_06.differ
record_07
record_08
record_09.right only
record_10
$ diff --unchanged-line-format= --new-line-format= left right
record_02.left only
record_03
record_05.differ
record_06
record_09
$

shr_eax  05-11-2007 17:08
Хе, какие хитрые параметры у diff - заханырили так, шо найти можно только глубоко в недрах info. Спасибо, всё работает :sur:

shr_eax  19-09-2009 22:02
Вобщем, получилось сделать нормально работающий скрипт. Из требований - нужны утилиты sed, awk, find, bash (возможно сработает на sh, но не проверял).

Параметры, которые следует менять:
WHATSNEW_HOME - папка где будет лежать файл с базой по файлам (а также временные файлы при работе скрипта)
TMPCHK - название временного файла
CURCHK - название файла, где будет храниться база по файлам
LINKS - папка, в которой будут создаваться симлинки на новые файлы
CHECK_DIR - собственно, папка, которую проверяют на обновления (у меня это папка с кучей симлинков на смонтированные разделы, основная шара в самбе)

Также, если необходимо исключить некоторые папки на проверку обновлений, то следует поправить части кода, где находится:
find -L "$CHECK_DIR" \
-not -path '/mnt/_share/fish/fish_сырая/*' \
-not -path '/mnt/_share/nevod_по_датам/*' \
-type f > "$CURCHK"

Здесь, /mnt/_share/fish/fish_сырая/* и /mnt/_share/nevod_по_датам/* - это папки, которые исключаются из проверки. Если исключений не надо - просто уберите эти две строки, оставив:

find -L "$CHECK_DIR" \
-type f > "$CURCHK"



Сам скрипт:
#!/bin/bash

DATE=`date +%y-%m-%d`

WHATSNEW_HOME="/etc/whatsnew"
TMPCHK="$WHATSNEW_HOME/nevod_tmpchk"
CURCHK="$WHATSNEW_HOME/nevod_curchk"

LINKS="/mnt/_share/nevod_по_датам"
CHECK_DIR="/mnt/_share"

if test ! -d "$LINKS" ; then
echo "No links basedir!"
exit
fi

if test ! -d "$CHECK_DIR" ; then
echo "No check dir!"
exit
fi

LINKS_BASEDIR="$LINKS/$DATE/"
TMP2="$WHATSNEW_HOME/tmp2"

# Если до этого совсем не было проверок - создаём первую и выходим
if test ! -f "$CURCHK" ; then
echo "Creating new curchk.."
find -L "$CHECK_DIR" \
-not -path '/mnt/_share/fish/fish_сырая/*' \
-not -path '/mnt/_share/nevod_по_датам/*' \
-type f > "$CURCHK"
exit
fi

if test ! -f "$TMPCHK" ; then
rm -f "$TMPCHK"
fi

CHECK_DIR_LNG=`awk 'BEGIN {print length("'$CHECK_DIR'")+1}'`

echo "Checking current state.."
find -L "$CHECK_DIR" \
-not -path '/mnt/_share/fish/fish_сырая/*' \
-not -path '/mnt/_share/nevod_по_датам/*' \
-type f > "$TMPCHK"

# Если текущее состояние такое же как и прежде - выходим
echo "Check for difference.."
# Создадим временный файл с различиями для ускорения обработки
if diff --unchanged-line-format= --new-line-format= --speed-large-files "$TMPCHK" "$CURCHK" > "$TMP2" ; then
rm -f "$TMPCHK"
rm -f "$TMP2"
echo "There's no difference"
exit
fi

#ЗЫ: \42 это "
#ЗЫ: \47 это '

# Создаём структуру директорий
echo "Creating directories.."
cat "$TMP2" | \
# Заменяем все ' на '\''
sed 's/'\''/'\''\\'\'\''/g' | \
# Откидываем имя файла и оставляем только путь
awk '{system("dirname \47"$0"\47")}' | \
# Делаем пути уникальными
uniq | \
sed 's/'\''/'\''\\'\'\''/g' | \
# Собственно создаём каталог
awk '{system("mkdir -p \47'$LINKS_BASEDIR'"substr($0,'$CHECK_DIR_LNG')"\47")}'

# Создаём символические ссылки
echo "Creating symbolic links.."
cat "$TMP2" | \
sed 's/'\''/'\''\\'\'\''/g' | \
awk '{system("ln -s \47"$0"\47 \47'$LINKS_BASEDIR'"substr($0,'$CHECK_DIR_LNG')"\47")}'

rm -f "$TMP2"
mv -f $TMPCHK $CURCHK


Как он работает - при первом запуске создаёт базу и выходит. При повторном и последующих запусках создаёт временную базу, сравнивает с основной, различия (новые файлы) появляются в папке LINKS, в которой сначала создаётся подпапка с именем вроде 09-09-19 (т.е. 19 сентября 2009, дата проверки), а в ней подпапки до нового файла и симлинк на него.
Т.е. например, в папке /mnt/_share/mp3/__unsorted_7/_pump появился новый файл Markus_Schulz_-_Global_DJ_Broadcast_2009.07.23.mp3, тогда в LINKS директории будут создано следующее дерево папок: /mnt/_share/nevod_по_датам/09-09-19/mp3/__unsorted_7/_pump. Внутри последней будет лежать симлинк: Markus_Schulz_-_Global_DJ_Broadcast_2009.07.23.mp3 -> /mnt/_share/mp3/__unsorted_7/_pump/Markus_Schulz_-_Global_DJ_Broadcast_2009.07.23.mp3

Скрипт вешаем по крону, но только чтобы не особо часто выполнялся, т.к. винты сильно напрягаются во время проверки.