2010-08-16 13 views
6

Soy nuevo en el shell scripting, por lo que necesito ayuda, necesito saber cómo solucionar este problema.Obtenga el archivo más reciente basado en la marca de tiempo

Tengo un directorio que contiene archivos en el siguiente formato. Los archivos están en un diretory llamada entrante///externa de datos

AA_20100806.dat 
AA_20100807.dat 
AA_20100808.dat 
AA_20100809.dat 
AA_20100810.dat 
AA_20100811.dat 
AA_20100812.dat 

Como se puede ver el nombre del archivo incluye una marca de tiempo. es decir [RANGE] _ [AAAAMMDD] .dat

Lo que debo hacer es averiguar cuál de estos archivos tiene la fecha más reciente utilizando la marca de tiempo en el nombre de archivo no la marca de tiempo del sistema y almacenar el nombre de archivo en una variable y moverlo a otro directorio y mueva el resto a un directorio diferente.

+0

¿Puede [RANGE] ser una combinación de dos caracteres? Eso hace una gran diferencia, como probablemente notará por las respuestas ya dadas. –

+0

Sí, pueden ser diferentes. Y también la misma carpeta contendrá otros tipos de archivos con nombres que no son los que se muestran arriba. – ziggy

Respuesta

17

Para aquellos que sólo quieren una respuesta, aquí está:

ls | sort -n -t _ -k 2 | tail -1 

Aquí es el proceso de pensamiento que me condujo aquí.

Voy a suponer que la porción [RANGE] podría ser cualquier cosa.

Comience con lo que sabemos. Directorio

  • de trabajo:///externas de datos entrantes
  • formato de los archivos: [RANGE] _ [AAAAMMDD] .dat

Tenemos que encontrar el archivo más reciente [AAAAMMDD] en el directorio, y necesitamos almacenar ese nombre de archivo.

herramientas disponibles (sólo estoy enumerando las herramientas pertinentes para este problema ... la identificación de ellos se hace más fácil con la práctica):

Supongo que no necesitamos sed, ya que podemos trabajar con toda la salida del comando ls.La orden ls, awk, clasificar, y la cola podemos obtener el archivo correcto al igual que (tenga en cuenta que tendrá que comprobar la sintaxis en contra de lo aceptará su sistema operativo):

NEWESTFILE=`ls | awk -F_ '{print $1 $2}' | sort -n -k 2,2 | tail -1` 

Entonces es sólo una cuestión de volver a poner el guión bajo, lo cual no debería ser demasiado difícil.

EDIT: Tenía un poco de tiempo, así que me puse a arreglar el comando, al menos para usar en Solaris.

Aquí está la primera pasada intrincada (esto supone que TODOS los archivos en el directorio están en el mismo formato: [RANGE] _ [aaaammdd] .dat). Estoy apostando que hay mejores maneras de hacer esto, pero esto funciona con mis propios datos de prueba (de hecho, he encontrado una mejor forma en este momento; véase más adelante):

ls | awk -F_ '{print $1 " " $2}' | sort -n -k 2 | tail -1 | sed 's/ /_/' 

... al escribir esto , Descubrí que puedes hacer esto:

ls | sort -n -t _ -k 2 | tail -1 

Lo dividiré en partes.

ls 

Bastante simple ... obtiene la lista de directorios, solo nombres de archivos. Ahora puedo conectarlo a la siguiente orden.

awk -F_ '{print $1 " " $2}' 

Este es el comando AWK. te permite tomar una línea de entrada y modificarla de una manera específica. Aquí, todo lo que estoy haciendo es especificar que awk debería interrumpir la entrada donde haya un underscord (_). Lo hago con la opción -F. Esto me da dos mitades de cada nombre de archivo. Luego le digo a awk que publique la primera mitad ($ 1), seguido de un espacio ("") , seguido de la segunda mitad ($ 2). Tenga en cuenta que el espacio era la parte que faltaba en mi sugerencia inicial. Además, esto no es necesario, ya que puede especificar un separador en el comando de ordenamiento a continuación.

