GNU/Linux >> Linux Esercitazione >  >> Linux

Gestisci l'interruzione di riga con i comandi Fold e FMT nel terminale Linux

Quando si utilizza un elaboratore di testi, la formattazione del testo in modo che le righe si adattino allo spazio disponibile sul dispositivo di destinazione non dovrebbe essere un problema. Ma quando si lavora al terminale, le cose non sono così facili.

Naturalmente, puoi sempre interrompere le righe a mano usando il tuo editor di testo preferito, ma questo è raramente desiderabile ed è persino fuori questione per l'elaborazione automatizzata.

Si spera che POSIX fold utility e GNU/BSD fmt il comando può aiutarti a ridisporre un testo in modo che le righe non superino una determinata lunghezza.

Cos'è una riga in Unix, di nuovo?

Prima di entrare nei dettagli del fold e fmt comandi, definiamo prima di cosa stiamo parlando. In un file di testo, una riga è composta da una quantità arbitraria di caratteri, seguita dalla speciale sequenza di controllo di nuova riga (a volte chiamata EOL, per fine riga )

Sui sistemi simili a Unix, la sequenza di controllo di fine riga è composta dal (unico e solo) carattere avanzamento riga , a volte abbreviato LF o scritto \n seguendo una convenzione ereditata dal linguaggio C. A livello binario, il carattere di avanzamento riga è rappresentato come un byte contenente 0a valore esadecimale.

Puoi verificarlo facilmente usando hexdump utility che useremo molto in questo articolo. Quindi potrebbe essere una buona occasione per familiarizzare con quello strumento. Ad esempio, puoi esaminare i dump esadecimali di seguito per trovare quanti caratteri di nuova riga sono stati inviati da ciascun comando echo. Una volta che pensi di avere la soluzione, riprova quei comandi senza il | hexdump -C parte per vedere se hai indovinato correttamente.

sh$ echo hello | hexdump -C
00000000  68 65 6c 6c 6f 0a                                 |hello.|
00000006
sh$ echo -n hello | hexdump -C
00000000  68 65 6c 6c 6f                                    |hello|
00000005
sh$ echo -e 'hello\n' | hexdump -C
00000000  68 65 6c 6c 6f 0a 0a                              |hello..|
00000007

Vale la pena menzionare a questo punto diversi sistemi operativi possono seguire regole diverse per quanto riguarda la sequenza di nuova riga. Come abbiamo visto sopra, i sistemi operativi simili a Unix utilizzano il line feed carattere, ma Windows, come la maggior parte dei protocolli Internet, utilizza due caratteri:ritorno a capo+avanzamento riga coppia (CRLF o 0d 0a o \r\n ). Su Mac OS "classico" (fino a MacOS 9.2 incluso nei primi anni 2000), i computer Apple utilizzavano solo il CR come carattere di nuova riga. Anche altri computer legacy utilizzavano la coppia LFCR, o anche sequenze di byte completamente diverse nel caso di vecchi sistemi incompatibili con ASCII. Fortunatamente, questi ultimi sono reliquie del passato e dubito che vedrai un computer EBCDIC in uso oggi!

Parlando di storia, se sei curioso, l'uso dei caratteri di controllo "ritorno a capo" e "avanzamento riga" risalgono al codice Baudot utilizzato nell'era della telescrivente. Potresti aver visto la telescrivente raffigurata nei vecchi film come interfaccia per un computer delle dimensioni di una stanza. Ma anche prima, le telescriventi venivano utilizzate "autonome" per la comunicazione punto-punto o multipunto. A quel tempo, un terminale tipico sembrava una macchina da scrivere pesante con una tastiera meccanica, carta e un carrello mobile che reggeva la testina di stampa. Per iniziare una nuova linea, il carrello deve essere riportato all'estrema sinistra e la carta deve spostarsi verso l'alto ruotando la piastra (a volte chiamata "cilindro"). Queste due mosse erano controllate da due sistemi elettromeccanici indipendenti, i caratteri di controllo dell'avanzamento riga e del ritorno a capo erano collegati direttamente a quelle due parti del dispositivo. Poiché lo spostamento del carrello richiede più volte rispetto alla rotazione della piastra, era logico avviare prima il ritorno del carrello. La separazione delle due funzioni ha avuto anche un paio di interessanti effetti collaterali, come consentire la sovrastampa (inviando solo il CR) o la trasmissione efficiente di "doppia interlinea" (un CR + due LF).

