Ordenar un archivo según un campo que comienza con una cadena

Ordenar un archivo según un campo que comienza con una cadena

Supongamos que tengo un archivo tan estructurado

/home/zz/AUTHORBOOKS/Author-Chomsky-Who-Rules-the-World.epub
/home/zz/AUTHORBOOKS/Author-Cioran-Il-nulla.epub
/home/zz/BOOKS/Author-Artemis-Mathematica-Examples.nb
/home/zz/Books/Author-Zigniwe-Hisory-Medicine.pdf
/home/z1/OLDBOOKS1/OLDBOOKS2/Author-Watanabe-Waterloo.pdf
/home/z2/OLDBOOKS1/OLDBOOKS2/Author-Barbero-Lepanto.epub.pdf

Me gustaría un archivo ordenado de esta manera:

/home/zz/BOOKS/Author-Artemis-Mathematica-Examples.nb
/home/z2/OLDBOOKS1/OLDBOOKS2/Author-Barbero-Lepanto.epub.pdf
/home/zz/AUTHORBOOKS/Author-Chomsky-Who-Rules-the-World.epub
/home/zz/AUTHORBOOKS/Author-Cioran-Il-nulla.epub
/home/z1/OLDBOOKS1/OLDBOOKS2/Author-Watanabe-Waterloo.pdf
/home/zz/Books/Author-Zigniwe-History-Medicine.pdf

Es decir, alfabéticamente, según la cadenaAuthor-...

Como puede ver, la posición de Author-...no es constante.

¿Cómo puedo hacer esto?

Respuesta1

Pruebe el siguiente bashcomando:

sort -t- -d -k2 -o output.txt input.txt

Tiene cuatro opciones más el nombre del archivo de entrada input.txt. Si este archivo no está en el directorio actual, deberá proporcionar el archivo path/to/the/folder/input.txt. Las opciones y sus argumentos son los siguientes:

  • -t marca el separador de campos. Lo usamos -como separador, para que todo lo que esté antes y después -se considere columnas separadas.
  • -d indica clasificación por diccionario. Por ejemplo, Apple está antes que Berry.
  • -k2 indica la columna por la cual ordenar, en este caso la segunda columna. Tenga en cuenta que la primera columna es todo lo que hay antes de la primera -. Por ejemplo, /home/zz/BOOKS/Author. La segunda columna está entre la primera y la segunda -, es decir Artemis.
  • -o output.txtredirige la salida ordenada a un archivo en lugar de a la terminal.

Espero que esto ayude

Respuesta2

Aunque es excesivo para el presente ejemplo debido a lasolución propuesta en la respuesta del usuario68186, generalmente podrías hacer algo como esto en GNU awk:

gawk -F/ '
  function mycmp(i1,v1,i2,v2) {
    m = split(v1,a);
    n = split(v2,b);
    return a[m]"" > b[n]"" ? 1 : a[m]"" < b[n]"" ? -1 : 0
  }
  {
    lines[NR] = $0
  }
  END {
    PROCINFO["sorted_in"] = "mycmp";
    for(i in lines) print lines[i]
  }
' file

Tenga en cuenta que ordena según el valor léxico de todo lo que sigue al último /, por lo que si el formato es Author-<author name>-<title>.<extension>ese, será

  • la cadena fija Author-(que no tiene ningún efecto, ya que tiene el mismo peso para todas las líneas); entonces
  • <author name>-; entonces
  • <title>.; entonces
  • <extension>

Esto es similar a cómo funciona sortel KEYDEF simple de GNU -t- -k2, es decir, la clave de clasificación efectiva comienza desde <author name>y continúa hasta el final de la línea.

Se omite un delimitador explícito en las splitllamadas para que hereden el valor de FS, lo que facilita el cambio en sistemas que utilizan un separador de ruta diferente. Las cadenas vacías adjuntas ""en la mycmpfunción fuerzan la comparación léxica incluso si los nombres de archivos son numéricos; consulte, por ejemploCómo awk convierte entre cadenas y números


Si prefiere seguir con el sortcomando, puede aprovechar GNU awkComunicaciones bidireccionales con otro procesoa:

  • duplicar el último /campo separado al comienzo de la cadena
  • pasar el resultado a un sortcomando
  • Vuelva a leer el resultado ordenado, elimine el prefijo duplicado e imprima

es decir

gawk -F/ '
  BEGIN {OFS=FS; cmd = "sort -d"} 
  {print $NF $0 |& cmd} 
  END {
    close(cmd,"to"); 
    while(cmd |& getline){$1 = ""; print};
    close(cmd,"from")
  }
' file

Hay un pequeño truco aquí en el sentido de que las rutas absolutas (las líneas comienzan con /) implican un campo vacío inicial; para manejar rutas relativas, necesitaría cambiar print $NF $0para print $NF,$0insertar el separador "faltante", y luego tal vez usar una expresión regular sub()en lugar de la más simple $1 = ""para eliminar el elemento principal.

Además de ser potencialmente más rápido y más eficiente en memoria que la gawksolución pura, esto permite sortagregar otras opciones directamente, por ejemplo. cmd = "sort -d -t " FS " -k1,1r".

información relacionada