Digamos que tengo esta lista:

sharpest
  tool
  in
the
  shed
im
  not
  the

¿Cómo puedo ordenar alfabéticamente por líneas no sangradas y preservar grupos de líneas? Lo anterior debe convertirse en:

im
  not
  the
sharpest
  tool
  in
the
  shed

Preguntas similares existen aquí y aquí pero parece que no puedo hacer que funcionen para mi ejemplo.

Ideas esperanzadoras hasta ahora

  • ¿Tal vez podría usar grep -n de alguna manera, ya que me da los números de línea? Estaba pensando en obtener primero los números de línea, luego ordenar. Supongo que de alguna manera necesitaría calcular un rango de línea antes de ordenar, y luego buscar el rango de líneas de alguna manera. ¡Ni siquiera puedo pensar cómo hacer esto!
  • también parecen prometedoras, pero el mismo trato; sed 1,2p y más ejemplos aquí.
5
Nick Bull 22 feb. 2018 a las 13:42

4 respuestas

La mejor respuesta

Si perl está bien:

$ perl -0777 -ne 'print sort split /\n\K(?=\S)/' ip.txt
im
  not
  the
sharpest
  tool
  in
the
  shed
  • -0777 sorbe todo el archivo, por lo que la solución no es adecuada si la entrada es demasiado grande
  • split /\n\K(?=\S)/ proporciona una matriz utilizando caracteres de nueva línea seguidos de caracteres que no son espacios en blanco como indicación de división
  • sort para ordenar la matriz
3
Sundeep 22 feb. 2018 a las 10:57

Puede usar esta función asort en un solo comando gnu awk:

awk '{if (/^[^[:blank:]]/) {k=$1; keys[++i]=k} else arr[k] = arr[k] $0 RS} 
END{n=asort(keys); for (i=1; i<=n; i++) printf "%s\n%s", keys[i], arr[keys[i]]}' file
im
  not
  the
sharpest
  tool
  in
the
  shed

Código de demostración


Solución alternativa usando awk + sort:

awk 'FNR==NR{if (/^[^[:blank:]]/) k=$1; else arr[k] = arr[k] $0 RS; next}
{printf "%s\n%s", $1, arr[$1]}' file <(grep '^[^[:blank:]]' file | sort)
im
  not
  the
sharpest
  tool
  in
the
  shed

Editar: cumplimiento POSIX:

#!/bin/sh
awk 'FNR==NR{if (/^[^[:blank:]]/) k=$1; else arr[k] = arr[k] $0 RS; next} {printf "%s\n%s", $1, arr[$1]}' file | 
  grep '^[![:blank:]]' file | 
  sort
3
anubhava 22 feb. 2018 a las 11:32

Con un solo comando GNU awk :

awk 'BEGIN{ PROCINFO["sorted_in"] = "@ind_str_asc" }
     /^[^[:space:]]+/{ k = $1; a[k]; next }
     { a[k] = (a[k]? a[k] ORS : "")$0 }
     END{ for(i in a) print i ORS a[i] }' file

La salida:

im
  not
  the
sharpest
  tool
  in
the
  shed
1
RomanPerekhrest 22 feb. 2018 a las 11:10

awk one-liner

$ awk '/^\w/{k=$1; a[k]=k; next} {a[k]=a[k] RS $0} END{ n=asorti(a,b); for(i=1; i<=n; i++) print a[b[i]] }' file
im
  not
  the
sharpest
  tool
  in
the
  shed
0
Rahul Verma 22 feb. 2018 a las 16:37