find -exec ls -lR {} \; retorna cada item duas vezes

0

Background : Atualmente, estou escrevendo um script de arquivamento, que cria tarballs compactados em algumas pastas e em seu conteúdo. Ele deve ser capaz de sincronizar os arquivos compactados com as fontes sem descompactar os arquivos ou compactar as fontes. Para isso, a solução procurada é sincronizar a saída de ls -l com a saída de tar -ztvf .

Ambos os comandos retornam uma saída similar, mas são ligeiramente diferentes. A maioria dessas diferenças pode ser resolvida com expressões regulares ou cut . Uma coisa que não consegui resolver é listar o caminho dos arquivos em relação ao diretório consultado em profundidade máxima.

Para superar esse problema, usei find para localizar todos os arquivos e os alimentei em ls com o comando:

find Webcam -exec ls -lR --time-style="+%Y-%m-%d %H:%M" {} \; | cut -f1,3- -d" " | sed "s/ /\//2" | sed "s/ \+/ /g"

onde a maior parte do pipeline atende à finalidade de formatação, find Webcam -exec ls -lR {} \; é a parte problemática e Webcam é a pasta de teste. A saída deste comando é a seguinte:

-rw-r--r-- debian/debian 162406 2014-04-12 13:42 2014-04-12-134210.jpg
-rw-r--r-- debian/debian 116247 2014-08-09 16:38 2014-08-09-163849.jpg
-rw-r--r-- debian/debian 96597 2015-03-15 19:39 2015-03-15-193905.jpg
-rw-r--r-- debian/debian 100795 2015-04-29 20:23 2015-04-29-202242.jpg
-rw-r--r-- debian/debian 97120 2015-08-02 13:42 2015-08-02-134230.jpg
-rw-r--r-- debian/debian 123835 2015-08-27 23:03 2015-08-27-230306.jpg
-rw-r--r-- debian/debian 97120 2015-08-02 13:42 Webcam/2015-08-02-134230.jpg
-rw-r--r-- debian/debian 100795 2015-04-29 20:23 Webcam/2015-04-29-202242.jpg
-rw-r--r-- debian/debian 116247 2014-08-09 16:38 Webcam/2014-08-09-163849.jpg
-rw-r--r-- debian/debian 96597 2015-03-15 19:39 Webcam/2015-03-15-193905.jpg
-rw-r--r-- debian/debian 162406 2014-04-12 13:42 Webcam/2014-04-12-134210.jpg
-rw-r--r-- debian/debian 123835 2015-08-27 23:03 Webcam/2015-08-27-230306.jpg

Agora, a saída se parece com a saída de tar -ztvf :

-rw-r--r-- debian/debian 162406 2014-04-12 13:42 Webcam/2014-04-12-134210.jpg
-rw-r--r-- debian/debian 116247 2014-08-09 16:38 Webcam/2014-08-09-163849.jpg
-rw-r--r-- debian/debian 96597 2015-03-15 19:39 Webcam/2015-03-15-193905.jpg
-rw-r--r-- debian/debian 100795 2015-04-29 20:23 Webcam/2015-04-29-202242.jpg
-rw-r--r-- debian/debian 97120 2015-08-02 13:42 Webcam/2015-08-02-134230.jpg
-rw-r--r-- debian/debian 123835 2015-08-27 23:03 Webcam/2015-08-27-230306.jpg

com a falha óbvia de ls listando cada item encontrado duas vezes, uma vez com o caminho requerido e uma vez sem ele. Como posso "corrigir" ls para listar cada item duas vezes?

Uma visão adicional sobre a natureza desse erro (por exemplo, o que está acontecendo sob o capô) é mais do que bem-vinda, enquanto formas mais práticas de resolver todo o problema de arquivamento também são bem-vindas como notas secundárias. No entanto, agora eu considero isso como um desafio, o que eu gostaria de resolver, então o foco principal deve ser mantido limitando a saída de ls .

    
por Gabor Farkas 10.04.2016 / 15:24

3 respostas

4

O problema é que find também encontra o diretório Webcam e executa ls Webcam , que lista todos os arquivos lá. Para listar apenas arquivos, não diretórios, informe o find

-type f
    
por 10.04.2016 / 15:31
4

Seu problema é que ls -lR será executado para todos os arquivos (que exibirão os arquivos) e todos os diretórios (que exibirão o conteúdo do diretório). Se a hierarquia de diretórios não fosse plana, mas contivesse subdiretórios, isso exibiria o conteúdo com mais frequência, já que -R informa ls para percorrer subdiretórios novamente. Em vez disso, você deve chamar find da seguinte forma:

  1. find . -type f -exec ls -l {} , que exibiria apenas arquivos.
  2. find . -exec ls -dl {} , que exibiria arquivos e diretórios.
por 10.04.2016 / 15:37
2

A causa deste problema é incrivelmente curta: . (sim: um ponto).

