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
awkstesso, nel blocco BEGIN.awk "BEGIN {FS = OFS = "|"} {print $1, $8}" logfile -
Puoi assegnare queste variabili quando chiami
awkdalla 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$NFinvece di codificare in modo rigido$8per ottenere lultima colonna. - dopodiché come aggiornare il file?
- @pankajprasad Scrivi su un nuovo file con h
>quindi sovrascrivi quello vecchio o utilizzasponge. 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