Come posso tagliare gli spazi bianchi iniziali e finali da ciascuna riga di un output?


155

Vorrei rimuovere tutti gli spazi e le schede iniziali e finali da ciascuna riga di un output.

Esiste uno strumento semplice come il quale trimpotrei convogliare il mio output?

File di esempio:

test space at back 
 test space at front
TAB at end  
    TAB at front
sequence of some    space in the middle
some empty lines with differing TABS and spaces:





 test space at both ends 

1
Per chiunque cerchi una soluzione per rimuovere le nuove righe, questo è un problema diverso. Per definizione una nuova riga crea una nuova riga di testo. Pertanto una riga di testo non può contenere una nuova riga. La domanda che vuoi porre è come rimuovere una nuova riga dall'inizio o dalla fine di una stringa: stackoverflow.com/questions/369758 o come rimuovere le righe vuote o solo spazi bianchi: serverfault.com/questions/252921
Tony,

Risposte:


200
awk '{$1=$1;print}'

o più corto:

awk '{$1=$1};1'

Taglia i spazi iniziali e finali o i caratteri di tabulazione 1 e comprime anche sequenze di tabulazioni e spazi in un unico spazio.

Questo funziona perché quando assegni qualcosa a uno dei campi , awkricostruisce l'intero record (come stampato da print) unendo tutti i campi ( $1, ..., $NF) con OFS(spazio per impostazione predefinita).