Entenda que find (sem um dir) é equivalente a find . . De man find :

If no paths are given, the current directory is used.

E, quando você executa find . , o ponto aparece na lista gerada
(Usando apenas quatro arquivos com nomes distintos para simplificar):

$ find                        ### Works the same with or without the dot.
.
./2014-08-09-163849.jpg
./2014-04-12-134210.jpg
./Webcam
./Webcam/2015-04-29-202242.jpg
./Webcam/2015-08-27-230306.jpg

E então você está dando essa lista para ls -R (recursivamente).
Apenas o ponto irá reproduzir todos os arquivos:

$ ls -1R .         ### The 1 will make the list 1 column.
.:
Webcam
2014-04-12-134210.jpg
2014-08-09-163849.jpg

./Webcam:
2015-04-29-202242.jpg
2015-08-27-230306.jpg

Portanto, não é de admirar que todos os arquivos apareçam duas vezes (uma vez para o ponto, uma vez a partir da localização).

$ find -exec ls -1R {} \;
.:
2014-04-12-134210.jpg
2014-08-09-163849.jpg
Webcam

./Webcam:
2015-04-29-202242.jpg
2015-08-27-230306.jpg
./2014-08-09-163849.jpg
./2014-04-12-134210.jpg
./Webcam:
2015-04-29-202242.jpg
2015-08-27-230306.jpg
./Webcam/2015-04-29-202242.jpg
./Webcam/2015-08-27-230306.jpg

Soluções

Remove o ponto (use \( ! -name . -prune \) -a ).

Remova o ponto da lista de arquivos encontrados da pesquisa:

$ find . \( ! -name . -prune \) -a -print
./2014-08-09-163849.jpg
./2014-04-12-134210.jpg
./Webcam

Então você pode usar um ls -R recursivo:

$  find . \( ! -name . -prune \) -a -exec ls -1R {} \;
./2014-08-09-163849.jpg
./2014-04-12-134210.jpg
./Webcam:
2015-04-29-202242.jpg
2015-08-27-230306.jpg

Evite ls recursivo (mais simples, mas exige ls -d ).

Não use uma% recursivals -R (com também uma opção -d para evitar expandir para dirs) e deixe find fazer o andamento da árvore para encontrar todos os arquivos:

$ find . ! -path . -exec ls -1d {} \;  
./2014-08-09-163849.jpg
./2014-04-12-134210.jpg
./Webcam
./Webcam/2015-04-29-202242.jpg
./Webcam/2015-08-27-230306.jpg    

Arquivamento

Claro, para o uso específico de arquivamento:
você não precisa dos nomes de diretório, apenas nomes de arquivos de caminho completo:

$ find . ! -path ./ -type f -a -exec ls -1R {} \;
./2014-08-09-163849.jpg
./2014-04-12-134210.jpg
./Webcam/2015-04-29-202242.jpg
./Webcam/2015-08-27-230306.jpg

Sobre find dir (não ponto).

Se você usar um caminho, o problema é o mesmo se a profundidade dos diretórios for maior que um.

Isso não acionará um problema:

$ find Webcam -exec ls -1R {} \;
Webcam:
2015-04-29-202242.jpg
2015-08-27-230306.jpg
Webcam/2015-04-29-202242.jpg
Webcam/2015-08-27-230306.jpg

No entanto, aumentar a profundidade em um (cd ..) irá:

$ cd ..
$  find jpg -exec ls -1R {} \;
jpg:
2014-04-12-134210.jpg
2014-08-09-163849.jpg
Webcam

jpg/Webcam:
2015-04-29-202242.jpg
2015-08-27-230306.jpg
jpg/2014-08-09-163849.jpg
jpg/2014-04-12-134210.jpg
jpg/Webcam:
2015-04-29-202242.jpg
2015-08-27-230306.jpg
jpg/Webcam/2015-04-29-202242.jpg
jpg/Webcam/2015-08-27-230306.jpg

que isso não acionará:

$  find jpg \( ! -path ./jpg -prune \) -exec ls -1R {} \;
jpg:
2014-04-12-134210.jpg
2014-08-09-163849.jpg
Webcam

jpg/Webcam:
2015-04-29-202242.jpg
2015-08-27-230306.jpg

Eu insisto que o uso de duas ferramentas recursivas é muito mal aconselhado .

Mude para uma estrutura mais simples, como find jpg -ls ou até mesmo tente uma solução de listagem fornecida pelo shell semelhante a echo ** :

$ (shopt -s globstar nullglob; printf '%s\n' jpg/**/*)
jpg/2014-04-12-134210.jpg
jpg/2014-08-09-163849.jpg
jpg/Webcam
jpg/Webcam/2015-04-29-202242.jpg
jpg/Webcam/2015-08-27-230306.jpg
    
por 10.04.2016 / 22:14

Tags