Como fazer essa lista Comparação com o Find?

0

Eu faço e obtenho uma lista de arquivos onde eu gostaria de deletar muitos arquivos duplicados de backup

find . -type f -name '._*' 

Eu gostaria de encontrar os arquivos que têm um nome de arquivo correspondente

  • /home/masi/._test.tex corresponde a /home/masi/test.tex
  • /home/masi/math/lorem.png corresponde a /home/masi/math/._lorem.png

O pseudocódigo dos arquivos desejava ser salvo filename , que tem ._filename correspondente, mas também economiza filename sem ._filename

find . -type f -name '._*' -exec \ 
   find filenameWithoutDotUnderscore, if yes, print the filename

O esclarecimento do Pseudocódigo 2 sobre arquivos desejava ser removido = ._filename se houver um filename

correspondente
  • Se houver filename e ._filename no mesmo diretório, imprima ._filename de forma que eu possa remover a duplicata = ._filename .
  • Exclua filenamePart1_.filenamePart2 , bok_3A.pdf , ... em ._filename .
  • Não remova ._filename se não houver filename correspondente no mesmo diretório.

Revendo o comando do Wildcard

Eu faço find . -type f -name '._*' -exec sh -c 'for a; do f="${a%/*}/${a##*/._}"; [ -e "$f" ] && printf "rm -- %s\n" "$a"; done' find-sh {} + , mas ele retorna muitos arquivos. Acho que preciso de mais && condições ao lado da verificação de existência ( [ -e "$f" ] ). Seria ótimo para obter aqui alguma comparação de conteúdo e por último diff se suspeita de muita diferença.

Sistemas: Ubuntu 16.04 e Debian 8.25
Bash: 4,3.42
Localizar: 4.7.0

    
por Léo Léopold Hertz 준영 09.06.2016 / 21:54

2 respostas

3

Você pode fazer isso com find , mas, para fazê-lo de forma robusta, você precisará incorporar uma linha de uma concha também. A maneira correta de fazer isso é um dos seguintes:

Coloque o loop no shell gerado:

find . -type f -name '._*' -exec sh -c 'for a in "$@"; do f="${a%/*}/${a##*/._}"; [ -e "$f" ] && printf %s\n "$f"; done' find-sh {} +

Ou crie um shell separado para cada arquivo a ser testado (menos eficiente, potencialmente mais legível):

find . -type f -name '._*' -exec sh -c 'f="${1%/*}/${1##*/._}"; [ -e "$f" ] && printf %s\n "$f"' find-sh {} \;

Para remover diretamente os arquivos de backup, altere para o seguinte para execução a seco:

find . -type f -name '._*' -exec sh -c 'for a; do f="${a%/*}/${a##*/._}"; [ -e "$f" ] && printf "rm -- %s\n" "$a"; done' find-sh {} +

Em seguida, quando estiver satisfeito com a lista de comandos impressos, use:

find . -type f -name '._*' -exec sh -c 'for a; do f="${a%/*}/${a##*/._}"; [ -e "$f" ] && rm -- "$a"; done' find-sh {} +

Notas:

Em todos esses, o argumento find-sh é uma string arbitrária; você poderia colocar qualquer coisa lá. Ele é definido como $0 dentro do shell gerado e é usado para relatório de erros.

for a in "$@"; do é exatamente equivalente a for a; do .

printf é melhor que echo .

A citação é importante .

    
por 09.06.2016 / 23:03
0

Eu fiz um a.sh (porque não sei como fazer isso como uma função), que é apenas uma linha:

test -f "${*/._/}" && echo "$* matches ${*/._/}";

Ou seja, estou testando a existência de um arquivo cujo nome é todos os argumentos passados para o shell script, com a primeira instância de ._ removida (tecnicamente uma pesquisa e substituição sem nada no arquivo ' substitua 'campo'. Quando encontra tal arquivo, ecoa o nome dos dois arquivos correspondentes.

Então eu corri com find ... -exec ./a.sh '{}' \;

Sobre a pesquisa (e substituição) no bash: ${foo/bar/baz} significa pesquisar a variável foo para a string bar e substituí-la por baz . Você pode tentar este experimento: x=abcdef; echo ${x/c/C} . Então, o código acima está procurando ._ e substituindo-o por nada. Para mais detalhes, em man bash pesquise Pattern substitution .

    
por 09.06.2016 / 22:06

Tags