Come fare in modo che il comando 'cut' tratti gli stessi delimitatori sequenziali di uno?


309

Sto cercando di estrarre un certo (il quarto) campo dal flusso di testo basato su colonne e adattato allo spazio. Sto cercando di utilizzare il cutcomando nel modo seguente:

cat text.txt | cut -d " " -f 4

Sfortunatamente, cutnon considera diversi spazi come un delimitatore. Avrei potuto passare attraverso awk

awk '{ printf $4; }'

o sed

sed -E "s/[[:space:]]+/ /g"

per far crollare gli spazi, ma mi piacerebbe sapere se esiste un modo per gestire cutnativamente e diversi delimitatori?


12
AWK è la strada da percorrere.
In pausa fino a ulteriore avviso.

Risposte:


546

Provare:

tr -s ' ' <text.txt | cut -d ' ' -f4

Dalla trpagina man:

-s, --squeeze-repeats sostituisce ogni sequenza di input di un carattere ripetuto
                        che è elencato in SET1 con una singola occorrenza
                        di quel personaggio

24
Non c'è bisogno di catqui. Potresti passare < text.txtdirettamente a tr. it.wikipedia.org/wiki/Cat_%28Unix%29#Useless_use_of_cat
arielf

1
Non sono sicuro che sia più semplice, ma stai per unire, puoi rinunciare a tagliare -de tradurre direttamente da più caratteri in scheda. Ad esempio: sono venuto qui alla ricerca di un modo per esportare automaticamente il mio display:who am i | tr -s ' ()' '\t' | cut -f5
Leo

Questo non rimuove gli spazi bianchi iniziali / finali (che possono o non possono essere desiderati, ma di solito non lo sono), in contrasto con la soluzione awk. La soluzione awk è anche molto più leggibile e meno dettagliata.
n.caillou,

-1 ATTENZIONE: QUESTA NON È LA STESSA COSA COME TRATTARE I DELIMETRI SEQUENZIALI COME UNO. Confronta echo "a b c" | cut -d " " -f2-,echo "a b c" | tr -s " " | cut -d " " -f2-
user541686

96

Mentre commenti nella tua domanda, awkè davvero la strada da percorrere. Usare cutè possibile insieme tr -sa spremere gli spazi, come mostra la risposta di kev .

Vorrei tuttavia passare attraverso tutte le possibili combinazioni per i futuri lettori. Le spiegazioni sono nella sezione Test.

tr | tagliare

tr -s ' ' < file | cut -d' ' -f4

awk

awk '{print $4}' file

bash

while read -r _ _ _ myfield _
do
   echo "forth field: $myfield"
done < file

sed

sed -r 's/^([^ ]*[ ]*){3}([^ ]*).*/\2/' file

test

Dato questo file, testiamo i comandi:

$ cat a
this   is    line     1 more text
this      is line    2     more text
this    is line 3     more text
this is   line 4            more    text

tr | tagliare

$ cut -d' ' -f4 a
is
                        # it does not show what we want!


$ tr -s ' ' < a | cut -d' ' -f4
1
2                       # this makes it!
3
4
$

awk

$ awk '{print $4}' a
1
2
3
4

bash

Questo legge i campi in sequenza. Usando _indichiamo che questa è una variabile usa e getta come una "variabile spazzatura" per ignorare questi campi. In questo modo, memorizziamo $myfieldcome il quarto campo nel file, indipendentemente dagli spazi tra loro.

$ while read -r _ _ _ a _; do echo "4th field: $a"; done < a
4th field: 1
4th field: 2
4th field: 3
4th field: 4

sed

Questo cattura tre gruppi di spazi e senza spazi ([^ ]*[ ]*){3}. Quindi, cattura tutto ciò che arriva fino a uno spazio come il quarto campo, con il quale è finalmente stampato \1.

$ sed -r 's/^([^ ]*[ ]*){3}([^ ]*).*/\2/' a
1
2
3
4

2
awknon è solo elegante e semplice, è anche incluso in VMware ESXi, dove trmanca.
user121391,

2
@ user121391 ancora un altro motivo per usare awk!
fedorqui "SO smettere di danneggiare"

@fedorqui Non ho mai sentito parlare del trattino basso come "variabile spazzatura". Potete fornire ulteriori approfondimenti / riferimenti su questo?
BryKKan,

1
@BryKKan L'ho imparato in Greg Come posso leggere un file (flusso di dati, variabile) riga per riga (e / o campo per campo)? : Alcune persone usano la variabile usa e getta _ come "variabile junk" per ignorare i campi. Può anche essere usato più di una volta in un singolo readcomando (o, in effetti, qualsiasi variabile) , se non ci interessa cosa succede . Può essere qualsiasi cosa, è solo che in qualche modo è diventato standard al posto di junk_varo whatever:)
fedorqui 'COSI fermata del male'

25

la soluzione più breve / amichevole

Dopo essere stato frustrato dalle troppe limitazioni di cut, ho scritto il mio sostituto, che ho chiamato cutsper "ridurre gli steroidi".

tagli fornisce quella che è probabilmente la soluzione più minimalista a questo e molti altri problemi di taglia / incolla correlati.

Un esempio, tra i tanti, che affronta questa particolare domanda:

$ cat text.txt
0   1        2 3
0 1          2   3 4

$ cuts 2 text.txt
2
2

cuts supporti:

  • rilevamento automatico dei delimitatori di campo più comuni nei file (+ possibilità di sovrascrivere i valori predefiniti)
  • delimitatori con corrispondenza multi-char, mixed-char e regex
  • estrarre colonne da più file con delimitatori misti
  • offset dalla fine della linea (usando numeri negativi) oltre all'inizio della linea
  • incollaggio automatico di colonne affiancate (non è necessario invocare pasteseparatamente)
  • supporto per il riordino sul campo
  • un file di configurazione in cui gli utenti possono modificare le proprie preferenze personali
  • grande enfasi sulla facilità d'uso e la digitazione minimalista richiesta

e altro ancora. Nessuno dei quali è fornito dalla norma cut.

Vedi anche: https://stackoverflow.com/a/24543231/1296044

Fonte e documentazione (software libero): http://arielf.github.io/cuts/


4

Questo one-liner Perl mostra quanto Perl sia strettamente legato a awk:

perl -lane 'print $F[3]' text.txt

Tuttavia, l' @Farray autosplit inizia all'indice $F[0]mentre iniziano i campi awk$1


3

Con le versioni di cutI know of, no, questo non è possibile. cutè utile principalmente per l'analisi di file in cui il separatore non è uno spazio bianco (ad esempio /etc/passwd) e che hanno un numero fisso di campi. Due separatori di fila significano un campo vuoto, e questo vale anche per gli spazi bianchi.

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.