Como escolher o arquivo mais antigo em uma pasta do diretório

Como escolher o arquivo mais antigo em uma pasta do diretório

Eu tinha nvários arquivos em meu ../in/diretório. Desses arquivos, quero que o arquivo mais antigo seja processado e enviado para o ../complete/diretório. Os arquivos restantes são enviados para o ../error/diretório. Alguém pode ajudar?

Responder1

Para copiar o arquivo mais antigo para ../complete:

cp -v "$(find ../in -maxdepth 1 -type f -printf '%T@ %p\0' | sort -zn | \
  sed -zn '1s/[0-9,\.]\+ //p')" ../complete

Para copiar todos, exceto o mais antigo, para ../error:

find ../in -maxdepth 1 -type f -printf '%T@ %p\0' | sort -zn | \
  sed -zn '2,$s/[0-9,\.]\+ //p' | xargs -0 cp -vt ../error

Explicação:

  • find
    • -maxdepth 1desce apenas 1 nível; portanto, ele não pesquisará o diretório de forma recusada.
    • -type fcorresponder apenas aos arquivos.
    • -printf '...'um formato de saída personalizado. %T@fornece a hora da última modificação do arquivo em um carimbo de data/hora, %pé o nome do arquivo. Observe o \0no final. Os arquivos são impressos delimitados por bytes nulos, não delimitados por nova linha, porque a nova linha provavelmente poderia ser um caractere no nome do arquivo, o que quebraria o comando.
  • sort -znisso irá ler a saída delimitada por byte nulo ( -z) e classificá-la numericamente ( -n).
  • sed -znlê a saída delimitada por byte nulo.
    • 1corresponderá apenas à primeira linha (primeiro comando) e 2,$corresponderá a todas as outras (segundo comando)
    • s/[0-9,\.]\+ //premoverá o carimbo de data/hora inicial da saída.
  • Somente a partir do segundo comando: xargs -0 cp -vt ../errorprocessa a saída delimitada por byte nulo ( -0) e chama cp -vt ../errortodas as entradas, que copia os arquivos.

Exemplo de saída:

$ ls -lt ../in/
total 0
-rw-r--r-- 1 user user 0 Jun 24 08:18 file2
-rw-r--r-- 1 user user 0 Jun 24 08:18 file3
-rw-r--r-- 1 user user 0 Jun 24 08:18 file4
-rw-r--r-- 1 user user 0 Jun 24 08:18 file5
-rw-r--r-- 1 user user 0 Jun 24 08:17 file_oldest
$ cp -v "$(...)" ../complete
'../in/file_oldest' -> '../complete/file_oldest'
$
$ find ... | xargs ... ../error
'../in/file2' -> '../error/file2'
'../in/file3' -> '../error/file3'
'../in/file4' -> '../error/file4'
'../in/file5' -> '../error/file5'

Responder2

Para encontrar o arquivo mais antigo e movê-lo para o diretório desejado, use:

# cd to ../in/

$ ls -lt | grep -v '^d' | tail -1 | awk '{print $NF}' | xargs -I '{}' mv '{}' ../complete/

Agora que o arquivo mais antigo foi movido, você pode mover todos os arquivos para../error/

$ mv -- * ../error/

O --seguinte mvé necessário se você tiver algum nome de arquivo/diretório começando com -.

Responder3

Construindo emA resposta de Raul:

$ ls -ltr | grep -v '^d' | awk 'NR==2 {print $NF; exit}' | xargs -I '{}' mv -- '{}' ../complete/

Notas:

  • Você diz que quer fazer algo com “o arquivo mais antigo”. Todas as respostas pressupõem que você quer dizer modificado menos recentemente. Se você quer dizer menos recentementemudado, então diz; as respostas serão um pouco diferentes. Se você quer dizer menos recentementecriada, o que você quer é quase impossível no Unix.
  • ls -lt(o que Rahul usou) lista o diretório atual em formato longo em ordem por data/hora de modificação, com o mais novo primeiro e o mais antigo por último.  ls -ltré oRsempre disso; o mais antigo primeiro e o mais novo por último.
  • Se você tiver arquivos cujos nomes começam com um ponto (.), adicione a Aopção a ls; por exemplo, ls -ltrA. (A ordem das opções não importa; você pode usar ls -ltAr, ls -lAtr, ou mesmo ls -ltr -Ase quiser.)
  • Eu menti. Uma listagem longa lsde um diretório sempre tem uma totallinha primeiro. Em ls -ltr, a entrada mais antiga está nosegundolinha.
  • grep -v '^d'filtra os diretórios (se houver).
  • awk 'NR==2 { print $NF; exit }' imprime o último campo (o nome do arquivo*) da segunda linha (o arquivo mais antigo) e depois sai.

    • Este é um processo a menos que tail -1 | awk '{print $NF}'.
    • Isso pode funcionar mais rápido, porque, quando awksai, lstambém pode sair, e você evitaria gerar a listagem para todo o diretório.
    • Você pode eliminar isso grepfazendo

      ls -ltr | awk '! /^d/ { count++ } count==2 { print $NF; exit }'
      

      mas eu não aconselharia isso. Scripts excessivamente complexos são difíceis de manter.

  • O --depoismv no xargscomandoé necessário se você tiver algum nome de arquivo começando com um-.
  • Você realmente não precisa do xargs. Você pode simplificar o comando acima para

    $ mv -- $(ls -ltr | grep -v '^d' | awk 'NR==2 { print $NF; exit }') ../complete/
    

________
* Como a resposta de Rahul, isso falhará se o nome do arquivo contiver espaços ou tabulações - e pior ainda se contiver novas linhas.

Se você tiver arquivos cujos nomes começam com um ponto (.), faça shopt -s dotglobantes de fazer o

$ mv -- * ../error/

informação relacionada