Sostituisci più spazi con uno solo usando 'tr'


71

Ho un file f1.txt,:

ID     Name
1      a
2         b
3   g
6            f

Il numero di spazi non è fisso. Qual è il modo migliore per sostituire tutti gli spazi bianchi con uno spazio usando solo tr?

Questo è quello che ho finora:

cat f1.txt | tr -d " "

Ma l'output è:

IDName
1a
2b
3g
6f

Ma voglio che assomigli a questo:

ID Name
1 a
2 b
3 g
6 f

Per favore, cerca di evitare sed.


6
Perché è così importante evitare sed? Usa qualunque cosa funzioni!
David Richerby,

7
Perché so come farlo sed.
Volevo

Risposte:


106

Con tr, utilizzare l' opzione di ripetizione squeeze :

$ tr -s " " < file
ID Name
1 a
2 b
3 g
6 f

Oppure puoi usare una awksoluzione:

$ awk '{$2=$2};1' file
ID Name
1 a
2 b
3 g
6 f

Quando si modifica un campo nel record, la awkricostruzione $0, prende tutti i campi e li concatena insieme, separati da OFS, che è uno spazio per impostazione predefinita.

Ciò comprimerà le sequenze di spazio e tabulazioni (e possibilmente altri caratteri vuoti a seconda delle impostazioni locali e dell'implementazione di awk) in uno spazio, ma rimuoverà anche gli spazi vuoti iniziali e finali da ogni riga.


1
Anche questa è un'ottima soluzione. . . Non so quale scegliere ora: / @Gnouc
gkmohit

Sentiti libero di scegliere qualsiasi soluzione che ti piace e funziona per te. Una nota che la mia soluzione è diversa con la risposta di @ polym.
cuonglm,

1
:)) Sìì! La risposta di @Gnouc è davvero dinamica, perché usa awk, può fare qualsiasi cosa. Puoi anche accettare la sua soluzione. Solo una cosa: Gnouc puoi forse spiegare cosa fa il formato awk nel tuo comando? Inoltre, puoi aggiungere schede / spazi in modo che l'output sia conforme all'output previsto di Unknown?
polimero

1
@polym: con l'ultima modifica di Unknown, sembra voler solo uno spazio, non output come column -tfa. Aggiungi spiegazione per awk.
cuonglm

4
C'è una piccola differenza qui. trsostituirà due spazi alla fine di una linea con un singolo spazio. awkrimuoverà tutti gli spazi finali.
Anne van Rossum,

19

Usa solo column:

column -t inputFile

Produzione:

ID  Name
1   a
2   b
3   g
6   f

Meravigliosa e una rapida risposta :)
gkmohit,

1
@Sconosciuto Ottimo per essere al servizio :)!
polimero

1
@Gnouc wow cool, la colonna prende anche un file come argomento. bene grazie!
polimero

Come posso ottenere la seconda colonna solo se lo desidero? Ci ho provato column -t f1.txt | cut -d " " -f2 ma non era una soluzione che mi aspettavo
gkmohit,

2
Usa awk quindi: column -t file | awk '{print $2}'stampa solo la seconda colonna
polimero

8

Se si desidera comprimere lo "spazio bianco", si desidera utilizzare i set di caratteri predefiniti di tr ": vuoto:" (scheda e spazio bianco orizzontale) o ": spazio:" (bianco spazio):

/bin/echo -e  "val1\t\tval2   val3" | tr -s "[:blank:]"

Alcuni esempi sono stati eseguiti su Red Hat 5 (GNU tr).

Nel mio caso, volevo normalizzare tutti gli spazi bianchi in un unico spazio in modo da poter fare affidamento sullo spazio come delimitatore.

Come sottolineato dal secondo commento di Dastrobu, mi mancava il testo nella pagina man:

 -s uses the last specified SET, and occurs after translation or deletion.

Questo ci consente di eliminare la prima tr. Kudo deve cercare le sue pazienze di fronte alla mia densità.

Prima, analizzava la porta dalla configurazione di Redis. file:

grep "^port" $redisconf | tr "[:blank:]" " " | tr -s "[:blank:]"  | cut -d" " -f2

Successivamente, con SET2 specificato con la compressione:

grep "^port" $redisconf | tr -s "[:blank:]" " " | cut -d" " -f2

