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
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
.
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:
find . -type f -exec ls -l {}
, que exibiria apenas arquivos. find . -exec ls -dl {}
, que exibiria arquivos e diretórios. 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
\( ! -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
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
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
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