Come rendere il comando ‘taglia’ trattare gli stessi delimitatori sequenziali come uno?

Sto provando ad estrarre un certo (il quarto) campo dal stream di testo adattato alle colonne e adattato allo spazio. Sto cercando di utilizzare il comando di cut nel modo seguente:

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

Sfortunatamente, il cut non considera più spazi come un delimitatore. Avrei potuto trasmettere 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 nativamente il cut e diversi delimitatori?

Provare:

 tr -s ' '  

Dalla pagina tr man:

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

Mentre commentate la vostra domanda, awk è davvero la strada da percorrere. Usare il cut è ansible insieme a tr -s per spremere gli spazi, come mostra la risposta di kev .

Lasciatemi comunque 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, proviamo 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 modo sequenziale. Usando _ indichiamo che questa è una variabile usa e getta come "variabile spazzatura" per ignorare questi campi. In questo modo, archiviamo $myfield come il 4 ° 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 nessuno spazio con ([^ ]*[ ]*){3} . Quindi, cattura qualsiasi cosa arrivi fino a uno spazio come il 4 ° campo, che viene infine stampato con \1 .

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

soluzione più breve / più amichevole

Dopo essere stato frustrato dalle troppe limitazioni di cut , ho scritto il mio sostituto, che ho chiamato cuts per “tagliare con gli steroidi”.

tagli fornisce quella che è probabilmente la soluzione più minimalista per questo e molti altri problemi relativi al taglia / incolla.

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

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

supporti per cuts :

  • rilevamento automatico dei più comuni delimitatori di campo nei file (+ possibilità di sovrascrivere i valori predefiniti)
  • delimitatori combinati multi-char, mixed-char e regex
  • estrazione di colonne da più file con delimitatori misti
  • offset dalla fine della riga (utilizzando numeri negativi) oltre all’inizio della riga
  • incollatura affiancata automatica delle colonne (non è necessario richiamare paste separatamente)
  • supporto per il riordino in campo
  • un file di configurazione in cui gli utenti possono modificare le proprie preferenze personali
  • grande enfasi sulla facilità d’uso e sulla tipizzazione minimalista richiesta

e altro ancora. Nessuno dei quali è fornito dal cut standard.

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

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

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

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

Tuttavia, l’array autosplit @F inizia all’indice $F[0] mentre i campi awk iniziano con $1

Con le versioni di cut che conosco, no, questo non è ansible. cut è utile principalmente per analizzare i file in cui il separatore non è uno spazio bianco (ad esempio /etc/passwd ) e che hanno un numero fisso di campi. Due separatori in una riga indicano un campo vuoto, e questo vale anche per gli spazi vuoti.