La definizione all'inizio di questa sezione descrive principalmente ciò che è logico la linea è. La maggior parte delle volte, tuttavia, quella linea logica "arbitrariamente lunga" deve essere inviata su un fisico dispositivo come uno schermo o una stampante, dove lo spazio disponibile è limitato. La visualizzazione di linee logiche brevi su un dispositivo con linee fisiche più grandi non è un problema. Semplicemente c'è spazio inutilizzato a destra del testo. Ma cosa succede se si tenta di visualizzare una riga di testo più grande dello spazio disponibile sul dispositivo? In realtà, ci sono due soluzioni, ognuna con la sua parte di inconvenienti:

  1. In primo luogo, il dispositivo può troncare le righe alla loro dimensione fisica, nascondendo così parte del contenuto all'utente. Alcune stampanti lo fanno, in particolare le stampanti stupide (e sì, ci sono ancora stampanti ad aghi di base in uso oggi, specialmente in ambienti difficili o sporchi!)
  2. La seconda opzione per visualizzare righe logiche lunghe è dividerle in più righe fisiche. Questo è chiamato a capo automatico perché le linee sembrano avvolgere lo spazio disponibile, un effetto particolarmente visibile se puoi ridimensionare il display come quando si lavora con un emulatore di terminale.

Questi comportamenti automatici sono abbastanza utili, ma ci sono ancora volte in cui vuoi interrompere lunghe file in una determinata posizione indipendentemente dalle dimensioni fisiche del dispositivo. Ad esempio, può essere utile perché si desidera che le interruzioni di riga si verifichino nella stessa posizione sia sullo schermo che sulla stampante. Oppure perché si desidera che il testo venga utilizzato in un'applicazione che non esegue il ritorno a capo della riga (ad esempio, se si incorpora il testo a livello di codice in un file SVG). Infine, che tu ci creda o no, ci sono ancora molti protocolli di comunicazione che impongono una larghezza massima della linea nelle trasmissioni, compresi quelli popolari come IRC e SMTP (se hai mai visto l'errore 550 Lunghezza massima della linea superata sai cosa sono parlare di). Quindi ci sono molte occasioni in cui è necessario spezzare lunghe file in pezzi più piccoli. Questo è il compito di POSIX fold comando.

Il comando piega

Se utilizzato senza alcuna opzione, il fold il comando aggiunge ulteriori sequenze di controllo di nuova riga per garantire che nessuna riga superi il limite di 80 caratteri. Giusto per chiarire, una riga conterrà al massimo 80 caratteri più la sequenza di nuova riga.

Se hai scaricato il materiale di supporto per quell'articolo, puoi provarlo da solo:

sh$ fold POSIX.txt | head -5
The Portable Operating System Interface (POSIX)[1] is a family of standards spec
ified by the IEEE Computer Society for maintaining compatibility between operati
ng systems. POSIX defines the application programming interface (API), along wit
h command line shells and utility interfaces, for software compatibility with va
riants of Unix and other operating systems.[2][3]

# Using AWK to prefix each line by its length:
sh$ fold POSIX.txt | awk '{ printf("%3d %s\n", length($0), $0) }'
 80 The Portable Operating System Interface (POSIX)[1] is a family of standards spec
 80 ified by the IEEE Computer Society for maintaining compatibility between operati
 80 ng systems. POSIX defines the application programming interface (API), along wit
 80 h command line shells and utility interfaces, for software compatibility with va
 49 riants of Unix and other operating systems.[2][3]
  0
 80 The standards emerged from a project that began circa 1985. Richard Stallman sug
 80 gested the name POSIX to the IEEE instead of former IEEE-IX. The committee found
 71  it more easily pronounceable and memorable, and thus adopted it.[2][4]

Puoi modificare la lunghezza massima della riga di output utilizzando -w opzione. Più interessante probabilmente è l'uso di -s opzione per garantire che le righe si interrompano al limite di una parola. Confrontiamo il risultato senza e con -s opzione se applicata al secondo paragrafo del nostro testo di esempio:

# Without `-s` option: fold will break lines at the specified position
# Broken lines have exactly the required width
sh$ awk -vRS='' 'NR==2' POSIX.txt |
                        fold -w 30 | awk '{ printf("%3d %s\n", length($0), $0) }'
 30 The standards emerged from a p
 30 roject that began circa 1985.
 30 Richard Stallman suggested the
 30  name POSIX to the IEEE instea
 30 d of former IEEE-IX. The commi
 30 ttee found it more easily pron
 30 ounceable and memorable, and t
 21 hus adopted it.[2][4]

