Вы пробовали Evolution? http://projects.gnome.org/evolution/index.shtml
Я никогда не использовал его, но он должен поддерживать подключение к Exchange.
Если Вы используете bash
в качестве своей оболочки, то shopt -s extglob
может активировать еще некоторые опции в шаблонах шарика. Например
!(5e1adcf7c9c1bcf8842c24f3bacbf169*|5e2497180424aa0d5a61c42162b03fef*)
будет соответствовать всем именам, не запускающимся с одной из двух строк.
При записи вопроса я начал играть вокруг с grep
. Часть проблемы производительности - то, что grep выполняет тонну поисков regex каждого файла. Это дорого .
Мы можем просто сделать полные поиски строки без regex, с помощью -F
аргумент.
find | grep -vFf <(
sqlite3 database.sqlite3 'select replace(images, CHAR(124), CHAR(10)) from cars_car'
) ### | xargs rm
вывод является тем же и работает в 0,045 с.
старый занял 14,211 с.
Одной из проблем с парсингом ls
являются проблематичные имена файлов. комментарий muru ниже выделяет довольно достойный способ использовать нулевые символы через весь конвейер.
find -print0 | grep -vzFf <(
sqlite3 database.sqlite3 'select replace(images, CHAR(124), CHAR(10)) from cars_car'
) ### | xargs -0 rm
причина я не переключаюсь, мой основной ответ на это - то, что я знаю, что мои файлы всегда будут чистыми и что я выполнял это в wc -l
, чтобы удостовериться, что я вижу корректное количество файлов для удаления.
find . -iname '*.jpg' -print0 | grep -vzFf <(sqlite3 database.sqlite3 'select images from cars_car;' | sed 's/|/\n/g') | xargs -0 rm
? Начиная с фиксированного сопоставления строк doesn' t автоматически подразумевают соответствие целого слова, таким образом foo
отфильтрует и foo.jpg
и foo_tn.jpg
.
– James C.
22.03.2015, 14:05
wc -l
) немного более жесткий.
– dtbarne
22.03.2015, 14:14
Вы могли просто удалить изображения в рамках выполнения сценария удаления продукта. Таким образом, загрузка будет балансироваться через каждое удаление продукта со временем. Дополнительно Вы не должны будете волноваться о выполнении сценария для чистки их вообще, и целое приложение будет автономной системой. Не говоря уже о нем решил бы проблему пространства с этой целью.
я понятия не имею, о котором DBMS Вы используете, ни о котором языке сценариев Вы используете для управления им или о том, как структура базы данных похожа (никакая идея о пути изображений также), но например, принимая MySQL
как DBMS, PHP
как язык сценариев и Products
таблица в 1-many отношениях с Images
таблица, с путем изображений, указывающим img
папка, помещенная под корневым каталогом, это было бы что-то вроде этого:
<?php
// ...
$imgPath = $SERVER['DOCUMENT_ROOT'].'/img/';
$result = mysqli_query($link, "SELECT Images.basename FROM Products, Images WHERE Products.productId = Images.productId AND Products.productId = $productId)
while($row = mysqli_fetch_assoc($result)) {
unlink($imgPath.$row['Images.basename'].'.jpg');
unlink($imgPath.$row['Images.basename'].'_tn.jpg');
}
// ...
?>
, Если Вы заинтересованы [приблизительно 117] действия, Вы могли бы всегда использовать:
<?php
// ...
$imgPath = $SERVER['DOCUMENT_ROOT'].'/img/';
$result = mysqli_query($link, "SELECT Images.basename FROM Products, Images WHERE Products.productId = Images.productId AND Products.productId = $productId)
while($row = mysqli_fetch_assoc($result)) {
shell_exec("rm {$imgPath}{$row['Images.basename']}*");
}
// ...
?>
Опасения по поводу них решение могло бы быть о дополнительном запросе, который необходимо будет выполнить каждый раз, если Вы уже не вытягиваете от Images
прежде в сценарии и если это - беспокойство вообще.
Я предположил бы, что это будет и более простым и быстрее, чтобы просто использовать GLOBIGNORE
(предположение, что Ваша оболочка является ударом так или иначе):
GLOBIGNORE
A colon-separated list of patterns defining the set of filenames
to be ignored by pathname expansion. If a filename matched by a
pathname expansion pattern also matches one of the patterns in
GLOBIGNORE, it is removed from the list of matches.
Так, Вы могли просто считать шаблоны, которые Вы хотите из своего файла, добавляете *
для создания их, шарики и преобразовать в двоеточие разделили список:
GLOBIGNORE=$(sqlite3 database.sqlite3 'select images from cars_car;' |
sed 's/|/*:/g; s/$/*/')
Затем Вы можете всего rm
все, и сбросить GLOBIGNORE (или просто закрыть текущий терминал):
rm * && GLOBIGNORE=""
, поскольку GLOBIGNORE
будет теперь похож на это:
$ echo $GLOBIGNORE
5e1adcf7c9c1bcf8842c24f3bacbf169*:5e2497180424aa0d5a61c42162b03fef*
Любые файлы, соответствующие тем шарикам, не будут включены в расширение *
. Это обладает дополнительным преимуществом работы с любым типом имени файла, включая тех с пробелами, новыми строками или другими странными символами.
Долгосрочное решение, к которому я допускаю ошибку, является чем-то в конце моего сценария обновления (Python/Django). У меня есть список Автомобильных объектов — так больше базы данных querying—, который делает это еще быстрее. Это также происходит в точное время, старые изображения прекращают быть полезными.
я использую Python set
, потому что это - вероятно, самый быстрый способ проверить. В это я добавляю все тупики изображений, которые я хочу сохранить, затем я выполняю итерации через миниатюры (легче к шарику) и удаляю файлы, которые не находятся в наборе.
# Generate a python "set" of image stubs
import itertools
imagehashes = set(itertools.chain(*map(lambda c: c.images.split('|'), cars)))
# Check which files aren't in the set and delete
import glob, os
for imhash in map(lambda i: i[25:-7], glob.glob('/path/to/images/*_tn.jpg')):
if imhash in imagehashes:
continue
os.remove('/path/to/images/%s_tn.jpg' % imhash)
os.remove('/path/to/images/%s.jpg' % imhash)
существует несколько приемов с map
и itertools
, чтобы сэкономить немного времени, но это главным образом сам объяснительное.
Когда чистый удар не сокращает его (или становится излишне неловким), пора переключиться на надлежащий язык сценариев. Мой предпочтительный инструмент обычно является Perl, но Вы могли использовать Python или Ruby или, heck, даже PHP для этого, если Вы предпочтете.
Однако вот простой сценарий Perl, который читает список префиксов от stdin (так как Вы не определили точно, как Вы получаете этот список), один на строку, и удаляет все файлы в текущем каталоге с .jpg
суффикс, которые не имеют одного из этих префиксов:
#!/usr/bin/perl
use strict;
use warnings;
my @prefixes = <>;
chomp @prefixes;
# if you need to do any further input mangling, do it here
my $regex = join "|", map quotemeta, @prefixes;
$regex = qr/^($regex)/; # anchor the regex and precompile it
foreach my $filename (<*.jpg>) {
next if $filename =~ $regex;
unlink $filename or warn "Error deleting $filename: $!\n";
}
, Если Вы предпочли бы, можно сжать это вниз до остроты, например:
perl -e '$re = "^(" . join("|", map { chomp; "\Q Когда чистый удар не сокращает его (или становится излишне неловким), пора переключиться на надлежащий язык сценариев. Мой предпочтительный инструмент обычно является Perl, но Вы могли использовать Python или Ruby или, heck, даже PHP для этого, если Вы предпочтете.
Однако вот простой сценарий Perl, который читает список префиксов от stdin (так как Вы не определили точно, как Вы получаете этот список), один на строку, и удаляет все файлы в текущем каталоге с .jpg
суффикс, которые не имеют одного из этих префиксов:
[110] , Если Вы предпочли бы, можно сжать это вниз до остроты, например:
[111] <час> ps В Вашем случае, так как достаточно легко извлечь префикс из имен файлов, Вы могли также использовать хеш вместо regex для оптимизации поиска, как это:
my %hash;
undef @hash{@prefixes}; # fastest way to add keys to a hash
foreach my $filename (<*.jpg>) {
my ($prefix) = ($filename =~ /^([0-9a-f]+)/);
next if exists $hash{$prefix};
unlink $filename or warn "Error deleting $filename: $!\n";
}
Однако даже при том, что этот метод масштабируется лучше асимптотически (по крайней мере, на практике; в теории regex механизм мог оптимизировать соответствие для масштабирования, а также метод хеша), всего для 500 префиксов вообще нет никакого заметного различия.
, По крайней мере, на текущих версиях Perl, однако, regex решение становится намного медленнее, как только количество альтернатив превышает определенный предел. Для 32-байтовых префиксов, мое тестирование показало крупный переход во время выполнения, когда количество альтернатив достигло 6553, но точный порог, по-видимому, также зависит от длины префиксов и на том, что еще, во всяком случае, содержит regex. Это - по-видимому, причуда Perl regex механизм и его оптимизатор, таким образом, другие regex реализации (даже PCRE) могут показать различное поведение.
" } <>) . ")"; unlink grep !/$re/, <*.jpg>'
<час> ps В Вашем случае, так как достаточно легко извлечь префикс из имен файлов, Вы могли также использовать хеш вместо regex для оптимизации поиска, как это:
my %hash;
undef @hash{@prefixes}; # fastest way to add keys to a hash
foreach my $filename (<*.jpg>) {
my ($prefix) = ($filename =~ /^([0-9a-f]+)/);
next if exists $hash{$prefix};
unlink $filename or warn "Error deleting $filename: $!\n";
}
Однако даже при том, что этот метод масштабируется лучше асимптотически (по крайней мере, на практике; в теории regex механизм мог оптимизировать соответствие для масштабирования, а также метод хеша), всего для 500 префиксов вообще нет никакого заметного различия.
, По крайней мере, на текущих версиях Perl, однако, regex решение становится намного медленнее, как только количество альтернатив превышает определенный предел. Для 32-байтовых префиксов, мое тестирование показало крупный переход во время выполнения, когда количество альтернатив достигло 6553, но точный порог, по-видимому, также зависит от длины префиксов и на том, что еще, во всяком случае, содержит regex. Это - по-видимому, причуда Perl regex механизм и его оптимизатор, таким образом, другие regex реализации (даже PCRE) могут показать различное поведение.
запрос быстр, таким образом, это эти
grep
бит, который срывает все это.
Другое решение состояло бы в том, чтобы просто инвертировать запрос, так, чтобы можно было передать результаты по каналу к rm
непосредственно.
Это не должно представлять различие в синхронизации вообще.