GNU/Linux >> Tutoriels Linux >  >> Linux

Alignement de texte complexe dans bash

Si toutes vos commandes et arguments ne contiennent pas # , et un autre caractère (disons le caractère ASCII donné par l'octet 1), vous pouvez insérer cet autre caractère comme séparateur supplémentaire et utiliser column pour aligner les commentaires (voir cette réponse). Donc, quelque chose comme :

$ 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 votre column ne prend pas en charge -e pour éviter d'éliminer les lignes vides, vous pouvez ajouter quelque chose aux lignes vides (par exemple, un espace ou le caractère séparateur utilisé ci-dessus) :

$ 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

Le traitement de texte avec le shell seul est un peu gênant et peut être sujet aux erreurs (voir "Pourquoi l'utilisation d'une boucle shell pour traiter le texte est-elle considérée comme une mauvaise pratique ?"). Il est généralement préférable d'utiliser un autre langage de programmation pour des tâches telles que celles-ci.

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

Cela utilise Perl pour capturer le bit devant le # (en supprimant les espaces entre le dernier mot et le # ) et le peu après. Si la correspondance a réussi, il alloue 16 emplacements de caractères pour le texte et imprime le texte formaté et le commentaire. Si la correspondance a échoué (parce que la ligne était vide ou commençait par un # ), la ligne est imprimée sans modification.

# 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

Voici un script Python qui devrait faire ce que vous voulez :

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

Exécutez-le comme ceci :

python align.py input.txt

Il produit la sortie suivante :

# 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. Comment supprimer les lignes en double dans un fichier texte ?

  2. Modifier un courrier entrant de Text/plain à Text/html ?

  3. Extraire du texte entre deux lignes spécifiques ?

  4. Imprimer un fichier, en sautant les X premières lignes, dans Bash

  5. Convertir une chaîne de texte en bash en tableau

Bash Shebang

Script bash :comment écrire des données dans des fichiers texte

Comment imprimer des lignes dupliquées dans un fichier texte sous Linux

Comment modifier les lignes précédentes dans une commande à plusieurs lignes dans Bash ?

Historique BASH tronqué à 500 lignes à chaque connexion

Comment afficher certaines lignes d'un fichier texte sous Linux ?