# With `-s` option: fold will break lines at the last space before the specified position
# Broken lines are shorter or equal to the required width
awk -vRS='' 'NR==2' POSIX.txt |
                         fold -s -w 30 | awk '{ printf("%3d %s\n", length($0), $0) }'
 29 The standards emerged from a
 25 project that began circa
 23 1985. Richard Stallman
 28 suggested the name POSIX to
 27 the IEEE instead of former
 29 IEEE-IX. The committee found
 29 it more easily pronounceable
 24 and memorable, and thus
 17 adopted it.[2][4]

Ovviamente, se il tuo testo contiene parole più lunghe della lunghezza massima della riga, il comando fold non sarà in grado di rispettare il -s bandiera. In tal caso, il fold l'utilità interromperà le parole di grandi dimensioni nella posizione massima, assicurando sempre che nessuna linea superi la larghezza massima consentita.

sh$ echo "It's Supercalifragilisticexpialidocious!" | fold -sw 10
It's
Supercalif
ragilistic
expialidoc
ious!

Caratteri multibyte

Come la maggior parte, se non tutte, le utility principali, il fold il comando è stato progettato in un momento in cui un carattere equivaleva a un byte. Tuttavia, questo non è più il caso dell'informatica moderna, specialmente con l'adozione diffusa di UTF-8. Qualcosa che porta a problemi sfortunati:

# Just in case, check first the relevant locale
# settings are properly defined
debian-9.4$ locale | grep LC_CTYPE
LC_CTYPE="en_US.utf8"

# Everything is OK, unfortunately...
debian-9.4$ echo élève | fold -w2
é
l�
�v
e

La parola “élève” (la parola francese per “studente”) contiene due lettere accentate:é (LETTERA E PICCOLA LATINA CON ACUTO) e è (LETTERA E PICCOLA LATINA CON GRAVE). Utilizzando il set di caratteri UTF-8, queste lettere vengono codificate utilizzando due byte ciascuna (rispettivamente, c3 a9 e c3 a8 ), invece di un solo byte come nel caso delle lettere latine non accentate. Puoi verificarlo esaminando i byte grezzi usando hexdump utilità. Dovresti essere in grado di individuare le sequenze di byte corrispondenti a é e è caratteri. A proposito, potresti anche vedere in quel dump il nostro vecchio amico il carattere del feed di riga il cui codice esadecimale è stato menzionato prima:

debian-9.4$ echo élève | hexdump -C
00000000  c3 a9 6c c3 a8 76 65 0a                           |..l..ve.|
00000008

Esaminiamo ora l'output prodotto dal comando fold:

debian-9.4$ echo élève | fold -w2
é
l�
�v
e
debian-9.4$ echo élève | fold -w 2 | hexdump -C
00000000  c3 a9 0a 6c c3 0a a8 76  0a 65 0a                 |...l...v.e.|
0000000b

Ovviamente, il risultato prodotto dal fold comando è leggermente più lungo della stringa di caratteri originale a causa delle nuove righe extra:rispettivamente 11 byte di lunghezza e 8 byte di lunghezza, comprese le nuove righe. A proposito, nell'output di fold comando potresti aver visto il feed di riga (0a ) carattere che compare ogni due byte. E questo è esattamente il problema:il comando fold ha interrotto le righe a byte posizioni, non a carattere posizioni. Anche se l'interruzione si verifica nel mezzo di un carattere multi-byte! Non c'è bisogno di menzionare che l'output risultante non è più un flusso di byte UTF-8 valido, da qui l'uso del carattere sostitutivo Unicode ( ) dal mio terminale come segnaposto per le sequenze di byte non valide.

Come per il cut comando che ho scritto qualche settimana fa, questa è una limitazione nell'implementazione GNU del fold utilità e questo è chiaramente in contrasto con le specifiche POSIX che affermano esplicitamente che "Una riga non deve essere interrotta nel mezzo di un carattere".

Quindi appare il fold di GNU l'implementazione gestisce correttamente solo le codifiche di caratteri a un byte di lunghezza fissa (US-ASCII, Latin1 e così via). Come soluzione alternativa, se esiste un set di caratteri adatto, è possibile transcodificare il testo in una codifica di caratteri a un byte prima di elaborarlo e successivamente transcodificarlo in UTF-8. Tuttavia, questo è ingombrante, per non dire altro:

debian-9.4$ echo élève |
      iconv -t latin1 | fold -w 2 |
      iconv -f latin1 | hexdump -C
00000000  c3 a9 6c 0a c3 a8 76 0a  65 0a                    |..l...v.e.|
0000000a
debian-9.4$ echo élève |
         iconv -t latin1 | fold -w 2 |
         iconv -f latin1
