GNU/Linux >> Tutoriales Linux >  >> Linux

Alineación de texto complejo en bash

Si todos sus comandos y argumentos no contienen # y otro carácter (por ejemplo, el carácter ASCII proporcionado por el byte 1), puede insertar ese otro carácter como un separador adicional y usar column para alinear los comentarios (ver esta respuesta). Entonces, algo como:

$ sed $'s/#/\001#/' input-file | column -ets $'\001'
# Lines starting with # stay the same
# Empty lines stay the same
# only lines with comments should change

ls                                        # show all major directories
                                          # and other things

cd                                        # The cd command - change directory
                                          # will allow the user to change between file directories

touch                                     # The touch command, the make file command
                                          # allows users to make files using the Linux CLI #  example, cd ~

bar foo baz                               # foo foo foo

Si tu column no es compatible con -e para evitar la eliminación de líneas vacías, puede agregar algo a las líneas vacías (por ejemplo, un espacio o el carácter separador utilizado anteriormente):

$ sed $'s/#/\001#/;s/^$/\001/' input-file | column -ts $'\001'
# Lines starting with # stay the same
# Empty lines stay the same
# only lines with comments should change

ls                                        # show all major directories
                                          # and other things

cd                                        # The cd command - change directory
                                          # will allow the user to change between file directories

touch                                     # The touch command, the make file command
                                          # allows users to make files using the Linux CLI #  example, cd ~

bar foo baz                               # foo foo foo

El procesamiento de texto solo con el shell es un poco incómodo y puede ser propenso a errores (consulte "¿Por qué se considera una mala práctica usar un bucle de shell para procesar texto?"). Por lo general, es mejor usar otro lenguaje de programación para tareas como estas.

perl -ne 'if (/^([^#]+?)\s*#(.*)$/) { printf("%-16s#%s\n", $1, $2) } else { print }' file

Esto usa Perl para capturar el bit delante del # (descartando los espacios entre la última palabra y el # ) y el poco después. Si la coincidencia fue exitosa, asigna 16 ubicaciones de caracteres para el texto e imprime el texto con formato y el comentario. Si la coincidencia no tuvo éxito (porque la línea estaba en blanco o comenzaba con un # ), la línea se imprime sin modificación.

# Lines starting with # stay the same
# Empty lines stay the same
# only lines with comments should change

ls              # show all major directories
                # and other things

cd              # The cd command - change directory
                # will allow the user to change between file directories

touch           # The touch command, the make file command
                # allows users to make files using the Linux CLI #  example, cd ~

bar foo baz     # foo foo foo

Aquí hay una secuencia de comandos de Python que debería hacer lo que quieras:

#!/usr/bin/env python
# -*- encoding: ascii -*-
"""align.py"""

import re
import sys

# Read the data from the file into a list
lines = []
with open(sys.argv[1], 'r') as textfile:
    lines = textfile.readlines()

# Iterate through the data once to get the maximum indentation
max_indentation = 0
comment_block = False
for line in lines:

    # Check for the end of a comment block
    if comment_block:
        if not re.match(r'^\s*#.*$', line):
            comment_block = False

    # Check for the beginning of a comment block
    else:
        if re.match(r'^[^#]*[^ #].*#.*$', line):
            comment_block = True
            indentation = line.index('#')
            max_indentation = max(max_indentation, indentation)

# Iterate through the data a second time and output the reformatted text
comment_block = False
for line in lines:
    if comment_block:
        if re.match(r'^\s*#.*$', line):
            line = ' ' * max_indentation + line.lstrip()
        else:
            comment_block = False
    else:
        if re.match(r'^[^#]*[^ #].*#.*$', line):
            pre, sep, suf = line.partition('#')
            line = pre.ljust(max_indentation) + sep + suf
            comment_block = True

    sys.stdout.write(line)

Ejecútelo así:

python align.py input.txt

Produce el siguiente resultado:

# Lines starting with # stay the same
# Empty lines stay the same
# only lines with comments should change

ls                # show all major directories
                  # and other things

cd                # The cd command - change directory  
                  # will allow the user to change between file directories

touch             # The touch command, the make file command 
                  # allows users to make files using the Linux CLI #  example, cd ~

bar foo baz       # foo foo foo

Linux
  1. Bash Script:¿Comprobar si un archivo es un archivo de texto?

  2. ¿Modificar un correo entrante de texto/sin formato a texto/html?

  3. ¿Extraer texto entre dos líneas específicas?

  4. Eliminar líneas vacías en un archivo de texto a través de grep

  5. Ejecutar archivo de texto como comandos en Bash

Bash Shebang

Bash scripting:cómo escribir datos en archivos de texto

Cómo imprimir líneas duplicadas en un archivo de texto en Linux

¿Cómo edito líneas anteriores en un comando de varias líneas en Bash?

Historial de BASH truncado a 500 líneas en cada inicio de sesión

Ordenar archivos de texto con varias líneas como una fila