Ordenar una sección de un archivo

8

¿Es posible ordenar entre dos cadenas en un archivo grande?

Por ejemplo, el archivo actual es como:

    0cf  Front Brake
    0d0  Rear Brake
    0ce  Handle Bars
HUT 03  VR Controls
    009  Vest
    001  Belt
    002  Body Suit
    020  Stereo Enable
    003  Flexor
    007  Hand Tracker
    004  Glove
    006  Head Mounted Display
    008  Oculometer
    00a  Animatronic Device
    000  Unidentified
    021  Display Enable
    005  Head Tracker
HUT 04  Sport Controls
    000  Unidentified
    002  Golf Club
    001  Baseball Bat

Y la salida deseada es como:

    0ce  Handle Bars
    0cf  Front Brake
    0d0  Rear Brake
HUT 03  VR Controls
    000  Unidentified
    001  Belt
    002  Body Suit
    003  Flexor
    004  Glove
    005  Head Tracker
    006  Head Mounted Display
    007  Hand Tracker
    008  Oculometer
    009  Vest
    00a  Animatronic Device
    020  Stereo Enable
    021  Display Enable
HUT 04  Sport Controls
    000  Unidentified
    001  Baseball Bat
    002  Golf Club

Aquí, la sección HUT 03 VR Controls y HUT 04 Sports Controls está ordenada.

En un archivo dado, los encabezados de sección comienzan con caracteres que no son espacios, mientras que el contenido de la sección siempre comienza con espacio o tabulación. Como este archivo tiene más de 100 secciones, no será posible codificar el nombre de la sección en el script / comando

SHW
fuente
¿Las secciones están en números de línea fijos o están definidas por patrones?
Sparhawk
Los encabezados de sección comienzan como un primer carácter de línea, mientras que su contenido comienza con espacio / tabulación. Las secciones no están en números fijos.
SHW
¿Desea ordenar solo una sección (según el título de la pregunta y el texto), o cada sección?
Kusalananda
@Kusalananda Estoy de acuerdo en que la pregunta es ambigua en este punto; sin embargo, la salida de ejemplo muestra todas las secciones (o partes de las mismas) ordenadas.
Stephen Kitt
No diría que "HUT" usa caracteres hexadecimales.
jlliagre

Respuestas:

7

En Python:

#!/usr/bin/python3

with open("file.txt", "r") as ins:
    lines = []
    for line in ins:
        if line.startswith((" ", "\t")):
            lines.append(line)
        else:
            lines.sort()
            print(*lines, end = "", sep = "")
            print(line, end = "")
            lines = []
    lines.sort()
    print(*lines, end = "", sep = "")

Esto ordena todas las secciones (por separado), no solo aquellas entre dos líneas específicas.

Stephen Kitt
fuente
¡Soberbio! Esto es golpe maestro.
SHW
6

Por diversión, aquí hay una manera de ordenar una sola sección usando ex:

ex file <<%
/HUT
+1,/HUT/-1!sort
w file.sorted
q
%
jlliagre
fuente
6
$ awk 'BEGIN { OFS="\t"; s=0 } /^[^[:blank:]]/ { print ++s "\b", $0; next } { print s, $0 }' file | sort -n | cut -f 2-
    0ce  Handle Bars
    0cf  Front Brake
    0d0  Rear Brake
HUT 03  VR Controls
    000  Unidentified
    001  Belt
    002  Body Suit
    003  Flexor
    004  Glove
    005  Head Tracker
    006  Head Mounted Display
    007  Hand Tracker
    008  Oculometer
    009  Vest
    00a  Animatronic Device
    020  Stereo Enable
    021  Display Enable
HUT 04  Sport Controls
    000  Unidentified
    001  Baseball Bat
    002  Golf Club

Esto se usa awkpara agregar un número (y un separador de tabulación) delante de cada línea correspondiente a la sección en la que se encuentra esta línea. Para los encabezados de sección, agregamos un número seguido de un carácter de retroceso (solo porque el retroceso se ordena antes de las pestañas). Luego, simplemente ordenamos los datos resultantes de estos números antes de eliminarlos y los separadores de pestañas agregados.

Los encabezados de sección se detectan al buscar caracteres no en blanco al comienzo de la línea.

Kusalananda
fuente
1
¡Agradable! Me gusta especialmente el truco de retroceso.
Stephen Kitt
1
Con este enfoque, también podría usar el número de sección (después del HUTcampo) como prefijo, para ordenar las secciones también.
Stephen Kitt
3

Podrías conseguir awky sortcooperar para hacer el trabajo.

awk '
    /^[[:blank:]]/{print | "sort"; next}
    {close("sort"); print}; 
    END{close("sort")}
' file
  • Canaliza cada línea de contenido en sort
  • Llamar closeen sortcuando se encuentra un marcador de sección; esto hace sortque su salida se descargue a la salida estándar y salga
  • Imprimir el marcador de sección
  • Una nueva instancia de sorttoma de control para las líneas de contenido que siguen al marcador de sección
  • Llamar closeen sortal final de cuidar de los contenidos de fuga
iruvar
fuente
1

Para tales tareas, a menudo me resulta tedioso escribir un guión. Si solo necesita hacerse una vez y tal vez para algunos archivos, puede hacerse bastante bien usando una macro si abre el archivo vimy escribe:

  • GoFAKE SECTION<ESC>: agregue una sección falsa al final y asegúrese de que esté al comienzo de la línea (puede tenerla cindento autoindenthabilitarla). Esto también es necesario para ordenar la última sección.
  • gg: volver al inicio del archivo, luego el archivo comienza con una sección baja una línea con j
  • qq: comienza a grabar una macro para registrar q
  • v: iniciar selección
  • /^\S\+<Enter>: busca el inicio de la siguiente sección
  • k: hasta una línea
  • :!sort<Enter: ordenar la sección
  • nj: vaya al primer elemento de la siguiente sección
  • q: deja de grabar la macro
  • @q: repite la macro
  • 100@@: repite la macro varias veces (hasta que no queden secciones)
  • dd: elimina la última línea del archivo (el FAKE SECTION)

Es posible que desee :set lazyredrawacelerar la ejecución de macros.

MarcDefiant
fuente