Pregunta:
Estoy tratando de ordenar en varias columnas. Los resultados no son los esperados.
Aquí están mis datos (people.txt):
Simon Strange 62
Pete Brown 37
Mark Brown 46
Stefan Heinz 52
Tony Bedford 50
John Strange 51
Fred Bloggs 22
James Bedford 21
Emily Bedford 18
Ana Villamor 44
Alice Villamor 50
Francis Chepstow 56
Lo siguiente funciona correctamente:
bash-3.2$ sort -k2 -k3 <people.txt
Emily Bedford 18
James Bedford 21
Tony Bedford 50
Fred Bloggs 22
Pete Brown 37
Mark Brown 46
Francis Chepstow 56
Stefan Heinz 52
John Strange 51
Simon Strange 62
Ana Villamor 44
Alice Villamor 50
Pero lo siguiente no funciona como se esperaba:
bash-3.2$ sort -k2 -k1 <people.txt
Emily Bedford 18
James Bedford 21
Tony Bedford 50
Fred Bloggs 22
Pete Brown 37
Mark Brown 46
Francis Chepstow 56
Stefan Heinz 52
John Strange 51
Simon Strange 62
Ana Villamor 44
Alice Villamor 50
Estaba tratando de ordenar por apellido y luego por nombre, pero verá que los Villamors no están en el orden correcto. Esperaba ordenar por apellido, y luego, cuando los apellidos coincidieran, ordenar por nombre.
Parece que hay algo sobre cómo debería funcionar esto que no entiendo. Podría hacer esto de otra manera, por supuesto (usando awk), pero quiero entender el tipo.
Estoy usando el shell Bash estándar en Mac OS X.
Respuesta:
Una especificación clave como -k2
significa tener en cuenta todos los campos desde 2 hasta el final de la línea. Entonces Villamor 44
termina antes que Villamor 50
. Dado que estos dos no son iguales, la primera comparación en la sort -k2 -k1
es suficiente para discriminar estas dos líneas, y la segunda clave de clasificación -k1
no se invoca. Si los dos Villamors hubieran tenido la misma edad, -k1
habría provocado que se clasificaran por nombre.
Para ordenar por una sola columna, use -k2,2
como especificación clave. Esto significa utilizar los campos del n. ° 2 al n. ° 2, es decir, solo el segundo campo.
sort -k2 -k3 <people.txt
es redundante: es equivalente a sort -k2 <people.txt
. Para ordenar por apellidos, luego por nombre y luego por edad, ejecute el siguiente comando:
sort -k2,2 -k1,1 <people.txt
o, de forma equivalente, sort -k2,2 -k1 <people.txt
ya que solo existen estos tres campos y los separadores son los mismos. De hecho, obtendrá el mismo efecto de sort -k2,2 <people.txt
, porque sort
usa toda la línea como último recurso cuando todas las claves en un subconjunto de líneas son idénticas.
También tenga en cuenta que el separador de campo predeterminado es la transición entre un espacio en blanco y uno que no está en blanco, por lo que las claves incluirán los espacios en blanco iniciales (en su ejemplo, para la primera línea, la primera clave será "Emily"
, pero la segunda clave " Bedford"
. Agrega la opción -b
para quitar esos espacios en blanco:
sort -b -k2,2 -k1,1
También se puede hacer por clave agregando el indicador b
al final de la especificación de inicio de clave:
sort -k2b,2 -k1,1 <people.txt
Pero algo a tener en cuenta: tan pronto como agregue uno de esos indicadores a la especificación de clave, los indicadores globales (como -n
, -r
…) ya no se aplican a ellos, por lo que es mejor evitar mezclar indicadores por clave y banderas globales.