Come utilizzare un comando di shell per mostrare solo la prima e lultima colonna in un file di testo?

Ho bisogno di aiuto per capire come utilizzare il comando sed per mostrare solo la prima e lultima colonna in un file di testo. Ecco cosa ho finora per la colonna 1:

cat logfile | sed "s/\|/ /"|awk "{print $1}" 

Il mio debole tentativo di mostrare anche lultima colonna è stato:

cat logfile | sed "s/\|/ /"|awk "{print $1}{print $8}" 

Tuttavia, questo prende la prima e lultima colonna e le unisce in un unico elenco. Esiste un modo per stampare chiaramente la prima e le ultime colonne con i comandi sed e awk?

Esempio di input:

foo|dog|cat|mouse|lion|ox|tiger|bar 

Commenti

  • Fornisci un input di esempio.

Risposta

Ci siamo quasi. Metti semplicemente entrambi i riferimenti di colonna uno accanto allaltro.

cat logfile | sed "s/|/ /" | awk "{print $1, $8}" 

Tieni presente inoltre che non è necessario cat qui .

sed "s/|/ /" logfile | awk "{print $1, $8}" 

Tieni inoltre presente che puoi dire a awk che i separatori di colonna sono |, invece degli spazi, quindi non è necessario nemmeno sed.

awk -F "|" "{print $1, $8}" logfile 

Come da suggerimenti di Caleb , se desideri una soluzione che restituisca comunque lultimo campo , anche se non sono esattamente otto, puoi utilizzare $NF.

awk -F "|" "{print $1, $NF}" logfile 

Inoltre, se desideri output per mantenere i separatori |, invece di utilizzare uno spazio, puoi specificare i separatori del campo di output. Sfortunatamente, “è un po più goffo del semplice utilizzo del flag -F, ma qui ci sono tre approcci.

  • Puoi assegnare linput e i separatori dei campi di output in awk stesso, nel blocco BEGIN.

    awk "BEGIN {FS = OFS = "|"} {print $1, $8}" logfile 
  • Puoi assegnare queste variabili quando chiami awk dalla riga di comando, tramite il flag -v.

    awk -v "FS=|" -v "OFS=|" "{print $1, $8}" logfile 
  • o semplicemente:

    awk -F "|" "{print $1 "|" $8}" logfile 

Commenti

  • Ottimo lavoro analizzando come questo problema può essere semplificato. Potresti aggiungere una nota su come utilizzare | come separatore di output invece di lo spazio predefinito per la concatenazione di stringhe. Potresti anche spiegare di utilizzare $NF invece di codificare in modo rigido $8 per ottenere lultima colonna.
  • dopodiché come aggiornare il file?
  • @pankajprasad Scrivi su un nuovo file con h > quindi sovrascrivi quello vecchio o utilizza sponge. Questa è davvero una nuova domanda.
  • @Sparhawk funziona, ma lalesatura del contenuto viene cancellata. come affrontarlo?
  • @pankajprasad Devi fare una nuova domanda. Fai clic sul grande pulsante blu in alto con la dicitura ” Fai una domanda “.

Risposta

Stai utilizzando awk comunque:

awk "{ print $1, $NF }" file 

Commenti

  • ‘ non è necessario specificare il separatore del campo di input (poiché in questo caso sembra essere | piuttosto quello spazio) con -F\| o simile? E se volesse usare lo stesso delimitatore per loutput?
  • @Caleb Probabilmente: stavo aspettando che lOP confermasse laspetto esattamente dellinput, piuttosto che provare a ipotesi basata su esempi non funzionanti …
  • Nota che questo presuppone che linput contenga almeno 2 campi.
  • @St é phaneChazelas OP ha chiaramente indicato nel codice che ha otto campi, sempre.
  • @ michaelb958 Penso ” chiaramente ” sta esagerando, solo un po 🙂

Risposta

Basta sostituire dalla prima allultima | con | (o spazio se preferisci):

sed "s/|.*|/|/" 

Nota che sebbene non ci sia sed implementazione dove | è speciale (purché esteso regolare le espressioni non sono abilitate tramite -E o in alcune implementazioni), \| stesso è speciale in alcuni come GNU sed. Quindi non dovresti eseguire lescape di | se intendi che corrisponda al carattere |.

Se si sostituisce con spazio e se linput può già contenere righe con una sola |, allora “dovrai trattarlo specialmente come |.*| non corrisponde a quelli.Potrebbe essere:

sed "s/|\(.*|\)\{0,1\}/ /" 

(ovvero rendere la parte .*| facoltativa) Oppure:

sed "s/|.*|/ /;s/|/ /" 

o:

sed "s/\([^|]*\).*|/\1 /" 

Se desideri il primo e lottavo campo indipendentemente dal numero di campi linput, quindi è solo:

cut -d"|" -f1,8 

(tutti quelli funzionerebbero con qualsiasi utilità conforme a POSIX assumendo linput forma un testo valido (in particolare, quelli sed generalmente non funzionano se linput ha byte o sequenze di byte che non formano caratteri validi nella lingua corrente come ad esempio printf "unix|St\351phane|Chazelas\n" | sed "s/|.*|/|/" in una lingua UTF-8)).

Rispondi

Se ti trovi senza awk e sed, puoi ottenere il stessa cosa con coreutils:

paste <( cut -d"|" -f1 file) \ <(rev file | cut -d"|" -f1 | rev) 

Commenti

  • cut è più pulito e più compatto di awk / sed quando sei interessato solo alla prima colonna, o se i delimitatori sono fissi (cioè non un numero variabile di spazi).
  • Abbastanza elegante!

Risposta

Sembra che tu stia cercando di ottenere il primo e lultimo campo di testo che sono delimitati da |.

Presumo che il tuo file di log contenga il testo come di seguito,

foo|dog|cat|mouse|lion|ox|tiger|bar bar|dog|cat|mouse|lion|ox|tiger|foo 

E tu vuoi loutput come,

foo bar bar foo 

Se sì, allora ecco che arriva il comando per il tuo “s

Attraverso GNU sed,

sed -r "s~^([^|]*).*\|(.*)$~\1 \2~" file 

Esempio:

$ echo "foo|dog|cat|mouse|lion|ox|tiger|bar" | sed -r "s~^([^|]*).*\|(.*)$~\1 \2~" foo bar 

Commenti

  • Le colonne non sono delimitate da una barra verticale | ma sono in colonne, mi interessa usare sed ma non usare il comando awk come hai fatto nel tuo comando: sed -r ‘ s ~ ^ ([^ |] *) . * \ | (. *) $ ~ \ 1 \ 2 ~ ‘ file
  • ” Le colonne sono non delimitato da una pipe | ma sono nelle colonne “, vuoi dire che le colonne sono separate da spazi?
  • Sarebbe meglio un input e un output di esempio.

Risposta

Probabilmente dovresti farlo con sed – lo farei comunque – ma, solo perché nessuno ha ancora scritto questo:

while IFS=\| read col1 cols do printf %10s%-s\\n "$col1 |" " ${cols##*|}" done <<\INPUT foo|dog|cat|mouse|lion|ox|tiger|bar INPUT 

OUTPUT

 foo | bar 

Lascia un commento

Il tuo indirizzo email non sarà pubblicato. I campi obbligatori sono contrassegnati *