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 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