él
èv
e

Essendo tutto ciò piuttosto deludente, ho deciso di controllare il comportamento di altre implementazioni. Come spesso accade, l'implementazione OpenBSD del fold l'utilità è molto migliore in questa materia poiché è conforme a POSIX e rispetterà il LC_CTYPE impostazione locale per gestire correttamente i caratteri multibyte:

openbsd-6.3$ locale | grep LC_CTYPE
LC_CTYPE=en_US.UTF-8
openbsd-6.3$ echo élève | fold -w 2            C
él
èv
e
openbsd-6.3$ echo élève | fold -w 2 | hexdump -C
00000000  c3 a9 6c 0a c3 a8 76 0a  65 0a                    |..l...v.e.|
0000000a

Come puoi vedere, l'implementazione di OpenBSD taglia correttamente le linee a carattere posizioni, indipendentemente dal numero di byte necessari per codificarle. Nella stragrande maggioranza dei casi d'uso, questo è ciò che desideri. Tuttavia, se hai bisogno del comportamento legacy (es.:stile GNU) considerando un byte come un carattere, puoi cambiare temporaneamente la locale corrente nella cosiddetta locale POSIX (identificata dalla costante "POSIX" o, per ragioni storiche, "C ”):

openbsd-6.3$ echo élève | LC_ALL=C fold -w 2
é
l�
�v
e
openbsd-6.3$ echo élève | LC_ALL=C fold -w 2 | hexdump -C
00000000  c3 a9 0a 6c c3 0a a8 76  0a 65 0a                 |...l...v.e.|
0000000b

Infine, POSIX specifica il -b flag, che indica il fold utility per misurare la lunghezza della linea in byte , ma ciò garantisce comunque caratteri multibyte (secondo l'attuale LC_CTYPE impostazioni locali) non essere rotto.

Come esercizio, ti consiglio vivamente di dedicare il tempo necessario per trovare le differenze a livello di byte tra il risultato ottenuto modificando la locale corrente in "C" (sopra) e il risultato ottenuto usando il -b flag invece (sotto). Potrebbe essere sottile. Ma c'è c'è una differenza:

openbsd-6.3$ echo élève | fold -b -w 2 | hexdump -C
00000000  c3 a9 0a 6c 0a c3 a8 0a  76 65 0a                 |...l....ve.|
0000000b

Allora, hai trovato la differenza?

Bene, cambiando la locale in "C", il fold l'utilità non si è occupata delle sequenze multi-byte, poiché, per definizione, quando la locale è "C" gli strumenti devono presumere un carattere è un byte . Quindi una nuova riga può essere aggiunta ovunque, anche nel mezzo di una sequenza di byte che farebbe sono stati considerati come un carattere multibyte in un'altra codifica dei caratteri. Questo è esattamente ciò che è successo quando lo strumento ha prodotto il c3 0a a8 sequenza di byte:i due byte c3 a8 sono intesi come un carattere quando LC_CTYPE definisce la codifica dei caratteri come UTF-8. Ma la stessa sequenza di byte è vista come due caratteri nella lingua "C":

# Bytes are bytes. They don't change so
# the byte count is the same whatever is the locale
openbsd-6.3$ printf "%d bytes\n" $(echo -n é | LC_ALL=en_US.UTF-8 wc -c)
2 bytes
openbsd-6.3$ printf "%d bytes\n" $(echo -n é | LC_ALL=C wc -c)
2 bytes

# The interpretation of the bytes may change depending on the encoding
# so the corresponding character count will change
openbsd-6.3$ printf "%d chars\n" $(echo -n é | LC_ALL=en_US.UTF-8 wc -m)
1 chars
openbsd-6.3$ printf "%d chars\n" $(echo -n é | LC_ALL=C wc -m)
2 chars

D'altra parte, con il -b opzione, lo strumento dovrebbe essere ancora multibyte. Quell'opzione cambia solo nel modo in cui conta le posizioni , in byte questa volta, anziché in caratteri come avviene per impostazione predefinita. In tal caso, poiché le sequenze multibyte non vengono suddivise, l'output risultante rimane un flusso di caratteri valido (secondo l'attuale LC_CTYPE impostazioni locali):

openbsd-6.3$ echo élève | fold -b -w 2
é
l
è
ve

L'hai visto, ora non ci sono più occorrenze del carattere sostitutivo Unicode ( ), e non abbiamo perso alcun carattere significativo nel processo, a scapito di finire questa volta con righe contenenti un numero variabile di caratteri e un numero variabile di byte. Infine, tutto lo strumento assicura che non ci siano più byte per riga di quelli richiesti con -w opzione. Qualcosa che possiamo verificare usando il wc strumento:

openbsd-6.3$ echo élève | fold -b -w 2 | while read line; do
>   printf "%3d bytes  %3d chars %s\n" \
>             $(echo -n $line | wc -c) \
>             $(echo -n $line | wc -m) \
>             $line
> done
  2 bytes    1 chars é
  1 bytes    1 chars l
  2 bytes    1 chars è
  2 bytes    2 chars ve

Ancora una volta, prenditi il ​​tempo necessario per studiare l'esempio sopra. Fa uso di printf e wc comandi che non ho spiegato in dettaglio in precedenza. Quindi, se le cose non sono abbastanza chiare, non esitate a utilizzare la sezione commenti per chiedere alcune spiegazioni!

Per curiosità, ho controllato -b flag sulla mia Debian box usando GNU fold attuazione:

debian-9.4$ echo élève | fold -w 2 | hexdump -C
00000000  c3 a9 0a 6c c3 0a a8 76  0a 65 0a                 |...l...v.e.|
0000000b
debian-9.4$ echo élève | fold -b -w 2 | hexdump -C
00000000  c3 a9 0a 6c c3 0a a8 76  0a 65 0a                 |...l...v.e.|
0000000b

Non perdere tempo a cercare una differenza tra -b e non--b versioni di quell'esempio:abbiamo visto che l'implementazione di GNU fold non è multi-byte, quindi entrambi i risultati sono identici. Se non ne sei convinto, forse potresti usare il diff -s comando per consentire al tuo computer di confermarlo. Se lo fai, usa la sezione commenti per condividere il comando che hai usato con gli altri lettori!

Comunque, significa il -b opzione inutile nell'implementazione GNU di fold utilità? Bene, leggendo più attentamente la documentazione GNU Coreutils per il fold comando, ho trovato il -b l'opzione tratta solo caratteri speciali come la tabulazione o il backspace che contano rispettivamente per 1~8 (da uno a otto) o -1 (meno uno) posizione in modalità normale, ma contano sempre per 1 posizione in modalità byte. Confuso? Quindi, forse potremmo prenderci del tempo per spiegarlo in modo più dettagliato.

Gestione di tabulazioni e backspace

La maggior parte dei file di testo con cui ti occuperai contiene solo caratteri stampabili e sequenze di fine riga. Tuttavia, occasionalmente, può capitare che alcuni personaggi di controllo si intromettano nei tuoi dati. Il carattere di tabulazione (\t ) è uno di questi. Molto più raramente, il backspace (\b ) possono anche essere incontrati. Lo menziono ancora qui perché, come suggerisce il nome, è un carattere di controllo che fa muovere il cursore di una posizione indietro (verso sinistra), mentre la maggior parte degli altri personaggi sta andando avanti (verso destra).

sh$ echo -e 'tab:[\t] backspace:[\b]'
tab:[    ] backspace:]

