Comando tr in Linux: convertire caratteri, eliminare CR e ridurre spazi ripetuti

tr legge dallo standard input e scrive sull’uscita standard, traducendo o eliminando caratteri oppure riducendo ripetizioni consecutive. Non accetta un nome di file come argomento di input: passa il contenuto con una pipe o con la redirezione <.

È un filtro per caratteri, non un motore di sostituzione di parole o espressioni regolari. Per trovare un testo in un contesto e sostituirlo, consulta la guida in inglese a sed. Classi, intervalli e testo multibyte richiedono attenzione all’implementazione e alle impostazioni locali.

Sintassi e ingresso dei dati

tr [OPTION] SET1 [SET2] < INPUTFILE

Questa riga è una notazione: sostituisci i segnaposto con opzioni, sequenze di caratteri e un percorso reale. Le sequenze indicano i caratteri da selezionare e, quando occorre, i loro sostituti; le opzioni vanno prima degli operandi. Il secondo operando serve nella traduzione, mentre una cancellazione semplice con -d richiede solo il primo.

La redirezione è gestita dalla shell: tr riceve i byte del file, non il suo percorso. Usa man tr per controllare le opzioni disponibili. Negli esempi ASCII seguenti LC_ALL=C si applica al processo tr e rende esplicito l’ambiente locale del filtro.

Esempi: maiuscole, ritorni a capo e spazi

Da minuscole a maiuscole

Questa prova non crea file; il risultato viene mostrato nel terminale:

printf '%s\n' hello | LC_ALL=C tr '[:lower:]' '[:upper:]'

L’output è HELLO, seguito da una nuova riga. Le classi [:lower:] e [:upper:] sono racchiuse fra apici perché la shell non deve interpretarle come pattern per nomi di file. Questa prova riguarda lettere ASCII; non dimostra una conversione completa delle lettere accentate in UTF-8.

Eliminare i caratteri di ritorno carrello

Prepara due file dimostrativi in una directory nuova con una shell compatibile con Bash. Se tr-demo esiste, scegli un altro nome: la creazione fallisce e il resto non parte. Gli apici conservano le barre inverse, che vengono poi interpretate da printf o tr secondo il rispettivo formato.

mkdir tr-demo && cd tr-demo && (
  set -e
  set -o noclobber
  printf 'prima\r\nseconda\r\n' > windows-lines.txt
  printf 'uno\040\040due\t\t tre\n' > notes.txt
  LC_ALL=C tr -d '\r' < windows-lines.txt
)

Ottieni prima e seconda su due righe. In windows-lines.txt ogni fine riga contiene CRLF, cioè ritorno carrello \r seguito da nuova riga \n; il filtro elimina CR e conserva LF. Puoi verificarlo con LC_ALL=C tr -d '\r' < windows-lines.txt | cat -v: nell’output non compaiono i marcatori ^M che GNU cat mostra per i CR.

-d '\r' elimina tutti i CR del contenuto, anche se non sono subito prima di LF. Non usarlo indiscriminatamente su dati binari o quando quei caratteri hanno un significato. Il file originale non viene modificato. Rimani nella directory tr-demo per la prova successiva.

Ridurre gli spazi ripetuti

Il file notes.txt contiene due spazi fra uno e due, due tabulazioni dopo due e uno spazio prima di tre. La sequenza \040 usata nella preparazione rappresenta uno spazio:

LC_ALL=C tr -s ' ' < notes.txt

Fra uno e due resta uno spazio; le due tabulazioni rimangono entrambe. Per vederle, aggiungi | cat -T: il risultato è uno due^I^I tre. -s riduce ripetizioni dello stesso carattere selezionato, senza trasformare automaticamente tabulazioni e spazi in un unico tipo.

Se vuoi convertire le tabulazioni in spazi e poi comprimere gli spazi risultanti, usa LC_ALL=C tr -s '\t' ' ' < notes.txt: ottieni uno due tre. Se invece scrivi tr -s '[:blank:]', vengono ridotte separatamente le ripetizioni di tabulazione e di spazio: una tabulazione seguita da uno spazio resta una coppia di caratteri diversi. Evita di sostituire indiscriminatamente [:space:] con uno spazio quando devi mantenere le righe, perché quella classe comprende anche la nuova riga.

Risultato di una conversione per caratteri

Per convertire le lettere ASCII maiuscole in minuscole:

printf 'HELLO 123\n' | LC_ALL=C tr '[:upper:]' '[:lower:]'

Output atteso:

hello 123

Le cifre, lo spazio e la nuova riga non appartengono alla classe da convertire e rimangono invariati. Gli operandi non sono parole da cercare: printf 'cat\n' | LC_ALL=C tr 'cat' 'dog' produce dog perché associa separatamente c a d, a a o e t a g. Lo stesso filtro trasformerebbe tac in god, anche senza la parola cat nell’input.

Opzioni e sequenze di selezione

Opzione o classe Significato
-d Elimina i caratteri selezionati dal primo operando.
-s Riduce a una occorrenza le ripetizioni consecutive dello stesso carattere presente nell’ultimo operando, dopo eventuale traduzione o cancellazione.
-c Seleziona il complemento del primo operando: i valori che non vi compaiono. Usa cautela fuori dagli ambienti a byte singolo.
[:lower:] / [:upper:] Classi abbinate per la conversione fra minuscole e maiuscole, soggetta alle condizioni dell’implementazione e dell’ambiente locale.

Per esempio, printf 'a1b2\n' | LC_ALL=C tr -cd '[:digit:]\n' produce 12 seguito da una nuova riga: -c inverte la selezione e -d elimina tutto ciò che non è una cifra o LF. Se ometti \n, vengono eliminate anche le interruzioni di riga.

Precauzioni: UTF-8, intervalli e file di uscita

Le sequenze di tr non sono espressioni regolari complete. In particolare, non usare una sintassi come [a-z] presumendo che abbia automaticamente il significato di una classe di una regex. Gli intervalli dipendono dalle regole previste nell’ambiente locale; per la conversione ASCII negli script usa un ambiente esplicito e verifica il risultato.

Il manuale GNU segnala che il supporto completo di tr riguarda ambienti sicuri a byte singolo, come C nei sistemi GNU. Impostare C rende prevedibile l’elaborazione dei byte, ma non trasforma tr in un filtro Unicode: un carattere UTF-8 può occupare più byte. Per conversioni linguistiche o sostituzioni multibyte usa uno strumento che supporti esplicitamente la codifica e prova i caratteri reali; anche sed va scelto e verificato secondo l’implementazione e l’ambiente locale.

Per salvare il file senza CR nella directory di prova puoi usare LC_ALL=C tr -d '\r' < windows-lines.txt > unix-lines.txt, scegliendo una destinazione nuova, poi controllare il successo del comando e cat -v unix-lines.txt. La redirezione può sovrascrivere un file esistente. Non usare lo stesso percorso per input e output: la shell può svuotarlo prima che tr lo legga. Conserva l’originale finché non hai verificato il risultato; il filtro non modifica direttamente il file in ingresso.

Domande frequenti

Posso passare direttamente un nome di file a tr?

No. Usa la redirezione, per esempio LC_ALL=C tr -d '\r' < windows-lines.txt, oppure una pipe. Un nome aggiunto alla riga di comando viene interpretato come operando di selezione o traduzione, oppure causa un errore: non viene aperto automaticamente come file di input.

Documentazione di riferimento

La pagina di manuale GNU di tr su man7 descrive le opzioni e i limiti di codifica della versione documentata. Il riferimento POSIX per tr specifica operandi, classi e trasformazioni.