GNU/Linux >> Linux Esercitazione >  >> Linux

Allineamento complesso del testo in bash

Se tutti i tuoi comandi e argomenti non contengono # , e un altro carattere (diciamo il carattere ASCII dato dal byte 1), puoi inserire quell'altro carattere come separatore extra e usare column per allineare i commenti (vedi questa risposta). Quindi, qualcosa come:

$ 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

Se il tuo column non supporta -e per evitare di eliminare le righe vuote, puoi aggiungere qualcosa alle righe vuote (ad esempio, uno spazio o il carattere separatore usato sopra):

$ 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

L'elaborazione del testo con la sola shell è un po' scomoda e può essere soggetta a errori (vedere "Perché l'utilizzo di un ciclo della shell per elaborare il testo è considerato una cattiva pratica?"). In genere è meglio usare un altro linguaggio di programmazione per compiti come questi.

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

Questo usa Perl per catturare il bit davanti al # (scartando gli spazi tra l'ultima parola e il # ) e poco dopo. Se la corrispondenza ha esito positivo, alloca 16 caratteri per il testo e stampa il testo formattato e il commento. Se la corrispondenza non ha avuto successo (perché la riga era vuota o iniziava con un # ), la riga viene stampata senza modifiche.

# 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

Ecco uno script Python che dovrebbe fare quello che vuoi:

#!/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)

Eseguilo in questo modo:

python align.py input.txt

Produce il seguente output:

# 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. Come rimuovere le righe duplicate all'interno di un file di testo?

  2. Script Bash:controlla se un file è un file di testo?

  3. Modificare una posta in arrivo da testo/normale a testo/html?

  4. Rimuovi le righe vuote in un file di testo tramite grep

  5. Esegui file di testo come comandi in Bash

Bash Shebang

Scripting Bash:come scrivere dati su file di testo

Come stampare righe duplicate in un file di testo in Linux

Come posso modificare le righe precedenti in un comando a più righe in Bash?

Cronologia BASH troncata a 500 righe a ogni accesso

Come visualizzare determinate righe da un file di testo in Linux?