Hvordan bruges en shell-kommando til kun at vise den første kolonne og sidste kolonne i en tekstfil?

Jeg har brug for hjælp til at finde ud af, hvordan man bruger kommandoen sed til kun at vise den første kolonne og den sidste kolonne i en tekstfil. Her er hvad jeg hidtil har til kolonne 1:

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

Mit svage forsøg på at få den sidste kolonne til at vise også var:

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

Dette tager dog den første kolonne og sidste kolonne og fletter dem sammen i en liste. Er der en måde at udskrive den første kolonne og sidste kolonne tydeligt med sed- og awk-kommandoer?

Eksempelindgang:

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

Kommentarer

  • Angiv nogle eksempler på input.

Svar

Næsten der. Sæt bare begge kolonnereferencer ved siden af hinanden.

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

Bemærk også, at du ikke har brug for cat her .

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

Bemærk også, at du kan fortælle awk, at søjleseparatorerne er | i stedet for mellemrum, så du behøver heller ikke sed.

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

I henhold til forslag af Caleb , hvis du vil have en løsning, der stadig udsender det sidste felt , selvom der ikke er nøjagtigt otte, kan du bruge $NF.

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

Også hvis du vil have output for at bevare | separatorer, i stedet for at bruge et mellemrum kan du angive outputfeltadskillere. Desværre er det “lidt mere klodset end blot at bruge -F -flagget, men her er tre tilgange.

  • Du kan tildele input og outputfeltadskillere i awk i BEGIN-blokken.

    awk "BEGIN {FS = OFS = "|"} {print $1, $8}" logfile 
  • Du kan tildele disse variabler, når du ringer til awk fra kommandolinjen via flagget -v.

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

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

Kommentarer

  • Godt arbejde med at nedbryde, hvordan dette problem kan forenkles. Du kan tilføje en note om, hvordan du bruger | som outputudskiller i stedet for standard plads til streng sammenkædning. Du kan også forklare at bruge $NF i stedet for hårdkodning $8 for at få den sidste kolonne.
  • derefter hvordan opdateres filen?
  • @pankajprasad Skriv til en ny fil med h > skriv derefter den gamle over, eller brug sponge. Dette er dog virkelig et nyt spørgsmål.
  • @Sparhawk det virker, men reaming-indhold slettes. hvordan skal man håndtere det?
  • @pankajprasad Du skal stille et nyt spørgsmål. Klik på den store blå knap øverst, der siger ” Stil spørgsmål “.

Svar

Du bruger awk alligevel:

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

Kommentarer

  • Ville ‘ t skal du specificere inputfeltadskilleren (da det i dette tilfælde ser ud til at være | snarere det mellemrum) med -F\| eller lignende? Også hvad hvis han ville bruge den samme afgrænser til output?
  • @Caleb Sandsynligvis: Jeg ventede på, at OP skulle bekræfte, hvordan nøjagtigt input lignede, snarere end at prøve at gæt baseret på de ikke-fungerende eksempler …
  • Bemærk, at det forudsættes, at input indeholder mindst 2 felter.
  • @St é phaneChazelas OP angav tydeligt i kode, at det altid har otte felter.
  • @ michaelb958 Jeg synes ” klart ” overvurderer sagen, bare lidt 🙂

Svar

Erstat bare fra første til sidste | med en | (eller mellemrum hvis du foretrækker det):

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

Bemærk, at selvom der ikke er sed implementering, hvor | er speciel (så længe udvidet regelmæssigt udtryk er ikke aktiveret via -E eller i nogle implementeringer), \| i sig selv er speciel i nogle som GNU sed. Så du bør ikke undslippe | hvis du har til hensigt at det skal matche | -tegnet.

Hvis du udskifter med mellemrum, og hvis input allerede muligvis indeholder linjer med kun |, skal du behandle det specielt som |.*| vandt ikke match på disse.Det kunne være:

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

(det vil sige at .*| -delen er valgfri) Eller:

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

eller:

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

Hvis du vil have det første og det ottende felt uanset antallet af felter i input, så er det bare:

cut -d"|" -f1,8 

(alle dem vil arbejde med ethvert POSIX-kompatibelt værktøj, forudsat at input danner gyldig tekst (især sed dem fungerer normalt ikke, hvis input har bytes eller sekvenser af bytes, der ikke danner gyldige tegn i det aktuelle sprog som f.eks. printf "unix|St\351phane|Chazelas\n" | sed "s/|.*|/|/" i et UTF-8-sprog)).

Svar

Hvis du finder dig selv ubehagelig og sed-mindre, kan du opnå samme ting med kerneudstyr:

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

Kommentarer

  • cut er renere og mere kompakt end awk / sed, når du bare er interesseret i den første kolonne, eller hvis afgrænsningerne er faste (dvs. ikke et variabelt antal mellemrum).
  • Temmelig elegant!

Svar

Det ser ud til, at du prøver at få det første og sidste felt i tekst, der er afgrænset af |.

Jeg antog, at din logfil indeholder teksten som nedenfor,

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

Og du vil have output ligesom,

foo bar bar foo 

Hvis ja, så kommer kommandoen til dine “s

Gennem 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

  • Kolonnerne afgrænses ikke af et rør | men de er i kolonner, jeg er interesseret i at bruge sed, men ikke at bruge kommandoen awk som du gjorde i din kommando: sed -r ‘ s ~ ^ ([^ |] *) . * \ | (. *) $ ~ \ 1 \ 2 ~ ‘ fil
  • ” Kolonnerne er ikke afgrænset af et rør | men de er i kolonner “, mener du kolonner er adskilt af mellemrum?
  • En prøveindgang og en output ville være bedre.

Svar

Du skulle sandsynligvis gøre det med sed – jeg ville alligevel – men bare fordi ingen har skrevet denne endnu:

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 

Skriv et svar

Din e-mailadresse vil ikke blive publiceret. Krævede felter er markeret med *