Cómo seleccionar el archivo más antiguo de una carpeta del directorio

Cómo seleccionar el archivo más antiguo de una carpeta del directorio

Tenía nvarios archivos en mi ../in/directorio. De esos archivos quiero que el archivo más antiguo se procese y lo envíe al ../complete/directorio. Los archivos restantes se envían al ../error/directorio. ¿Alguien puede ayudar?

Respuesta1

Para copiar el archivo más antiguo a ../complete:

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

Para copiar todo excepto el más antiguo a ../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

Explicación:

  • find
    • -maxdepth 1desciende solo 1 nivel; por lo tanto, no buscará en el directorio de forma recursiva.
    • -type fcoincidir sólo con archivos.
    • -printf '...'un formato de salida personalizado. %T@proporciona la hora de la última modificación del archivo en una marca de tiempo, %pes el nombre del archivo. Fíjate \0en el final. Los archivos se imprimen delimitados por bytes nulos, no delimitados por nueva línea, porque la nueva línea probablemente podría ser un carácter en el nombre del archivo, lo que luego interrumpiría el comando.
  • sort -znesto leerá el byte nulo de salida delimitado ( -z) y lo ordenará numéricamente ( -n).
  • sed -znlee la salida delimitada por bytes nulos.
    • 1solo coincidirá con la primera línea (primer comando) y 2,$coincidirá con todas las demás (segundo comando)
    • s/[0-9,\.]\+ //peliminará la marca de tiempo inicial de la salida.
  • Solo desde el segundo comando: xargs -0 cp -vt ../errorprocesa la salida con bytes nulos delimitados ( -0) y llama cp -vt ../errora todas las entradas, lo que copia los archivos.

Salida de ejemplo:

$ 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'

Respuesta2

Para encontrar el archivo más antiguo y moverlo al directorio deseado, use:

# cd to ../in/

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

Ahora que se ha eliminado el archivo más antiguo, puede mover todos los archivos a../error/

$ mv -- * ../error/

El --después mves necesario si tiene algún nombre de archivo/directorio que comience con -.

Respuesta3

Sobre la base deLa respuesta de Raúl:

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

Notas:

  • Dices que quieres hacer algo con "el archivo más antiguo". Todas las respuestas suponen que te refieres a la modificación menos reciente. Si te refieres a menos recientementecambió, dilo; las respuestas serán ligeramente diferentes. Si te refieres a menos recientementecreado, lo que quieres es casi imposible en Unix.
  • ls -lt(lo que usó Rahul) enumera el directorio actual en formato largo en orden por fecha/hora de modificación, con el más nuevo primero y el más antiguo al final.  ls -ltres elrreverso de eso; el más antiguo primero y el más nuevo al final.
  • Si tiene archivos cuyos nombres comienzan con un punto (.), agregue la Aopción a ls; p.ej, ls -ltrA. (El orden de las opciones no importa; puedes usar ls -ltAr, ls -lAtro incluso ls -ltr -Asi lo deseas).
  • Mentí. Una lista larga lsde un directorio siempre tiene una totallínea primero. En ls -ltr, la entrada más antigua está en elsegundolínea.
  • grep -v '^d'filtra los directorios (si los hay).
  • awk 'NR==2 { print $NF; exit }' imprime el último campo (el nombre del archivo*) de la segunda línea (el archivo más antiguo) y luego sale.

    • Este es un proceso menos que tail -1 | awk '{print $NF}'.
    • Esto podría funcionar más rápido porque, cuando awksale, lstambién podría salir y evitaría generar el listado para todo el directorio.
    • Puedes eliminarlo grephaciendo

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

      pero no lo recomendaría. Los scripts demasiado complejos son difíciles de mantener.

  • El --despuesmv en el xargscomandoes necesario si tiene algún nombre de archivo que comience con-.
  • Realmente no necesitas el xargs. Puede simplificar el comando anterior para

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

________
* Al igual que la respuesta de Rahul, esto fallará si el nombre del archivo contiene espacios o tabulaciones, y peor aún si contiene nuevas líneas.

Si tiene archivos cuyos nombres comienzan con un punto (.), hacer shopt -s dotglobantes de hacer el

$ mv -- * ../error/

información relacionada