Questo potrebbe non essere visibile nel tuo browser, quindi ti consiglio vivamente di testarlo sul tuo terminale. Ma i caratteri di tabulazione (\t ) occupa diverse posizioni sull'uscita. E il backspace? Sembra che ci sia qualcosa di strano nell'output, vero? Quindi rallenta un po' le cose, suddividendo la stringa di testo in più parti e inserendo un po' di sleep tra loro:

# For that to work, type all the commands on the same line
# or using backslashes like here if you split them into
# several (physical) lines:
sh$ echo -ne 'tab:[\t] backspace:['; \
  sleep 1; echo -ne '\b'; \
  sleep 1; echo -n ']'; \
  sleep 1; echo ''

OK? L'hai visto questa volta? Scomponiamo la sequenza degli eventi:

  1. La prima stringa di caratteri viene visualizzata "normalmente" fino alla seconda parentesi quadra aperta. A causa del -n flag, l'echo comando non invia un carattere di nuova riga, in modo che il cursore rimanga sulla stessa riga.
  2. Primo sonno.
  3. Viene emesso Backspace, con il risultato che il cursore si sposta indietro di una posizione. Ancora nessuna nuova riga, quindi il cursore rimane sulla stessa riga.
  4. Secondo sonno.
  5. Viene visualizzata la parentesi quadra di chiusura, sovrascrivendo quello di apertura.
  6. Terzo sonno.
  7. In assenza del -n opzione, l'ultimo echo il comando invia infine il carattere di nuova riga e il cursore si sposta sulla riga successiva, dove verrà visualizzato il prompt della shell.

