tag kid3 linux shell sorting

linux - tag - kid3



Clasificación en el último campo de una línea (10)

Quiero que esta lista se clasifique según los nombres de archivo, que comienzan con números que indican el orden en que se deben leer los archivos.

find . | sed ''s#.*/##'' | sort

el sed reemplaza todas las partes de la lista de resultados que terminan en barras. Los nombres de archivo son los que quedan, y usted los clasifica en eso.

¿Cuál es la forma más sencilla de ordenar una lista de líneas, clasificando en el último campo de cada línea? Cada línea puede tener un número variable de campos.

Algo como

sort -k -1

es lo que quiero, pero sort (1) no toma números negativos para seleccionar campos desde el final en lugar del inicio.

También me gustaría poder elegir el delimitador de campo también.

Edición: para agregar algo de especificidad a la pregunta: la lista que quiero ordenar es una lista de rutas de acceso. Las rutas de acceso pueden ser de una profundidad arbitraria, de ahí el número variable de campos. Quiero ordenar en el componente de nombre de archivo.

Esta información adicional puede cambiar la forma en que se manipula la línea para extraer el último campo (se puede usar el nombre base (1)), pero no cambia los requisitos de clasificación.

p.ej

/a/b/c/10-foo /a/b/c/20-bar /a/b/c/50-baz /a/d/30-bob /a/e/f/g/h/01-do-this-first /a/e/f/g/h/99-local

Quiero que esta lista se clasifique según los nombres de archivo, que comienzan con números que indican el orden en que se deben leer los archivos.

He añadido mi respuesta a continuación, que es cómo lo estoy haciendo actualmente. Esperaba que hubiera una forma más simple, tal vez una utilidad de ordenación diferente, tal vez sin necesidad de manipular los datos.


Aquí hay una línea de comando de Perl (tenga en cuenta que su shell puede requerir que escape los $ s):

perl -e "print sort {(split ''/'', $a)[-1] <=> (split ''/'', $b)[-1]} <>"

Simplemente coloque la lista en ella o, si la lista está en un archivo, coloque el nombre del archivo al final de la línea de comando.

Tenga en cuenta que esta secuencia de comandos no cambia realmente los datos, por lo que no debe tener cuidado con el delimitador que utiliza.

Aquí está la salida de la muestra:

>perl -e "print sort {(split ''/'', $a)[-1] <=> (split ''/'', $b)[-1]} " files.txt /a/e/f/g/h/01-do-this-first /a/b/c/10-foo /a/b/c/20-bar /a/d/30-bob /a/b/c/50-baz /a/e/f/g/h/99-local


Aquí hay una versión de Python oneliner, tenga en cuenta que asume que el campo es entero, puede cambiarlo según sea necesario.

echo file.txt | python3 -c ''import sys; list(map(sys.stdout.write, sorted(sys.stdin, key=lambda x: int(x.rsplit(" ", 1)[-1]))))''


Creo que la única solución sería usar awk :

  1. Pon el último campo al frente usando awk .
  2. Ordenar líneas.
  3. Ponga el primer campo al final de nuevo.

Reemplace el último delimitador en la línea con otro delimitador que de otra manera no aparece en la lista, ordene en el segundo campo usando ese otro delimitador como delimitador de clasificación (1), y luego revertir el cambio del delimitador.

delim=/ new_delim=" " cat $list / | sed "s|/(.*/)$delim|/1$new_delim|" / | sort -t"$new_delim" -k 2,2 / | sed "s|$new_delim|$delim|"

El problema es saber qué delimitador usar que no aparece en la lista. Puede hacer varias pasadas sobre la lista y luego grep para una sucesión de delimitadores potenciales, pero todo es bastante desagradable, especialmente cuando el concepto de "ordenar en el último campo de una línea" se expresa de manera muy simple, pero la solución no lo es.

Edición: un delimitador seguro para usar para $ new_delim es NUL ya que no puede aparecer en los nombres de archivo, pero no sé cómo colocar un carácter NUL en un script de shell bourne / POSIX (no bash) y si sort y sed se manejarán adecuadamente eso.


Una sola línea en perl para invertir el orden de los campos en una línea:

perl -lne ''print join " ", reverse split / /''

Podría usarlo una vez, canalizar la salida para ordenar, luego volver a canalizarla y lograría lo que desea. Puede cambiar / / a / +/ para que exprima espacios. Y, por supuesto, eres libre de usar cualquier expresión regular que quieras para dividir las líneas.


algo como esto

awk ''{print $NF"|"$0}'' file | sort -t"|" -k1 | awk -F"|" ''{print $NF }''


sort permite especificar el delimitador con la opción -t , si lo recuerdo bien. Para calcular el último campo, puede hacer algo como contar el número de delimitadores en una línea y sumar uno. Por ejemplo, algo como esto (asumiendo el delimitador ":"):

d=`head -1 FILE | tr -cd : | wc -c` d=`expr $d + 1`

( $d ahora contiene el último índice de campo).


#!/usr/bin/ruby f = ARGF.read lines = f.lines broken = lines.map {|l| l.split(/:/) } sorted = broken.sort {|a, b| a[-1] <=> b[-1] } fixed = sorted.map {|s| s.join(":") } puts fixed

Si todas las respuestas tienen que ver con perl o awk, también podría resolverlo todo en el lenguaje de scripting. (Por cierto, lo intenté en Perl primero y rápidamente recordé que no me gustan las listas de listas de Perl. Me encantaría ver la versión de un gurú de Perl).


awk ''{print $NF,$0}'' file | sort | cut -f2- -d'' ''

Básicamente, este comando hace:

  1. Repita el último campo al principio, separado con un espacio en blanco (OFS predeterminado)
  2. Ordene, resuelva los nombres de archivo duplicados usando la ruta completa ($ 0) para ordenar
  3. Corte el primer campo repetido, f2- significa desde el segundo campo hasta el último