Eu tenho uma lista de arquivos que quero verificar se eles existem no meu sistema de arquivos. Eu pensei em fazer isso usando find
como em:
for f in $(cat file_list); do
find . -name $f > /dev/null || print $f
done
(usando zsh
), mas isso não funciona, pois find
parece sair 0
se ele encontra ou não o arquivo. Eu acho que eu poderia passar por algum outro teste que testa para ver se find
produz alguma saída (bruto, mas eficaz seria substituí-lo > /dev/null
por |grep ''
), mas isso parece usar um troll para pegar uma cabra (outras nacionalidades podem dizer algo sobre marretas e nozes )
Existe uma maneira de coagir find
a me dar um valor de saída útil? Ou pelo menos para obter uma lista daqueles arquivos que não foram encontrados? (Eu posso imaginar o último sendo talvez mais fácil por alguma escolha astuta de conectivos lógicos, mas pareço sempre ficar atolado quando tento descobrir isso.)
Antecedentes / Motivação: Eu tenho um backup "principal" e quero verificar se existem alguns arquivos na minha máquina local no meu backup principal antes de excluí-los (para criar um pouco de espaço). Então, fiz uma lista dos arquivos, ssh
editei-os na máquina principal e fiquei sem saber por que descobrir a melhor maneira de encontrar os arquivos ausentes.
locate
.locate
não está mostrando o estado atual do sistema de arquivos, pode ser um dia ou até uma semana. Isso é adequado como base para testar backups.Respostas:
find
considera não encontrar nada como um caso especial de sucesso (nenhum erro ocorreu). Uma maneira geral de testar se os arquivos correspondem a algunsfind
critérios é testar se a saída defind
está vazia. Para uma melhor eficiência quando houver arquivos correspondentes, use-quit
no GNU find para fazê-lo sair na primeira partida ouhead
(head -c 1
se disponível, caso contrário, ohead -n 1
que é padrão) em outros sistemas para fazê-lo morrer de um cano quebrado ao invés de produzir uma saída longa.No bash ≥4 ou zsh, você não precisa do
find
comando externo para uma correspondência simples de nome: você pode usar**/$name
. Versão do Bash:Versão Zsh em um princípio semelhante:
Ou aqui está uma maneira mais curta, porém mais enigmática, de testar a existência de um arquivo que corresponde a um padrão. O qualificador glob
N
deixa a saída vazia se não houver correspondência,[1]
retém apenas a primeira correspondência ee:REPLY=true:
altera cada correspondência para expandir para em1
vez do nome do arquivo correspondente. Então,**/"$name"(Ne:REPLY=true:[1]) false
expande paratrue false
se houver uma correspondência ou apenasfalse
se não houver uma correspondência.Seria mais eficiente combinar todos os seus nomes em uma única pesquisa. Se o número de padrões não for muito grande para o limite de comprimento do sistema em uma linha de comando, você poderá juntar todos os nomes com
-o
, fazer uma únicafind
chamada e pós-processar a saída. Se nenhum dos nomes contiver metacaracteres de shell (para que os nomes também sejamfind
padrões), eis uma maneira de pós-processar com o awk (não testado):Outra abordagem seria usar o Perl e
File::Find
, o que facilita a execução do código Perl para todos os arquivos em um diretório.Uma abordagem alternativa é gerar uma lista de nomes de arquivos de ambos os lados e trabalhar em uma comparação de texto. Versão Zsh:
fonte
zsh
solução com a**
sintaxe. É uma solução muito simples e, embora possa não ser a mais eficiente em termos de máquina , é provavelmente a mais eficiente em termos de eu realmente me lembrar dela! Além disso, a primeira solução aqui responde à pergunta real , pois ela sefind
transforma em algo em que o código de saída distingue "eu consegui uma correspondência" de "eu não consegui uma correspondência".Você pode usarstat
para determinar se existe um arquivo no sistema de arquivos.Você deve usar as funções internas do shell para testar se existem arquivos.
O "teste" é opcional e o script realmente funciona sem ele, mas eu o deixei lá para facilitar a leitura.
Edit: Se você realmente não tem opção, a não ser trabalhar para uma lista de nomes de arquivos sem caminhos, sugiro que você crie uma lista de arquivos uma vez com o find, em seguida, itere-o com grep para descobrir quais arquivos estão lá.
Observe que:
fonte
Uma primeira abordagem simplista poderia ser:
a) classifique sua lista de arquivos:
para encontrar missões ou
encontrar correspondências
Desvantagens:
O find pode procurar vários arquivos ao mesmo tempo, com alguma preparação:
localize -name a.file -ou -name -b.file -ou -name c.file ...
Pode localizar ser uma opção? Novamente, uma lista pré-classificada de arquivos assumiu:
Uma pesquisa por foo.bar não corresponderá ao arquivo foo.ba ou oo.bar com a construção --regexp-(não deve ser confundida com regex sem p).
Você pode especificar um banco de dados específico para localização e precisará atualizá-lo antes de pesquisar, se precisar dos resultados mais recentes.
fonte
Eu acho que isso pode ser útil também.
Esta é uma solução de uma linha, caso você opte pela "lista" de arquivos reais que deseja sincronizar com outra pasta:
para ajudar a ler:
este exemplo exclui arquivos "* ~" de backup e limita ao tipo de arquivo regular "-type f"
fonte
Talvez?
fonte
Por que não simplesmente comparar o comprimento da lista de consultas com o comprimento da lista de resultados?
fonte