Ovviamente, un effetto altrettanto interessante può essere ottenuto utilizzando un ritorno a capo, se lo ricordi:

sh$ echo -n 'hello'; sleep 1; echo -e '\rgood bye'
good bye

Sono abbastanza sicuro che tu abbia già visto qualche utilità da riga di comando come curl , wget o ffmpeg visualizzazione di una barra di avanzamento. Fanno la loro magia usando una combinazione di \b e/o \r .

Per quanto interessante che la discussione possa essere di per sé, il punto qui era capire che gestire quei caratteri può essere difficile per il fold utilità. Si spera che lo standard POSIX definisca le regole:

Il conteggio corrente della larghezza della linea deve essere decrementato di uno, sebbene il conteggio non diventi mai negativo. L'utilità di piegatura non deve inserire un immediatamente prima o dopo qualsiasi . Il conteggio corrente della larghezza della linea deve essere impostato su zero. L'utilità di piegatura non deve inserire un immediatamente prima o dopo qualsiasi . Ogni incontrata farà avanzare il puntatore della posizione della colonna al successivo punto di tabulazione. I punti di tabulazione devono trovarsi in ciascuna posizione di colonna n tale che n modulo 8 sia uguale a 1. _

Tutti questi trattamenti speciali sono disabilitati quando si utilizza il -b opzione. In tal caso, soprattutto i caratteri di controllo contano (correttamente) per un byte e quindi aumentare il contatore di posizione di uno e solo uno, proprio come qualsiasi altro personaggio.

Per una migliore comprensione, ti lascio esaminare da solo i due seguenti esempi (magari usando hexdump utilità). Ora dovresti essere in grado di scoprire perché "ciao" è diventato "inferno" e dove si trova esattamente la "i" nell'output (come è lì, anche se non puoi vederlo!) Come sempre, se hai bisogno di aiuto , o semplicemente se vuoi condividere i tuoi risultati, la sezione commenti è tua.

# Why "hello" has become "hell"? where is the "i"?
sh$ echo -e 'hello\rgood bi\bye' | fold -w4
hell
good
 bye

# Why "hello" has become "hell"? where is the "i"?
# Why the second line seems to be made of only two chars instead of 4?
sh$ echo -e 'hello\rgood bi\bye' | fold -bw4
hell
go
od b
ye

Altre limitazioni

Il fold il comando che abbiamo studiato fino ad ora è stato progettato per suddividere lunghe linee logiche in linee fisiche più piccole, in particolare per scopi di formattazione.

Ciò significa che presuppone che ogni linea di input sia autonoma e possa essere interrotta indipendentemente dalle altre linee. Questo non è sempre il caso, tuttavia. Consideriamo ad esempio quella mail molto importante che ho ricevuto:

sh$ cat MAIL.txt
Dear friends,

Have a nice day!
We are manufactuer for event chairs and tables, more than 10 years experience.

We supply all kinds of wooden, resin and metal event chairs, include chiavari
chairs, cross back chairs, folding chairs, napoleon chairs, phoenix chairs, etc.

Our chairs and tables are of high quality and competitively priced.
If you need our products, welcome to contact me;we are happy to make you special
offer.

Best Regards
Doris
sh$ awk '{ length>maxlen && (maxlen=length) } END { print maxlen }' MAIL.txt
81

Ovviamente, le linee erano già interrotte a una larghezza fissa. Il awk il comando mi ha detto che la larghezza massima della riga qui era ... 81 caratteri, esclusa la nuova sequenza di righe. Sì, era sufficientemente strano che l'ho ricontrollato:infatti la riga più lunga ha 80 caratteri stampabili più uno spazio in più all'81a posizione e solo dopo c'è il carattere di avanzamento riga. Probabilmente gli informatici che lavorano per conto di questo "produttore" di sedie potrebbero trarre vantaggio dalla lettura di questo articolo!

Ad ogni modo, supponendo che io voglia cambiare la formattazione di quell'email, avrò problemi con il fold comando a causa delle interruzioni di riga esistenti. Ti ho lasciato controllare da solo i due comandi seguenti, se lo desideri, ma nessuno di essi funzionerà come previsto:

sh$ fold -sw 100 MAIL.txt
sh$ fold -sw 60 MAIL.txt

