2012-06-22 9 views
7

que tienen una estructura de archivos que tiene este aspecto¿Cómo encontrar el archivo en cada directorio con el número más alto como nombre de archivo?

./501.res/1.bin 
./503.res/1.bin 
./503.res/2.bin 
./504.res/1.bin 

y me gustaría encontrar la ruta de acceso al archivo .bin en cada directorio que tienen el mayor número como nombre de archivo. Lo que la salida Busco sería

./501.res/1.bin 
./503.res/2.bin 
./504.res/1.bin 

El número más alto puede tener un archivo es de 9.

Pregunta

¿Cómo hacer que en BASH?

me han llegado tan lejos como find .|grep bin|sort

Respuesta

1

¿Qué hay de usando awk? Usted puede obtener la primera aparición muy simple:

[[email protected] ~]$ cat data1 
./501.res/1.bin 
./503.res/1.bin 
./503.res/2.bin 
./504.res/1.bin 
[[email protected] ~]$ awk 'BEGIN{FS="."} a[$2] {next} {a[$2]=1} 1' data1 
./501.res/1.bin 
./503.res/1.bin 
./504.res/1.bin 
[[email protected] ~]$ 

para conseguir la última ocurrencia que pudiera tubería a través de un par de clases:

[[email protected] ~]$ sort -r data1 | awk 'BEGIN{FS="."} a[$2] {next} {a[$2]=1} 1' | sort 
./501.res/1.bin 
./503.res/2.bin 
./504.res/1.bin 
[[email protected] ~]$ 

Dado que usted está utilizando "encontrar" y "grep" , que probablemente podría hacer esto:

find . -name \*.bin -type f -print | sort -r | awk 'BEGIN{FS="."} a[$2] {next} {a[$2]=1} 1' | sort 

¿Cómo funciona esto?

El comando find tiene muchas opciones útiles, incluyendo la capacidad de seleccionar los archivos por glob, seleccione el tipo de archivo, etc. Su salida que ya conoce, y que se convierte en la entrada a sort -r.

Primero, ordenamos nuestros datos de entrada en reversa (sort -r). Esto asegura que dentro de cualquier directorio, el archivo con el número más alto aparecerá primero. Ese resultado se alimenta en awk. FS es el separador de campo, que hace $2 en cosas como "/ 501", "/ 502", etc. Las secuencias de comandos Awk tienen secciones en forma de condition {action} que se evalúan para cada línea de entrada. Si falta una condición, la acción se ejecuta en cada línea. Si "1" es la condición y no hay acción, imprime la línea. Así que este guión se divide de la siguiente manera:

  • a[$2] {next} - Si la matriz a con el subíndice $ 2 (es decir "/ 501") existe, acaba de saltar a la siguiente línea. De lo contrario ...
  • {a[$2]=1} - Colocar el conjunto un subíndice $ 2 a 1, por lo que en el futuro la primera condición se evaluará como cierto, entonces ...
  • 1 - imprimir la línea.

La salida de este script awk será la información que desee, pero en orden inverso. El sort final pone las cosas en el orden que esperabas.

Ahora ... eso es un montón de tuberías, y la ordenación puede ser un poco hambrienta de recursos cuando le pides que trate millones de líneas de entrada al mismo tiempo. Esta solución será perfectamente suficiente para pequeñas cantidades de archivos, pero si está tratando con grandes cantidades de información, infórmenos, y puedo encontrar una solución awk todo en uno (que llevará más de 60 segundos). escribir).

ACTUALIZACIÓN

sabio consejo

por Dennis', el script awk Incluí anterior podría mejorarse cambiando desde

BEGIN{FS="."} a[$2] {next} {a[$2]=1} 1 

a

BEGIN{FS="."} $2 in a {next} {a[$2]} 1 

Si bien esto es funcionalmente idéntica , la ventaja es que usted simplemente define los miembros de la matriz en lugar de asignarles valores, lo que puede ahorrar memoria o CPU. pendiente de su implementación de awk. En cualquier caso, es más limpio.

+0

Es mejor probar la existencia de un elemento en una matriz usando '$ 2 en a {next}'. Hacerlo de esa manera no crea nuevos elementos de matriz simplemente al referirse a ellos. Esto es lo que quise decir el otro día cuando discutíamos esto. Por cierto, si usa 'in' de esa manera, puede hacer' {a [$ 2]} 'en lugar de' {a [$ 2] = 1} ', pero cualquiera de los dos funcionará. –

+0

@DennisWilliamson, AH, ahora entiendo lo que estabas recibiendo el otro día. Muchas gracias por el puntero. :) – ghoti

0

me ocurrió con calle detrás de esta manera:

for dir in $(find . -mindepth 1 -type d | sort); do 
    file=$(ls "$dir" | sort | tail -n 1); 
    [ -n "$file" ] && (echo "$dir/$file"); 
done 

tal vez puede ser más simple

+0

creo que debería tener una especie -n como la numeración más alta que probablemente va 9. – bcelary

+0

@bcelary - OP indicado * "El número más alto de un archivo puede tener es 9. "* – ghoti

+0

Ah, lo siento. No se dio cuenta :) – bcelary

2

Probado:

find . -type d -name '*.res' | while read dir; do 
    find "$dir" -maxdepth 1 | sort -n | tail -n 1 
done 
+1

No muestra las rutas. – jcubic

+0

Solucionado. find ... -maxdepth 1 muestra la ruta correctamente ahora. Gracias. – bcelary

0

Si la invocación de una shell dentro hallazgo es una opción prueba este

find * -type d -exec sh -c "echo -n './'; ls -1 {}/*.bin | sort -n -r | head -n 1" \; 
3

están garantizados Globs a ampliarse con el fin léxico.

for dir in ./*/ 
do 
    files=($dir/*)   # create an array 
    echo "${files[@]: -1}" # access its last member 
done 
0

Y aquí es un trazador de líneas

find . -mindepth 1 -type d | sort | sed -e "s/.*/ls & | sort | tail -n 1 | xargs -I{} echo &\/{}/" | bash 
Cuestiones relacionadas