¿Cómo encontrar archivos en subdirecciones y ordenarlos por nombre de archivo en un solo comando?


9

Resultado de un hallazgo normal usando find . ! -path "./build*" -name "*.txt":

./tool/001-sub.txt
./tool/000-main.txt
./zo/001-int.txt
./zo/id/002-and.txt
./as/002-mod.txt

y cuando se ordena con sort -n:

./as/002-mod.txt
./tool/000-main.txt
./tool/001-sub.txt
./zo/001-int.txt
./zo/id/002-and.txt

sin embargo, la salida deseada es:

./tool/000-main.txt
./zo/001-int.txt
./tool/001-sub.txt
./zo/id/002-and.txt
./as/002-mod.txt

lo que significa que la salida se ordena solo en nombre de archivo , pero la información de la carpeta debe mantenerse como parte de la salida.

Editar : Haga que el ejemplo sea más complicado ya que la estructura del subdirectorio puede incluir más de un nivel.


2
Vea esta pregunta que hice en SO: stackoverflow.com/questions/3222810/…
— camh

@camh: si es posible, me gustaría usar solo comandos Unix. En cualquier caso, mi pregunta es prácticamente un duplicado de la suya. ¿Puede transferir la mejor solución a este hilo (mantenga un enlace al original de todos modos) para que pueda marcar como la solución?
— Unode

Si @Shawn realiza los cambios que sugerí en mi comentario (usar en -printflugar de awk), creo que esa es la mejor solución. He revisado mi implementación original para usar este método.
— camh

Respuestas:


9

Debe ordenar por el último campo (considerando /como un separador de campo). Desafortunadamente, no puedo pensar en una herramienta que pueda hacer esto cuando la cantidad de campos varía (si solo sort -kpudiera tomar valores negativos).

Para evitar esto, tendrás que hacer una decoración-ordenar-decorar. Es decir, tome el nombre del archivo y póngalo al principio seguido de un separador de campo, luego haga una ordenación, luego elimine la primera columna y el separador de campo.

find . ! -path "./build*" -name "*.txt" |\
    awk -vFS=/ -vOFS=/ '{ print $NF,$0 }' |\
    sort -n -t / |\
    cut -f2- -d/

Ese awkcomando dice que el separador de campo FS está configurado en /; Esto afecta la forma en que lee los campos. El separador de campo de salida OFS también se establece en /; Esto afecta la forma en que imprime los registros. La siguiente declaración dice imprimir la última columna ( NFes el número de campos en el registro, por lo que también es el índice del último campo), así como el registro completo ( $0es el registro completo); los imprimirá con la OFS entre ellos. Luego se edita la lista sort, que se trata /como el separador de campo, ya que tenemos el nombre de archivo primero en el registro, se ordenará por eso. Luego, las cutimpresiones solo los campos 2 hasta el final, nuevamente se tratan /como el separador de campo.


3
Como esto es con find (1), puede omitir la parte awk y usar-printf '%f/%p\n'
— camh

de hecho nuestra configuración es un poco más complicada. Incluye profundidades de subdirección variables. Editó la pregunta para reflejar este hecho. Mis disculpas por no incluir esto al principio.
— Unode

1
@Unode: la solución de Shawn maneja bien la profundidad variable, es la solución canónica a este problema (hasta pequeñas variaciones).
— Gilles 'SO- deja de ser malvado'

4

Usaría los archivos '-printf' para generar el nombre y la ruta, ordenar por nombre y cortar el nombre en un último paso. '###' es solo un marcador, para ayudar a cortar.

find -name "*.txt" -printf "%f###%p\n" | sort -n | sed 's/.*###//'

% f imprime el nombre del archivo,% p la ruta completa.

Simplifiqué el comando de búsqueda para ponerlo en una línea, por supuesto, dejarías la ! -path "./build*"parte.


3

En zsh ≥4.3.10:

print -l -- **/*.txt~build*(oe\''REPLY=${REPLY:t}'\')
  • **/*.txtcoincide *.txten el directorio actual y sus subdirectorios de forma recursiva .
  • ~build* excluye coincidencias cuyo texto comienza con build*(me gusta ! -path './build*'). (Necesitas setopt extended_globprimero)
  • (oe\''…'\')es un calificador global de clasificación . REPLY=…construye la cadena para ordenar de la cadena para devolver.
  • ${REPLY:t}es el nombre base ("cola") de la ruta.

Mucha magia concatenada. Interesante pero estamos limitados a la sintaxis sh. +1
— unode
Al usar nuestro sitio, usted reconoce que ha leído y comprende nuestra Política de Cookies y Política de Privacidad.
Licensed under cc by-sa 3.0 with attribution required.