Il primo semplicemente non farà nulla poiché tutte le righe sono già più corte di 100 caratteri. Per quanto riguarda il secondo comando, interromperà le righe alla 60a posizione ma manterrà i caratteri di nuova riga già esistenti in modo che il risultato sia frastagliato. Sarà particolarmente visibile nel terzo paragrafo:

sh$ awk -v RS='' 'NR==3' MAIL.txt |
            fold -sw 60 |
            awk '{ length>maxlen && (maxlen=length); print length, $0 }'
53 We supply all kinds of wooden, resin and metal event
25 chairs, include chiavari
60 chairs, cross back chairs, folding chairs, napoleon chairs,
20 phoenix chairs, etc.

La prima riga del terzo paragrafo è stata interrotta alla posizione 53, che è coerente con la nostra larghezza massima di 60 caratteri per riga. Tuttavia, la seconda riga si è interrotta alla posizione 25 perché quel carattere di nuova riga era già presente nel file di input. In altre parole, per ridimensionare correttamente i paragrafi, dobbiamo prima unire le righe prima di spezzarle nella nuova posizione di destinazione.

Puoi usare sed o awk per ricongiungersi alle linee. E in effetti, come l'ho menzionato nel video introduttivo, sarebbe una bella sfida per te. Quindi non esitare a pubblicare la tua soluzione nella sezione commenti.

Quanto a me, seguirò un percorso più semplice guardando il fmt comando. Sebbene non sia un comando standard POSIX, è disponibile sia nel mondo GNU che BSD. Quindi ci sono buone probabilità che sia utilizzabile sul tuo sistema. Sfortunatamente, la mancanza di standardizzazione avrà delle implicazioni negative come vedremo in seguito. Ma per ora concentriamoci sulle parti buone.

Il comando fmt

Il fmt il comando è più evoluto del fold comando e ha più opzioni di formattazione. La parte più interessante è che può identificare i paragrafi nel file di input in base alle righe vuote. Ciò significa che tutte le righe fino alla successiva riga vuota (o alla fine del file) verranno prima unite per formare quella che ho chiamato prima una "linea logica" del testo. Solo dopo, il fmt il comando interromperà il testo nella posizione richiesta.

Vediamo ora cosa cambierà quando applicato al secondo paragrafo della mia mail di esempio:

sh$  awk -v RS='' 'NR==3' MAIL.txt |
             fmt -w 60 |
             awk '{ length>maxlen && (maxlen=length); print length, $0 }'
60 We supply all kinds of wooden, resin and metal event chairs,
59 include chiavari chairs, cross back chairs, folding chairs,
37 napoleon chairs, phoenix chairs, etc.

Aneddoticamente, il fmt comando accettato per comprimere un'altra parola nella prima riga. Ma cosa più interessante, la seconda riga è ora riempita, il che significa che il carattere di nuova riga già presente nel file di input dopo che la parola "chiavari" (che cos'è?) è stata scartata. Naturalmente, le cose non sono perfette e il fmt l'algoritmo di rilevamento dei paragrafi a volte attiva falsi positivi, come nei saluti alla fine della posta (riga 14 dell'output):

sh$ fmt -w 60 MAIL.txt | cat -n
     1  Dear friends,
     2
     3  Have a nice day!  We are manufactuer for event chairs and
     4  tables, more than 10 years experience.
     5
     6  We supply all kinds of wooden, resin and metal event chairs,
     7  include chiavari chairs, cross back chairs, folding chairs,
     8  napoleon chairs, phoenix chairs, etc.
     9
    10  Our chairs and tables are of high quality and competitively
    11  priced.  If you need our products, welcome to contact me;we
    12  are happy to make you special offer.
    13
    14  Best Regards Doris

Ho detto prima il fmt command era uno strumento di formattazione del testo più evoluto rispetto a fold utilità. Certo che lo è. Potrebbe non essere ovvio a prima vista, ma se guardi attentamente le righe 10-11, potresti notare che usava due spazi dopo il punto:applicare una convenzione molto discussa di utilizzare due spazi alla fine di una frase. Non entrerò in quel dibattito per sapere se dovresti o meno usare due spazi tra le frasi, ma non hai una vera scelta qui:per quanto ne so, nessuna delle implementazioni comuni di fmt comando offrono un flag per disabilitare il doppio spazio dopo una frase. A meno che una tale opzione non esista da qualche parte e l'ho persa? Se questo è il caso, sarò felice che tu me lo faccia sapere usando la sezione commenti:come scrittore francese, non ho mai usato il "doppio spazio" dopo una frase...

Altre opzioni fmt

