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 bash
comando:
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 decirArtemis
. - -o
output.txt
redirige 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 sort
el 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 split
llamadas 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 mycmp
funció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 sort
comando, puede aprovechar GNU awkComunicaciones bidireccionales con otro procesoa:
- duplicar el último
/
campo separado al comienzo de la cadena - pasar el resultado a un
sort
comando - 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 $0
para print $NF,$0
insertar 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 gawk
solución pura, esto permite sort
agregar otras opciones directamente, por ejemplo. cmd = "sort -d -t " FS " -k1,1r"
.