У меня есть два каталога, скажем, Directory1 и Directory2. Они оба содержат изображения с некоторыми цифрами и строкой. Каталог1 содержит размытые изображения с номером и строкой _blur, например, 001_blur.png. Он содержит около 62 тыс. Изображений. Каталог 2 содержит соответствующие изображения, например, 001_fine.png. Он содержит 60 тыс. Изображений.

Проблема в том, что я потерял некоторые размытые изображения из Directory1, которые имеют соответствующую прекрасную пару в Directory2. И я потерял несколько прекрасных изображений в Directory2, который имеет соответствующее размытое изображение в Directory1.

Теперь я хотел бы сохранить только изображения, которые имеют соответствующую пару. Я имею в виду, если одного из соответствующих изображений нет, я хотел бы удалить их, и просто поместить изображения в пары.

Итак, мой формат каталога:

Directory1
    001_blur.png
    002_blur.png
    003_blur.png
    004_blur.png

Directory2
    001_fine.png
    002_fine.png
    003_fine.png
    005_fine.png

Примечание: я хотел бы оставить пару 001, пару 002 и пару 003. Я хотел бы скопировать размытие в Directory3 и хорошо в Directory4.

Я думаю, что эта проблема также имеет некоторую алгоритмическую сложность, так как изображения имеют размер около 60 КБ в каждой папке. Если я возьму одно изображение из Directory1 и попытаюсь найти соответствующее хорошее изображение в Directory2, я думаю, что сложность высока. Итак, как мне справиться с этой алгоритмической сложностью?

4 ответа4

1

Подход allo для чтения содержимого каталогов один раз, анализа текстовых данных и удаления файлов в конце кажется хорошим. Однако этот ответ, кажется, не признает разницу между именами файлов в двух каталогах (blur и fine).

Ваши файлы именуются в соответствии с шаблонами, поэтому их имена не должны содержать неприятных сюрпризов, таких как непечатные символы, символы новой строки или что-то в этом роде. Парсинг ls должен быть безопасным, но в общем случае этого делать не следует. Я хотел бы дать общее решение , поэтому я не буду разбирать ls здесь. Я буду использовать строки с нулевым символом в конце , поэтому все ключи, такие как -print0 и -z .

Давайте начнем. Вам нужно только корректировать пути в объявлениях переменных, если вы не копируете их в другую файловую систему. Если это так, вы также должны настроить cp -l . Сначала прочтите комментарии. Я советую вам вставить весь кодовый блок в файл, настроить его, а затем выполнить его или выполнить.

#/bin/bash

# Declare variables.
dir1="/your/directory1/"
dir2="/your/directory2/"
dir3="/your/new/directory3/" # Use absolute paths at least for dir3...
dir4="/your/new/directory4/" # and dir4.
core1=blur
core2=fine

# Create temporary file.
tmpf=$(mktemp)

# Get null-terminated local paths from dir1.
# Note the line doesn't end yet thanks to \.
{ (cd "$dir1"; find -maxdepth 1 -type f -iname "*${core1}*" -print0) ; \

# Add null-terminated local paths from dir2
# (the line continues because of the trailing |)
(cd "$dir2"; find -maxdepth 1 -type f -iname "*${core2}*" -print0) |

# but convert core2 to core1, so the names are all with core1.
# Note the output of the two finds is gathered by {} and piped...
sed -z "s|${core2}|${core1}|" ; } |

# ...to sort and uniq. With uinq -d we print only duplicates, only once.
sort -z | uniq -zd > "$tmpf"

# Note how long this one line was.

# At this moment tmpf lists all the files we need to copy to dir3.
# The filenames are local to dir1, so we have to cd temporarily.
# dir3 will be resolved from dir1, that's why I told to use absolute paths.
# I assume the same filesystem. Creating hardlinks instead of copying;
# remove -l option to do regular copy. Hardlinking.
(cd "$dir1"; xargs -0 -a "$tmpf" cp -alt "$dir3")

# Convert core1 to core2 in tmpf in place.
sed -zi "s|${core1}|${core2}|" "$tmpf"

# Hardlinking from dir2 to dir4.
(cd "$dir2"; xargs -0 -a "$tmpf" cp -alt "$dir4")

# Remove the temporary file.
rm "$tmpf"
0

Вы можете использовать следующий цикл, чтобы поместить все в Directory3, а затем удалить Directory1 и Directory2:

mkdir Directory3
cd Directory1
for file in *
do
    # note that the second "cp" is only executed if the first one succeeds:
    cp ../Directory2/${file/blur/fine} ../Directory3/ 2>/dev/null && cp $file ../Directory3/
done
cd ..
#rm -rf Directory1 Directory2
0

Вы можете создать два отсортированных платья и сравнить их.

# create the listings
cd Directory1;ls|sed 's/_blur\.png//' >../list1.txt;cd ..
cd Directory2;ls|sed 's/_fine\.png//' >../list2.txt;cd ..
# sort the items, then deduplicate them (uniq) and add the count (-c)
cat list1.txt list2.txt|sort|uniq -c >counts.txt

Это должно дать вам список имен файлов с предшествующими 1 или 2. Тогда вы можете сделать

# for each line which starts with a 1, remove the 1 and use it as filename
for file in $(grep '^1' counts.txt|sed 's/^1 //');do
    # delete it from first or second directory
    test -f "Directory1/${file}_blur.png" && echo rm "Directory1/${file}_blur.png"
    test -f "Directory2/${file}_fine.png" && echo rm "Directory2/${file}_fine.png"
done

Если это работает, удалите эхо. Но, пожалуйста, проверьте это раньше.

0

Чтобы удалить изображение _blur без соответствующего `_fine |:

for f in Dir1/*blur.png;do [[ -f Dir2/$(basename $f _blur.png)_fine.png ]] || echo rm $f;done

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

Команда для удаления _fine , у которой нет соответствующего _blur , оставляется читателю в качестве упражнения.

Всё ещё ищете ответ? Посмотрите другие вопросы с метками .