Hvordan bruker jeg en shell-kommando for å bare vise den første kolonnen og den siste kolonnen i en tekstfil?

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 bruk sponge. 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 

Legg igjen en kommentar

Din e-postadresse vil ikke bli publisert. Obligatoriske felt er merket med *