Ordenar archivos por el número más alto en el nombre del archivo

Ordenar archivos por el número más alto en el nombre del archivo

Tengo un montón de archivos, todos con nombres así:

name_file-1.txt
name_file-2.txt
name_file-3.txt
some_other_file-1.txt
some_other_file-2.txt

Hay miles de nombres de archivos diferentes, algunos con solo uno -1.txtal final, otros con -1.txt, -2.txt...-60.txt

Necesito copiar los números más altos de cada archivo, entonces name_file-3.txt. some_other_file-2.txt¿Cómo hago eso en una línea de comando de Linux?

Respuesta1

Con zsh:

typeset -A greatest
for f (*-*(n)) greatest[${f%-*}]=$f
cp -- $greatest /destination
  • *-*(n): archivos no ocultos cuyo nombre contiene un -( *-*), ordenados numéricamente ( (n)calificador global).
  • ${f%-*}: parte del nombre del archivo hasta el extremo derecho -(o hasta el final si no hay -).
  • $greatest: se expande al espacio no vacíovaloresde las matrices asociativas. Entonces, aquí, para los archivos que comparten la misma raíz, solo se expandirá el archivo con el mayor número.

Respuesta2

files=(*)
mapfile -t prefixes < <(printf "%s\n" "${files[@]%-*}" | sort -u)
for p in "${prefixes[@]}"; do ls -v "$p"* | tail -1; done
name_file-3.txt
some_other_file-2.txt

Y luego copiarlos a algún otro directorio:

for ...; done | xargs cp -t /destination/directory

Respuesta3

Si los archivos están en el directorio de trabajo actual y sus nombres se ajustan a los ejemplos (un solo guión que precede a un número), la siguiente canalización compatible con POSIX debería funcionar:

ls | sort -t- -k1,1 -k2,2rn | awk -F- 'k!=$1 {print; k=$1}' | pax -rw /path/to/dir

El componente awk se puede reemplazar por sort -u, si la opción -u del sort es estable (de modo que la primera línea de un conjunto siempre se elige para representar ese conjunto). POSIX no requiere esta estabilidad, pero, según sus manuales, las implementaciones {Free,Net,Open}BSD y GNU la proporcionan. Si te gusta tentar al destino:

ls | sort -t- -k1,1 -k2,2rn | sort -mut- -k1,1 | pax -rw /path/to/dir

En cualquier caso, el directorio de destino no debe estar en el directorio de trabajo actual.

Respuesta4

Dividí el archivo en partes delimitadas por tabulaciones para un análisis de nombres de archivo más confiable y personalizable, luego usé awk para encontrar la clasificación más alta de cada una e informar. Pruebe primero cada parte del proceso antes de pasar a la siguiente.

find DIR -type f <other find criteron> -print | 
perl -lne 'print join("\t",(/^(.*?-)(\d+)(\.\w+)$/))' |
awk -F\\t '$2 > f[$1] { f[$1]=$2;e[$1]=$3; } END { for (k in f) { print k f[k] e[k] }}' |
xargs cp -t <desination_directory>

El script awk coloca cada nombre de archivo en una entrada de matriz asociada, manteniendo siempre el rango más alto encontrado. La extensión se almacena en su propia matriz. Una vez procesadas todas las entradas, se generan todas las entradas de la matriz, una por línea. La xargs cp -tlínea copia todos los archivos al directorio que especifique.

Hay otro método queno funcionarámuy bien si los números son mayores que 9 y no están rellenos con 0. Ese método ordena los archivos lexicográficamente y luego, al analizar la lista, la primera parte cambia y se utiliza el nombre de archivo visto más recientemente. Cuando los nombres de los archivos son así, no funcionará:

file-9.txt
file-10.txt

porque el archivo-10.txt aparecerá antes que el archivo-9. El script awk anterior hace una comparación numérica.

ADVERTENCIA: Los nombres de archivos con tabulaciones y nuevas líneas harán que esto se bloquee.

ADVERTENCIA 2: Si son posibles varias extensiones por prefijo de nombre de archivo, tendremos que hacer algunos ajustes para hacerlo bien.

información relacionada