Compare a parte dos nomes de arquivos em dois diretórios

0

Eu tenho dois diretórios como Directory1 e Directory2. Ambos contêm imagens com alguns números e string. O Directory1 contém as imagens desfocadas com o número e a sequência _blur como, 001_blur.png. Ele contém cerca de 62k imagens. Diretório2 contém imagens finas correspondentes, digamos 001_fine.png. Contém 60k imagens.

O problema é que eu perdi algumas imagens tremidas do Directory1 que têm par fino correspondente no Directory2. E perdi algumas imagens no Directory2 que tem a imagem de desfoque correspondente no Directory1.

Agora eu gostaria de salvar apenas as imagens que têm par correspondente. Quer dizer, se uma das imagens correspondentes não estiver presente, gostaria de excluí-las e apenas colocar as imagens com pares.

Portanto, meu formato de diretório é:

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

Nota: Eu gostaria de manter 001 par, 002 par e 003 par. Eu gostaria de copiar o desfoque para Directory3 e bem para Directory4.

Eu acho que esse problema também tem alguma complexidade algorítmica como as imagens são cerca de 60k em cada pasta. Se eu pegar uma imagem do Directory1 e tentar procurar uma imagem fina correspondente no Directory2, acho que a complexidade é alta. Então, como eu lido com essa complexidade algorítmica?

    
por Dharma 06.07.2017 / 14:31

4 respostas

1

a abordagem do allo para ler o conteúdo dos diretórios uma vez, analisar os dados do texto e excluir os arquivos no final parece bom. No entanto, essa resposta parece não reconhecer a diferença entre nomes de arquivos nos dois diretórios ( blur vs. fine ).

Seus arquivos são nomeados de acordo com padrões, portanto, seus nomes não devem incluir surpresas desagradáveis como caracteres não imprimíveis, novas linhas ou mais. Analisar ls deve ser seguro, mas, em geral, não se deve fazê-lo . Gostaria de fornecer uma solução geral para não analisar ls aqui. Eu vou usar strings terminadas em null, daí as opções como -print0 e -z all over.

Vamos começar. Você só precisa ajustar os caminhos nas declarações de variáveis, a menos que você copie para outro (s) sistema (s) de arquivos. Em caso afirmativo, você também deve ajustar cp -l . Leia os comentários primeiro. Eu aconselho você a colar o código inteiro em um arquivo, ajustar e, em seguida, fonte ou executá-lo.

#/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"
    
por 06.07.2017 / 20:24
0

Você pode usar o seguinte loop para colocar tudo no Directory3 e, em seguida, excluir Directory1 e 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
    
por 06.07.2017 / 15:10
0

Para remover a imagem _blur sem correspondência '_fine |:

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

Tente uma vez como acima e, se parecer estar fazendo a coisa certa, remova echo para remover os arquivos.

O comando para remover o _fine que não tem _blur correspondente é deixado como um exercício para o leitor.

    
por 06.07.2017 / 21:48
0

Você pode criar dois dirlistings classificados e compará-los.

# 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

Isso deve fornecer uma lista de nomes de arquivos precedidos de 1 ou 2. Então você pode fazer

# 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

Se funcionar, remova o eco. Mas por favor teste antes.

    
por 06.07.2017 / 17:08