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