1 (e possibilmente altri caratteri vuoti a seconda della locale e awkdell'implementazione)


2
Il punto e virgola sul secondo esempio è superfluo. Potrebbe usare:awk '{$1=$1}1'
Brian


Interessante ... Nessun punto e virgola è supportato da gawk, mawk e awk di OS X. (Almeno per le mie versioni (1.2, 4.1.1 e 20070501, rispettivamente)
Brian

1
L'unica cosa che non mi piace di questo approccio è che perdi spazi ripetuti all'interno della linea. Ad esempio,echo -e 'foo \t bar' | awk '{$1=$1};1'
user.friendly

2
echo ' hello ' | xargs
JREAM

44

Il comando può essere condensato in questo modo se si utilizza GNU sed:

$ sed 's/^[ \t]*//;s/[ \t]*$//' < file

Esempio

Ecco il comando sopra in azione.

$ echo -e " \t   blahblah  \t  " | sed 's/^[ \t]*//;s/[ \t]*$//'
blahblah

È possibile utilizzare hexdumpper confermare che il sedcomando sta rimuovendo correttamente i caratteri desiderati.

$ echo -e " \t   blahblah  \t  " | sed 's/^[ \t]*//;s/[ \t]*$//' | hexdump -C
00000000  62 6c 61 68 62 6c 61 68  0a                       |blahblah.|
00000009

Classi di personaggi

Puoi anche usare i nomi delle classi di caratteri invece di elencare letteralmente i set in questo modo [ \t]:

$ sed 's/^[[:blank:]]*//;s/[[:blank:]]*$//' < file

Esempio

$ echo -e " \t   blahblah  \t  " | sed 's/^[[:blank:]]*//;s/[[:blank:]]*$//'

La maggior parte degli strumenti GNU che utilizzano espressioni regolari (regex) supportano queste classi.

 [[:alnum:]]  - [A-Za-z0-9]     Alphanumeric characters
 [[:alpha:]]  - [A-Za-z]        Alphabetic characters
 [[:blank:]]  - [ \x09]         Space or tab characters only
 [[:cntrl:]]  - [\x00-\x19\x7F] Control characters
 [[:digit:]]  - [0-9]           Numeric characters
 [[:graph:]]  - [!-~]           Printable and visible characters
 [[:lower:]]  - [a-z]           Lower-case alphabetic characters
 [[:print:]]  - [ -~]           Printable (non-Control) characters
 [[:punct:]]  - [!-/:-@[-`{-~]  Punctuation characters
 [[:space:]]  - [ \t\v\f]       All whitespace chars
 [[:upper:]]  - [A-Z]           Upper-case alphabetic characters
 [[:xdigit:]] - [0-9a-fA-F]     Hexadecimal digit characters

L'utilizzo di questi set anziché di set letterali sembra sempre uno spreco di spazio, ma se sei preoccupato che il tuo codice sia portatile o che tu abbia a che fare con set di caratteri alternativi (pensa a livello internazionale), probabilmente vorrai usare i nomi delle classi anziché.

Riferimenti


Si noti che [[:space:]]non equivale al [ \t]caso generale (unicode, ecc.). [[:space:]]sarà probabilmente molto più lento (poiché ci sono molti più tipi di spazi bianchi in Unicode rispetto a solo ' 'e '\t'). Stessa cosa per tutti gli altri.
Olivier Dulac il

sed 's/^[ \t]*//'non è portatile. Alla fine POSIX richiede anche che rimuova una sequenza di spazio, barra rovesciata o tcaratteri, ed è ciò che GNU sedfa anche quando si POSIXLY_CORRECTtrova nell'ambiente.
Stéphane Chazelas,

E se volessi tagliare i caratteri di nuova riga? '\ n \ n text \ n \ n'
Eugene Biryukov,

Mi piace la soluzione sed a causa della mancanza di altri effetti collaterali come nella soluzione awk. La prima variante non funziona quando l'ho provata bash su OSX jsut ora, ma la versione della classe di caratteri funziona:sed 's/^[[:blank:]]*//;s/[[:blank:]]*$//'
Tony

@EugeneBiryukov vedi il mio commento sul post originale
Tony,

23

Come suggerito da Stéphane Chazelas nella risposta accettata, ora puoi
creare uno script /usr/local/bin/trim:

#!/bin/bash
awk '{$1=$1};1'

e dare a quel file i diritti eseguibili:

chmod +x /usr/local/bin/trim

Ora puoi passare ogni output ad trimesempio:

cat file | trim

(per i commenti qui sotto: l'ho usato prima: while read i; do echo "$i"; done
che funziona anche bene, ma è meno performante)


1
Buona fortuna se il tuo file è enorme e / o contiene barre rovesciate.
don_crissti,

1
@don_crissti: potresti commentare un po 'di più ?, quale soluzione sarebbe più adatta per file di grandi dimensioni e come potrei modificare la mia soluzione se il file contenesse barre rovesciate?
rubo77

3
Dovrete usare while read -r lineper preservare backslash e anche allora ... . Per quanto riguarda i file / la velocità enormi, davvero, hai scelto la soluzione peggiore. Non credo ci sia niente di peggio là fuori. Vedi le risposte su Perché usare un loop di shell per elaborare le cattive pratiche di testo? incluso il mio commento sull'ultima risposta in cui ho aggiunto un link a un benchmark di velocità. Le sedrisposte qui sono IMO perfettamente bene e molto meglio di read.
don_crissti,

@don_crissti ... e / o ha linee che iniziano con -e seguite da combinazioni di 1 o più caratteri e, E o n e / o contiene caratteri NUL. Inoltre, verrà ignorata una riga non terminata dopo l'ultima nuova riga.
Stéphane Chazelas,

1
Puoi anche aggiungere un alias in / etc / profile (o il tuo ~ / .bashrc o ~ / .zshrc ecc ...) alias trim = "awk '{\ $ 1 = \ $ 1}; 1'"
Jeff Clayton

22

xargs senza argomenti lo fa.

Esempio:

trimmed_string=$(echo "no_trimmed_string" | xargs) 

1
Ciò contrasta anche più spazi all'interno di una linea, cosa non richiesta nella domanda
roaima,

1
@roaima: vero, ma la risposta accettata comprime anche gli spazi (cosa non richiesta nella domanda). Penso che il vero problema qui sia che xargsnon riuscirà a fornire se l'input contiene barre rovesciate e virgolette singole.
don_crissti,

@don_crissti ciò non significa che la risposta accettata risponda correttamente alla domanda come posta, però. Ma in questo caso qui non è stato contrassegnato come avvertimento mentre nella risposta accettata lo era. Spero di aver evidenziato il fatto nel caso in cui sia rilevante per un futuro lettore.
roaima,

Si rompe anche tra virgolette singole, doppie virgolette, caratteri di barra rovesciata. Gestisce anche una o più echoinvocazioni. Alcune implementazioni dell'eco elaboreranno anche opzioni e / o barre rovesciate ... Funziona anche solo con input a riga singola.
Stéphane Chazelas,

17
sed -e 's/^[[:space:]]*//' -e 's/[[:space:]]*$//'

Se stai leggendo una riga in una variabile shell, lo readfa già se non diversamente indicato .


1
+1 per read. Quindi, se vieni a leggere mentre funziona, funziona:cat file | while read i; do echo $i; done
rubo77

1
@rubo tranne che nel tuo esempio anche la variabile non quotata viene rielaborata dalla shell. Usa echo "$i"per vedere il vero effetto diread
roaima,

13

Se memorizzi le linee come variabili, puoi usare bash per fare il lavoro:

rimuovere lo spazio bianco iniziale da una stringa:

shopt -s extglob
echo ${text##+([[:space:]])}

rimuovere gli spazi vuoti finali da una stringa:

shopt -s extglob
echo ${text%%+([[:space:]])}

rimuovere tutto lo spazio bianco da una stringa:

echo ${text//[[:space:]]}

Rimuovere tutto lo spazio bianco da una stringa non equivale a rimuovere sia gli spazi iniziali che quelli finali (come in questione).
catpnosi,

Di gran lunga la soluzione migliore - richiede solo built-in bash e nessuna fork di processo esterna.
user259412

2
Bello. Gli script eseguono MOLTO più velocemente se non devono inserire programmi esterni (come awk o sed). Funziona anche con versioni "moderne" (93u +) di ksh.
user1683793,

9

Per rimuovere tutti gli spazi iniziali e finali di una determinata linea grazie a uno strumento "convogliato", posso identificare 3 modi diversi che non sono completamente equivalenti. Queste differenze riguardano gli spazi tra le parole della riga di input. A seconda del comportamento previsto, farai la tua scelta.

Esempi

Per spiegare le differenze, consideriamo questa linea di input fittizia:

"   \t  A   \tB\tC   \t  "

TR

$ echo -e "   \t  A   \tB\tC   \t  " | tr -d "[:blank:]"
ABC

trè davvero un comando semplice. In questo caso, elimina qualsiasi spazio o carattere di tabulazione.

awk

$ echo -e "   \t  A   \tB\tC   \t  " | awk '{$1=$1};1'
A B C

awk elimina gli spazi iniziali e di coda e comprime in un unico spazio tutti gli spazi tra le parole.

sed

$ echo -e "   \t  A   \tB\tC   \t  " | sed 's/^[ \t]*//;s/[ \t]*$//'
A       B   C

In questo caso, sedelimina gli spazi iniziali e di coda senza toccare gli spazi tra le parole.

Osservazioni:

Nel caso di una parola per riga, trfa il lavoro.


Niente di tutto ciò è tuttavia in svantaggio / in testa alle nuove linee
manutenzione,

+1 per un elenco di soluzioni con il loro output (a volte imprevisto).
Tony,

@ user61382 è piuttosto tardi, ma vedi il mio commento sul post originale.
Tony,

@highmaintenance: utilizzare [:space:], anziché [: blank:], per il comando tr, come :, ... | tr -d [:space:]per rimuovere anche le nuove righe. (vedi: man tr)
tron5

6

sed è un ottimo strumento per questo:

                        # substitute ("s/")
sed 's/^[[:blank:]]*//; # parts of lines that start ("^")  with a space/tab 
     s/[[:blank:]]*$//' # or end ("$") with a space/tab
                        # with nothing (/)

Puoi usarlo per il tuo caso sia come tubazioni nel testo, ad es

<file sed -e 's/^[[...

o agendo su di esso "inline" se il tuo sedè quello GNU:

sed -i 's/...' file

ma cambiare la fonte in questo modo è "pericoloso" in quanto potrebbe essere irrecuperabile quando non funziona correttamente (o anche quando lo fa!), quindi esegui prima il backup (o l'uso -i.bakche ha anche il vantaggio di essere portabile su alcuni BSD sed) !


2

il comando translate funzionerebbe

cat file | tr -d [:blank:]

4
Questo comando non è corretto in quanto rimuove tutti gli spazi dal file, non solo gli spazi iniziali / finali.
Brian Redbeard,

@BrianRedbeard Hai ragione. Questa è ancora una risposta utile per una stringa monolitica, senza spazi.
Anthony Rutledge,

0

Se la stringa che si sta cercando di tagliare è corta e continua / contigua, si può semplicemente passarla come parametro a qualsiasi funzione bash:

    trim(){
        echo $@
    }

    a="     some random string   "

    echo ">>`trim $a`<<"
Output
>>some random string<<
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.