Tenía n
varios 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 1
desciende solo 1 nivel; por lo tanto, no buscará en el directorio de forma recursiva.-type f
coincidir 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,%p
es el nombre del archivo. Fíjate\0
en 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 -zn
esto leerá el byte nulo de salida delimitado (-z
) y lo ordenará numéricamente (-n
).sed -zn
lee la salida delimitada por bytes nulos.1
solo coincidirá con la primera línea (primer comando) y2,$
coincidirá con todas las demás (segundo comando)s/[0-9,\.]\+ //p
eliminará la marca de tiempo inicial de la salida.
- Solo desde el segundo comando:
xargs -0 cp -vt ../error
procesa la salida con bytes nulos delimitados (-0
) y llamacp -vt ../error
a 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 mv
es 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 -ltr
es 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 laA
opción als
; p.ej,ls -ltrA
. (El orden de las opciones no importa; puedes usarls -ltAr
,ls -lAtr
o inclusols -ltr -A
si lo deseas). - Mentí. Una lista larga
ls
de un directorio siempre tiene unatotal
línea primero. Enls -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
awk
sale,ls
también podría salir y evitaría generar el listado para todo el directorio. Puedes eliminarlo
grep
haciendols -ltr | awk '! /^d/ { count++ } count==2 { print $NF; exit }'
pero no lo recomendaría. Los scripts demasiado complejos son difíciles de mantener.
- Este es un proceso menos que
- El
--
despuesmv
en elxargs
comandoes 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 dotglob
antes de hacer el
$ mv -- * ../error/