Ahora la salida se divide en [RANGE] [aaaammdd] .dat en cada línea. Ahora podemos ordenar esto:

sort -n -k 2 

Esto toma la entrada y la ordena según el segundo campo. El comando de ordenamiento usa espacios en blanco como un separador por defecto. Mientras escribía esta actualización, encontré la documentación para ordenar, que le permite especificar el separador, por lo que AWK y SED son innecesarios. Tome la ls y písela de la siguiente manera:

sort -n -t _ -k 2 

Esto consigue el mismo resultado. Ahora sólo desea que el último archivo, por lo que:

tail -1 

Si utilizó awk para separar el archivo (que se acaba de añadir complejidad extra, así que no lo haga tímida), puede reemplazar el espacio con un guión de nuevo con SED:

sed 's/ /_/' 

buena información aquí, pero estoy seguro que la mayoría de la gente no va a leer hasta la parte inferior de esta manera.

+0

Intenté esto pero no funcionó. ¿Podría explicar qué está haciendo exactamente? gracias – ziggy

+0

Bueno, actualicé después de la prueba. Tuve que arreglar algo en mi comando awk y luego descubrí que realmente no era necesario. La solución está en la parte superior, la explicación es larga y no es necesaria, pero disfruté escribiéndola. –

+0

Funciona para mí. Por favor, ten a mi bebé. –

2

Probar:

$ ls -lr 

espero que ayude.

+0

Hola, ¿No lo ordenaría usando la marca de tiempo del sistema para el archivo? Estaba interesado en la marca de tiempo en el nombre de archivo real. Gracias – ziggy

+0

No, clasifica los archivos por nombre de acuerdo con su configuración regional. Si quisiera ordenar por la marca de tiempo del sistema, necesitaría el indicador '-t'. – igor

1

Uso:

ls -r -1 AA_*.dat | head -n 1 

(asumiendo que no hay otros archivos que coinciden con AA_*.dat)

3

Esto debería funcionar:

newest=$(ls | sort -t _ -k 2,2 | tail -n 1) 
others=($(ls | sort -t _ -k 2,2 | head -n -1)) 

mv "$newest" newdir 
mv "${others[@]}" otherdir 

no va a funcionar si hay espacios en los nombres de archivo si bien se puede modificar la variable IFS a afectar eso.

+0

Hola, ¿para qué sirven los corchetes? – ziggy

+0

@ziggy: ¿Te refieres al conjunto externo en la segunda línea? Crean una matriz que se usa en la última línea. –

+0

Hola Dennis, Me estaba refiriendo a los soportes redondos internos y externos. Intenté ejecutar lo anterior, pero los corchetes están causando errores de sintaxis. Estoy usando el caparazón bourne. ¿Son estos constructos específicos de shell Korn? – ziggy

1

Debido a la convención de nomenclatura de los archivos, el orden alfabético es el mismo que el orden de fecha. Estoy bastante seguro de que en bash '*' se expande alfabéticamente (pero no puede encontrar ninguna evidencia en la página del manual), ls ciertamente lo hace, por lo que el archivo con la fecha más reciente sería el último en orden alfabético.

Por lo tanto, en la fiesta de

mv $(ls | tail -1) first-directory 
mv * second-directory 

debe hacer el truco.

Si quieres ser más específico acerca de la elección de archivo, a continuación, sustituya * con otra cosa - por ejemplo AA_*.dat

+0

Esto también funciona, pero estoy tratando de evitar depender del sistema para hacer la clasificación por mí (es decir, a través del cmd ls). Gracias – ziggy

+0

¿Por qué no quieres confiar en 'ls' - ¿qué quieres decir con 'sistema'? – Beano

1

Mi solución a esto es similar a otros, pero un poco más simple.

ls -tr | tail -1 

¿Qué es en realidad hace es confiar en ls para ordenar la salida, a continuación, utiliza la cola para obtener el último nombre de archivo en la lista.

Esta solución no funcionará si el nombre de archivo que necesita tiene un punto inicial (por ejemplo, perfil).

Esta solución funciona si el nombre del archivo contiene un espacio.

Cuestiones relacionadas