Produzione:

6379

Per maggiori dettagli sulle sfumature degli spazi bianchi

Dimostrare dove la compressione da sola fallisce quando sono coinvolti personaggi misti successivi che rientrano nella classe di caratteri [: blank:]:

 /usr/bin/printf '%s \t %s' id myname | tr -s "[:blank:]"  | od -cb
0000000   i   d      \t       m   y   n   a   m   e
        151 144 040 011 040 155 171 156 141 155 145
0000013

Nota: i miei due campi stringa nel formato printf sono separati da 1 spazio, 1 scheda, 1 spazio. Dopo la compressione questa sequenza esiste ancora. Nell'output del dump ottale questo è rappresentato dalla sequenza ascii 040 011 040.


1
Ne hai davvero bisogno tr "[:blank:]" " " | tr -s "[:blank:]"? Immagino che la prima parte sarà sufficiente, cioè tr "[:blank:]" " "poiché normalizza gli spazi bianchi e fa già la sostituzione. Dalla pagina man: "Comprimi più occorrenze dei caratteri [...] Questo si verifica dopo che tutte le cancellazioni e le traduzioni sono state completate."
dastrobu,

2
così ´tr -s "[: blank:]" "" ´ dovrebbe farlo, prima traduce tutti gli spazi vuoti in spazi e poi li schiaccia. Non è necessario un secondo "tr".
Dastrobu,

1
Ho provato printf 'ID \t Name\n' | tr -s "[:blank:]" " " | od -cb(come suggerito da @dastrobu) e ho ottenuto ID Name\n(con uno spazio) come output. L'hai provato davvero, @ user3183018?
Scott,

1
OK, lasciami provare a dirlo di nuovo. L'ho fatto printf 'ID␣\t␣Name\n' | tr -s "[:blank:]" "␣"  (come suggerito da @dastrobu), dove rappresenta uno spazio, e ho ottenuto ID␣Name\n(con uno spazio) come output. Questo è esattamente lo stesso del tuo esempio di "Porta <SPACE> <TAB> <SPACE> 6379", tranne per il fatto che ho usato le stringhe di intestazione della domanda. Mi chiedo se ci hai provato  tr -s "[:blank:]"(senza l' "␣"argomento finale ).
Scott,

1
Quando lo faccio printf 'ID \t Name\n' | od -cb, mostra esattamente cosa dovrebbe: ID ⁠  \t ⁠  N a m e \n(cioè,  ID 040 011 040 N a m e\n). Nel frattempo, con le tue prove, stai facendo esattamente l'errore che ho indovinato: eri in esecuzione tr -s "[:blank:]"(cioè  trcon un'opzione e  un argomento), invece del comando che @dastrobu e io abbiamo presentato quattro volte ora: tr -s '[:blank:]' '␣'(vale a dire,  trcon un'opzione e  due argomenti ).
Scott,

5

Chi ha bisogno di un programma (diverso dalla shell)?

while read a b
do
    echo "$a $b"
done < f1.txt

Se vuoi allineare i valori nella seconda colonna, come nella columnrisposta di polym , usa printfinvece di echo:

while read a b
do
    printf '%-2s %s\n' "$a" "$b"
done < f1.txt

1
In primo luogo, se confrontato con tr - questo è un suggerimento terribilmente debole dal punto di vista dell'efficienza, a meno che l'input non sia troppo piccolo per superare il piccolo costo trdell'invocazione, il che non vuol dire quanto più lavoro ci vuole per scrivere. Infine, non diresti che questo post in realtà non risponde alla domanda come richiesto? Qual è il modo migliore per sostituire tutti gli spazi bianchi con uno spazio usando solo tr?
mikeserv,

1
E inoltre - non potresti più facilmente fare qualcosa con $IFS? Forse piace IFS=' <tab>' set -f ; echo $(cat <file):?
mikeserv,

2

Questa è una vecchia domanda e risolta molte volte. Solo per completezza: avevo un problema simile, ma volevo passare le linee via pipe al programma antother. Ho usato xargs .

-L max-lines
   Use at most max-lines nonblank input lines per command line.
   Trailing blanks cause an input line to be logically continued 
   on the next input line.  Implies -x.

quindi cat f1.txt | xargs -L1sembra produrre esattamente quello che vuoi.

Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.