Jeg trenger litt hjelp til å finne ut hvordan du bruker sed-kommandoen til å bare vise den første kolonnen og den siste kolonnen i en tekstfil. Her er hva jeg har så langt for kolonne 1:
cat logfile | sed "s/\|/ /"|awk "{print $1}"
Mitt svake forsøk på å få den siste kolonnen til å vises også var:
cat logfile | sed "s/\|/ /"|awk "{print $1}{print $8}"
Dette tar imidlertid den første kolonnen og den siste kolonnen og slår dem sammen i en liste. Er det en måte å skrive ut første kolonne og siste kolonne tydelig med sed- og awk-kommandoer?
Eksempelinngang:
foo|dog|cat|mouse|lion|ox|tiger|bar
Kommentarer
- Vennligst oppgi noen eksempler.
Svar
Nesten der. Bare sett begge kolonnehenvisningene ved siden av hverandre.
cat logfile | sed "s/|/ /" | awk "{print $1, $8}"
Vær også oppmerksom på at du ikke trenger cat
her .
sed "s/|/ /" logfile | awk "{print $1, $8}"
Vær også oppmerksom på at du kan fortelle awk
at kolonneskillerne er |
, i stedet for blanke, så trenger du ikke sed
heller.
awk -F "|" "{print $1, $8}" logfile
I henhold til forslag av Caleb , hvis du vil ha en løsning som fremdeles gir ut det siste feltet , selv om det ikke er akkurat åtte, kan du bruke $NF
.
awk -F "|" "{print $1, $NF}" logfile
Også, hvis du vil ha utdata for å beholde |
skilletegn, i stedet for å bruke et mellomrom kan du spesifisere skilletegnene for utdata. Dessverre er det «litt mer klønete enn å bare bruke -F
-flagget, men her er tre tilnærminger.
-
Du kan tilordne inngangen og utgangsfeltskillere i
awk
i seg selv, i BEGIN-blokken.awk "BEGIN {FS = OFS = "|"} {print $1, $8}" logfile
-
Du kan tilordne disse variablene når du ringer til
awk
fra kommandolinjen, via-v
-flagget.awk -v "FS=|" -v "OFS=|" "{print $1, $8}" logfile
-
eller ganske enkelt:
awk -F "|" "{print $1 "|" $8}" logfile
Kommentarer
- God jobb med å bryte ned hvordan dette problemet kan forenkles. Du kan legge til et notat om hvordan du bruker
|
som utgangsseparator i stedet for standardområdet for strengkonkatenering. Du kan også forklare å bruke$NF
i stedet for hardkoding$8
for å få den siste kolonnen. - etterpå hvordan oppdaterer du filen?
- @pankajprasad Skriv til en ny fil med h
>
Skriv deretter over den gamle, eller bruksponge
. Dette er egentlig et nytt spørsmål. - @Sparhawk det fungerer, men innhold som reaming blir slettet. hvordan takler du det?
- @pankajprasad Du må stille et nytt spørsmål. Klikk på den store blå knappen øverst som sier » Still spørsmål «.
Svar
Du bruker awk
uansett:
awk "{ print $1, $NF }" file
Kommentarer
- Ville ikke ‘ t du trenger å spesifisere inndatafelteskilleren (siden det i dette tilfellet ser ut til å være
|
heller det rommet) med-F\|
eller lignende? Også hva om han ønsket å bruke den samme avgrenseren for utdata? - @Caleb Sannsynligvis: Jeg ventet på at OP skulle bekrefte hvordan nøyaktig inngangen så ut, i stedet for å prøve å gjett basert på ikke-fungerende eksempler …
- Merk at det antas at inngangen inneholder minst to felt.
- @St é phaneChazelas OP uttalte tydelig i koden at den alltid har åtte felt.
- @ michaelb958 Jeg tror » tydelig » overvurderer saken bare litt 🙂
Svar
Bare bytt ut fra første til siste |
med en |
(eller mellomrom hvis du foretrekker det):
sed "s/|.*|/|/"
Merk at selv om det ikke er sed
implementering der |
er spesiell (så lenge utvidet vanlig uttrykk er ikke aktivert via -E
eller i noen implementeringer), er \|
spesiell i noen som GNU sed
. Så du bør ikke unnslippe |
hvis du har tenkt at den skal matche |
-tegnet.
Hvis du erstatter med mellomrom og hvis inngangen allerede kan inneholde linjer med bare en |
, må du behandle det spesielt som |.*|
vant ikke kamp på de.Det kan være:
sed "s/|\(.*|\)\{0,1\}/ /"
(det vil si at .*|
delen er valgfri) Eller:
sed "s/|.*|/ /;s/|/ /"
eller:
sed "s/\([^|]*\).*|/\1 /"
Hvis du vil ha første og åttende felt uavhengig av antall felt i inngangen, så er den bare:
cut -d"|" -f1,8
(alle de vil jobbe med et POSIX-kompatibelt verktøy forutsatt at inngangen danner gyldig tekst (spesielt sed
vil vanligvis ikke fungere hvis inngangen har byte eller sekvenser av byte som ikke danner gyldige tegn i gjeldende lokalitet som for eksempel printf "unix|St\351phane|Chazelas\n" | sed "s/|.*|/|/"
i et UTF-8-sted)).
Svar
Hvis du opplever at du er vanskelig og sindfri, kan du oppnå samme ting med kjernefysiske:
paste <( cut -d"|" -f1 file) \ <(rev file | cut -d"|" -f1 | rev)
Kommentarer
-
cut
er renere og mer kompakt enn awk / sed når du bare er interessert i den første kolonnen, eller hvis avgrensningene er faste (dvs. ikke et variabelt antall mellomrom). - Ganske elegant!
Svar
Det virker som om du prøver å få det første og siste tekstfeltet som er avgrenset av |
.
Jeg antok at loggfilen din inneholder teksten som nedenfor,
foo|dog|cat|mouse|lion|ox|tiger|bar bar|dog|cat|mouse|lion|ox|tiger|foo
Og du vil utdata som,
foo bar bar foo
Hvis ja, så kommer kommandoen for «s
Gjennom GNU sed,
sed -r "s~^([^|]*).*\|(.*)$~\1 \2~" file
Eksempel:
$ echo "foo|dog|cat|mouse|lion|ox|tiger|bar" | sed -r "s~^([^|]*).*\|(.*)$~\1 \2~" foo bar
Kommentarer
- Kolonnene avgrenses ikke av et rør | men de er i kolonner, jeg er interessert i å bruke sed, men ikke bruke awk-kommandoen som du gjorde i kommandoen din: sed -r ‘ s ~ ^ ([^ |] *) . * \ | (. *) $ ~ \ 1 \ 2 ~ ‘ fil
- » Kolonnene er ikke avgrenset av et rør | men de er i kolonner «, mener du kolonner er atskilt med mellomrom?
- En prøveinngang og en utgang ville være bedre.
Svar
Du burde nok gjøre det med sed
– jeg ville uansett – men bare fordi ingen har skrevet denne ennå:
while IFS=\| read col1 cols do printf %10s%-s\\n "$col1 |" " ${cols##*|}" done <<\INPUT foo|dog|cat|mouse|lion|ox|tiger|bar INPUT
UTGANG
foo | bar