Il fmt l'utilità è progettata con alcune capacità di formattazione in più rispetto al comando fold. Tuttavia, non essendo definito POSIX, ci sono grandi incompatibilità tra le opzioni GNU e BSD.

Ad esempio, il -c l'opzione è usata nel mondo BSD per centrare il testo mentre in fmt di GNU Coreutils abilita la modalità margine corona, “preservando il rientro delle prime due righe all'interno di un paragrafo, e allineando il margine sinistro di ogni riga successiva con quello della seconda riga. “

Ti ho lasciato sperimentare da solo con GNU fmt -c se vuoi. Personalmente, trovo più interessante studiare la funzionalità di centratura del testo BSD a causa di alcune stranezze:infatti, in OpenBSD, fmt -c will center the text according to the target width— but without reflowing it! So the following command will not work as you might have expected:

openbsd-6.3$ fmt -c -w 60 MAIL.txt
                        Dear friends,

                      Have a nice day!
We are manufactuer for event chairs and tables, more than 10 years experience.

We supply all kinds of wooden, resin and metal event chairs, include chiavari
chairs, cross back chairs, folding chairs, napoleon chairs, phoenix chairs, etc.

Our chairs and tables are of high quality and competitively priced.
If you need our products, welcome to contact me;we are happy to make you special
                           offer.

                        Best Regards
                            Doris

If you really want to reflow the text for a maximum width of 60 characters and center the result, you will have to use two instances of the fmt comando:

openbsd-6.3$ fmt -w 60 MAIL.txt | fmt -c -w60
                        Dear friends,

  Have a nice day!  We are manufactuer for event chairs and
           tables, more than 10 years experience.

We supply all kinds of wooden, resin and metal event chairs,
 include chiavari chairs, cross back chairs, folding chairs,
            napoleon chairs, phoenix chairs, etc.

 Our chairs and tables are of high quality and competitively
 priced.  If you need our products, welcome to contact me;we
            are happy to make you special offer.

                     Best Regards Doris

I will not make here an exhaustive list of the differences between the GNU and BSD fmt implementations … essentially because all the options are different! Except of course the -w opzione. Speaking of that, I forgot to mention -N where N is an integer is a shortcut for -wN . Moreover you can use that shortcut both with the fold and fmt commands:so, if you were perseverent enough to read his article until this point, as a reward you may now amaze your friends by saving one (!) entire keystroke the next time you will use one of those utilities:

debian-9.4$ fmt -50 POSIX.txt | head -5
The Portable Operating System Interface
(POSIX)[1] is a family of standards specified
by the IEEE Computer Society for maintaining
compatibility between operating systems. POSIX
defines the application programming interface

openbsd-6.3$ fmt -50 POSIX.txt | head -5
The Portable Operating System Interface (POSIX)[1]
is a family of standards specified by the IEEE
Computer Society for maintaining compatibility
between operating systems. POSIX defines the
application programming interface (API), along

debian-9.4$ fold -sw50 POSIX.txt  | head -5
The Portable Operating System Interface
(POSIX)[1] is a family of standards specified by
the IEEE Computer Society for maintaining
compatibility between operating systems. POSIX
defines the application programming interface

openbsd-6.3$ fold -sw50 POSIX.txt  | head -5
The Portable Operating System Interface
(POSIX)[1] is a family of standards specified by
the IEEE Computer Society for maintaining
compatibility between operating systems. POSIX
defines the application programming interface

As the final word, you may also notice in that last example the GNU and BSD versions of the fmt utility are using a different formatting algorithm, producing a different result. On the other hand, the simpler fold algorithm produces consistent results between the implementations. All that to say if portability is a premium, you need to stick with the fold command, eventually completed by some other POSIX utilities. But if you need more fancy features and can afford to break compatibility, take a look at the manual for the fmt command specific to your own system. And let us know if you discovered some fun or creative usage for those vendor-specific options!


Linux
  1. Copia e incolla nella riga di comando di Linux con xclip

  2. Condivisione di sessioni del terminale Linux con Tmux e Screen

  3. Come trovare file di grandi dimensioni Linux con i comandi find e du

  4. Linux:come sincronizzare due cartelle con gli strumenti della riga di comando?

  5. Trova un file con i comandi Trova e individua in Linux

Il mio terminale Linux ricco di funzionalità e minimale

Personalizzazione del mio terminale Linux con tmux e Git

Poteri di due, poteri di Linux:2048 alla riga di comando

Come lavorare con il processo in primo piano e in background in Linux

5 comandi divertenti da usare in Linux e Terminal

Nozioni di base sulla riga di comando di Linux:lavorare con file e directory