¿Cómo escribo un script para mover solo los 20 archivos más antiguos de una carpeta a otra? ¿Hay alguna manera de tomar los archivos más antiguos en una carpeta?
bash
shell
shell-script
files
timestamps
usuario11598
fuente
fuente

atime(último acceso),ctime(último cambio de permiso) ymtime(última modificación) ... por ejemplo.ls -ty del hallazgoprintf "%T"usomtime... Parece, de acuerdo con este enlace , que misext4particiones son capaces de manejar una fecha de creación, perolsefindystatno tienen las opciones apropiadas (todavía) ...Respuestas:
Analizar la salida de no
lses confiable .En su lugar, utilice
findpara localizar los archivos ysortordenarlos por marca de tiempo. Por ejemplo:¿Qué está haciendo todo esto?
Primero, los
findcomandos localizan todos los archivos y directorios en el directorio actual (.), pero no en subdirectorios del directorio actual (-maxdepth 1), luego imprime:La marca de tiempo es importante. El
%T@especificador de formato-printfse desglosa enT, que indica "Tiempo de última modificación" del archivo (mtime) y@, que indica "Segundos desde 1970", incluidos los segundos fraccionarios.El espacio es simplemente un delimitador arbitrario. La ruta completa al archivo es para que podamos consultarlo más tarde, y el carácter NULL es un terminador porque es un carácter ilegal en un nombre de archivo y, por lo tanto, nos permite saber con seguridad que llegamos al final de la ruta al archivo.
Lo he incluido
2>/dev/nullpara que se excluyan los archivos a los que el usuario no tiene permiso de acceso, pero se suprimen los mensajes de error sobre su exclusión.El resultado del
findcomando es una lista de todos los directorios en el directorio actual. La lista se canaliza a lasortque se indica que:-zTrate NULL como el carácter terminador de línea en lugar de nueva línea.-nOrdenar numéricamenteComo los segundos desde 1970 siempre suben, queremos el archivo cuya marca de tiempo sea el número más pequeño. El primer resultado
sortserá la línea que contiene la marca de tiempo numerada más pequeña. Todo lo que queda es extraer el nombre del archivo.Los resultados de la
find,sortla tubería se pasa a través de la sustitución de proceso awhiledonde se lee como si fuera un archivo en la entrada estándar.whilea su vez invocareadpara procesar la entrada.En el contexto de
readestablecemos laIFSvariable en nada, lo que significa que los espacios en blanco no se interpretarán inapropiadamente como un delimitador.readse cuenta-r, que desactiva la expansión de escape, y-d $'\0', lo que hace que el NULL delimitador de fin de línea, haciendo coincidir la salida de nuestrafind,sorttubería.La primera porción de datos, que representa la ruta de archivo más antigua precedida por su marca de tiempo y un espacio, se lee en la variable
line. A continuación, la sustitución de parámetros se usa con la expresión#*, que simplemente reemplaza todos los caracteres desde el comienzo de la cadena hasta el primer espacio, incluido el espacio, sin nada. Esto elimina la marca de tiempo de modificación, dejando solo la ruta completa al archivo.En este punto, el nombre del archivo está almacenado
$filey puede hacer lo que quiera con él. Cuando termine de hacer algo con$filelawhileinstrucción,readse ejecutará un bucle y el comando se ejecutará nuevamente, extrayendo el siguiente fragmento y el siguiente nombre de archivo.¿No hay una manera más simple?
No. Las formas más simples son defectuosas.
Si usa
ls -ty canaliza haciaheadotail(o cualquier cosa ), romperá los archivos con nuevas líneas en los nombres de archivo. Simv $(anything)luego los archivos con espacios en blanco en el nombre causarán rotura. Simv "$(anything)"luego los archivos con líneas nuevas en el nombre causarán roturas. Sireadno-d $'\0', entonces usted va a romper en archivos con espacios en blanco en sus nombres.Quizás en casos específicos usted sabe con certeza que una forma más simple es suficiente, pero nunca debe escribir suposiciones como esa en los scripts si puede evitar hacerlo.
Solución
Llamar como:
Para mover los 20 archivos más antiguos de
/var/log/foo/a/mnt/backup/.Tenga en cuenta que estoy incluyendo archivos y directorios. Para archivos solo agregue
-type fa lafindinvocación.Gracias
Gracias a enzotib y Павел Танков por las mejoras a esta respuesta.
fuente
-n. Al menos en mi versión, no ordena los números decimales correctamente. Debe eliminar el punto en la fecha o el uso-printf '%TY-%Tm-%TdT%TH:%TM:%TS %p\0' | sort -rz, las fechas ISO u otra cosa..debe ser irrelevante para usted). Sería más claro decirlosort -z -n -t. -k1.%TStambién muestra una "parte fraccional" que estaría en la forma00.0000000000, por lo que también pierde granularidad. GNU recientesortpodría resolver este problema mediante el uso-Vde un "tipo de versión", que manejará este tipo de coma flotante como se esperaba.%T@también funcionaría, entonces, porque está rellenada con ceros.Es más fácil en zsh, donde puede usar el
Omcalificador global para ordenar las coincidencias por fecha (la más antigua primero) y el[1,20]calificador para retener solo las primeras 20 coincidencias:Agregue el
Dcalificador si también desea incluir archivos de puntos. Agregue.si desea hacer coincidir solo archivos normales y no directorios.Si no tiene zsh, aquí hay un Perl one-liner (puede hacerlo en menos de 80 caracteres, pero a un costo adicional en claridad):
Con solo las herramientas POSIX o incluso bash o ksh, ordenar archivos por fecha es una molestia. Puede hacerlo fácilmente
ls, pero analizar el resultado delses problemático, por lo que esto solo funciona si los nombres de los archivos contienen solo caracteres imprimibles distintos de las nuevas líneas.fuente
Combinar
ls -tsalida contailohead.Ejemplo simple, que funciona solo si todos los nombres de archivo contienen solo caracteres imprimibles que no sean espacios en blanco y
\[*?:fuente
ls -1Atrtouch $'foo\n*'. ¿Qué sucede si ejecuta mv "$ (ls)" con ese archivo allí?Puede usar GNU find para esto:
Donde find imprime el tiempo de modificación (en segundos desde 1970) y el nombre de cada archivo del directorio actual, la salida se ordena según el primer campo, los 20 más antiguos se filtran y se mueven
dest_dir. Elimine elechosi ha probado la línea de comando.fuente
Nadie ha publicado (todavía) un ejemplo de bash que atienda caracteres de nueva línea incrustados (incrustado cualquier cosa) en el nombre del archivo, así que aquí hay uno. Mueve los 3 archivos regulares más antiguos (mdate)
Este es el fragmento de datos de prueba
Aquí está el fragmento de verificación de resultados
fuente
Es más fácil hacerlo con GNU
find. Lo uso todos los días en mi DVR de Linux para eliminar grabaciones de mi sistema de videovigilancia anteriores a un día.Aquí está la sintaxis:
Recuerde que
finddefine un día como 24 horas desde el momento de la ejecución. Por lo tanto, los archivos modificados por última vez a las 11 p. M. No se eliminarán a la 1 a. M.Incluso puede combinar
findconcron, por lo que las eliminaciones se pueden programar automáticamente ejecutando el siguiente comando como root:Siempre puede obtener más información
findal consultar su página de manual:fuente
Como las otras respuestas no se ajustan a mi propósito y las preguntas, este shell se prueba en CentOS 7:
fuente