Ordenar a saída de find -exec ls

12

É possível a saída de find … -exec ls -ls ; ordenada alpabeticamente, por nome de arquivo?

Este é o meu comando cron:

find /home/setefgge/public_html -type f -ctime -1 -exec ls -ls {} \;

Este comando funciona bem, na maior parte. Mas os resultados não são classificados em nenhuma sequência significativa. Seria muito útil se eles fossem classificados pelo campo de nome de arquivo.

    
por MaJ 03.07.2014 / 16:02

5 respostas

12

Presumo que os nomes dos seus arquivos não contenham novas linhas.

find /home/setefgge/public_html -type f -ctime -1 -exec ls -nls {} + | sort -k 10

Usar + em vez de ; para finalizar a ação -exec torna mais rápido ao agrupar as invocações de ls . Você pode classificar por meio do comando sort ; diga para começar a classificação no 10º campo (os primeiros 9 são os metadados: blocos, permissões, contagem de links, usuário, grupo, tamanho e 3 campos de data / hora). A opção -n diz a ls para usar valores numéricos para o usuário e o grupo, o que evita o risco de nomes de usuários ou grupos que contêm espaço em branco.

Como alternativa, com o zsh, você pode se safar sem assumir qualquer nome usando qualificadores da glob para coletar e classificar os arquivos e zargs para executar ls várias vezes se a linha de comando for muito longa. Você precisa do GNU ls (especificamente da sua opção -f ) para evitar a reclassificação por ls (outra abordagem seria emular ls com zsh's zstat ).

autoload -U zargs
zargs -- /home/setefgge/public_html/**/*(.c-2) -- ls -lnsf
    
por 04.07.2014 / 02:15
1

Por que não canalizar o resultado da busca por meio da classificação e, em seguida, executar ls para cada uma das linhas?

find . -type f -ctime -1 | sort | while IFS= read -r filename; do ls -ls "$filename"; done
    
por 04.07.2014 / 01:47
1

POSIX tem a dizer sobre datas em uma listagem ls -l ong:

The <date and time> field shall contain the appropriate date and timestamp of when the file was last modified. In the POSIX locale, the field shall be the equivalent of the output of the following date command:

date "+%b %e %H:%M"

...if the file has been modified in the last six months, or:

date "+%b %e %Y"

Levando isso em consideração, e garantindo que, se houver novas linhas em um nome de arquivo, elas sejam apropriadamente distribuídas com a opção ls -q também POSIX especificada, é relativamente fácil preparar um regex para um resultado ls sem find de todos:

d=$(date "+%b %e") y=$(date --date=yesterday "+%b %e")
echo "$d" "$y"

###OUTPUT###
Jul  5 Jul  4

grep para isso e você retornará apenas as linhas que contêm as strings representando as datas de hoje ou de ontem. O comando a seguir adiciona isso um pouco:

ls -alRcq | sed "1H;/^-/!{/./d;N;h};/$d\|$y/!d;x;/\n/p;g"

ls opções consistem em:

  1. -a retorna todos os arquivos em um diretório - incluindo aqueles que começam com .dot
  2. % lista longa de-l
  3. -R lista recursivamente todos os diretórios filhos
  4. -c exibe o tempo de modificação em vez do tempo de acesso
  5. -q retorna o shell glob ? em vez de caracteres não imprimíveis ou \t ab em um nome de arquivo

Esses resultados são passados sobre o arquivo |pipe para sed , que corresponde apenas a:

  1. A linha em branco que precede um nome de caminho e a seguinte linha
  2. Linhas iniciadas com - (em outras palavras, não d para o diretório) que também contêm date .
  3. Ele não imprime as linhas do nome do caminho, a menos que o diretório que ele nomeie contenha arquivos filtrados.

A saída é assim:

ls -alRcq --color=always | 
sed "1H;/^-/!{/./d;N;h};/$d\|$y/!d;x;/\n/p;g"

###OUTPUT###
.:
-rw------- 1 mikeserv mikeserv   2086 Jul  4 10:52 .bash_history
-rw------- 1 mikeserv mikeserv   2657 Jul  4 15:20 .lesshst
-rw-r--r-- 1 mikeserv mikeserv    681 Jul  5 05:18 .zdirs
-rw------- 1 mikeserv mikeserv 750583 Jul  5 08:28 .zsh_history
-rw-r--r-- 1 mikeserv mikeserv    166 Jul  4 23:02 Terminology.log
-rw-r--r-- 1 mikeserv mikeserv 433568 Jul  4 13:34 shot-2014-06-22_17-10-16.jpg
-rw-r--r-- 1 mikeserv mikeserv 445192 Jul  4 13:34 shot-2014-06-22_17-11-06.jpg

./.cache/efreet:
-rw------- 1 mikeserv mikeserv  37325 Jul  4 22:51 desktop_localhost_C.eet
-rw------- 1 mikeserv mikeserv  37325 Jul  4 23:30 desktop_localhost_en_US.eet
-rw------- 1 mikeserv mikeserv  24090 Jul  4 22:51 desktop_util_localhost_C.eet
-rw------- 1 mikeserv mikeserv  24090 Jul  4 23:30 desktop_util_localhost_en_US.eet
-rw------- 1 mikeserv mikeserv  16037 Jul  4 23:30 icon_themes_localhost.eet
-rw------- 1 mikeserv mikeserv   3117 Jul  4 23:30 icons___efreet_fallback_localhost.eet
-rw------- 1 mikeserv mikeserv 768039 Jul  4 23:30 icons_gnome_localhost.eet
-rw------- 1 mikeserv mikeserv  18589 Jul  4 23:30 icons_hicolor_localhost.eet

./.config:
-rw-r--r-- 1 mikeserv mikeserv   30 Jul  4 19:10 pavucontrol.ini

./.config/chrome:
-rw-r--r-- 1 mikeserv mikeserv 94332179 Jul  4 13:36 conf.tar.lz4.bak

Sim, funciona mesmo com LS_COLORS - o que provavelmente é uma prioridade baixa para o seu cron , mas, ei, suas opções estão abertas.

Em qualquer caso, isso oferece algumas vantagens significativas sobre algumas outras soluções possíveis.

  1. Em primeiro lugar, find + ls envolve várias invocações - isso envolve apenas um único processo ls , e é por isso que é possível classificar tudo de maneira confiável - o que acontece por padrão - e então sort também é feito auxiliar.

  2. Qualquer solução envolvendo find e sort e ls está praticamente fazendo todo o trabalho duas vezes. ls e find resolverão todos os nomes de caminho e stat a cada arquivo. ls e sort classificarão todos os resultados. Provavelmente, é melhor usar apenas o único ls .

  3. Então, é claro que há as partes date e sed dessa resposta. O que é importante notar é que você faz a parte difícil e obtém o regex primeiro - e apenas uma vez - e depois você apenas remove uma única lista de resultados em vez de dizer, obter resultados, obter resultados, classificar resultados e classificar resultados. p>

  4. Isso não afeta nomes de arquivos que contêm novas linhas, como outras soluções provavelmente farão. Esta solução tem suas próprias ressalvas - o que eu explico a seguir -, mas elas são minuciosas e fáceis de lidar. Na minha opinião, esta é a solução mais robusta aqui.

Existem dois casos em que o comando acima pode causar problemas. O primeiro envolve o ? globs nos nomes dos arquivos - enquanto que como ele já é uma solução mais robusta do que qualquer outra oferecida aqui, e a probabilidade de você encontrar um ? é pequena o suficiente por conta própria, existe uma possibilidade de que resolver esses globs poderia corresponder a mais de um nome de arquivo. Consulte este para obter mais informações sobre este assunto.

A outra possibilidade envolve um falso positivo - por exemplo, se você tiver um nome de arquivo correspondente à string date para a qual estamos pesquisando com grep , mas que não foi realmente modificado em nenhum desses dias. Eu não estou contando com isso sendo um problema, mas, se for, pergunte sobre isso e eu provavelmente posso ajudá-lo a tornar o regex mais específico, a fim de lidar com isso.

    
por 05.07.2014 / 01:37
0

Você pode usar uma combinação de find, xargs e ls.

Aqui está um exemplo de comando: find . -type f -print0 | xargs -0 ls -lt

  • find procurará recursivamente todos os arquivos no diretório atual.
  • xargs passará essa lista de arquivos para o comando ls em uma única chamada (desde que find retorne menos de ARG_MAX arquivos).
  • ls -lt classificará esses arquivos por hora e formatará a saída

Para recuperar seu sistema ARG_MAX , você pode digitar:

$ getconf ARG_MAX
> 2621440
    
por 14.12.2015 / 08:22
-1
ls -l $(find /home/setefgge/public_html -type f -ctime -1 | sort)
    
por 03.07.2014 / 16:38

Tags