Nedenfor er teksten i filen:

Pseudo name=Apple Code=42B state=fault Pseudo name=Prance Code=43B state=good 

Jeg skal grep for “42B” og få output fra ovenstående tekst som:

Pseudo name=Apple Code=42B state=fault 

Har nogen idé om, hvordan man opnår dette ved hjælp af grep / awk / sed?

Kommentarer

  • Du taggede dette spørgsmål med bare " grep ". Leder du kun efter " grep " løsninger da? I spørgsmålet angiver du awk & sed også. Kan vi tilføje disse tags? Jeg var ikke ' ikke sikker på din hensigt, da jeg redigerede spørgsmålet i går aftes.
  • stackoverflow.com/ spørgsmål / 12024410 / …

Svar

Med awk

awk -v RS="" "/42B/" file 

RS= ændres input-record separator fra en ny linje til tomme linjer. Hvis et felt i en post indeholder /42B/ skal du udskrive posten.

"" (nullstrengen) er en magi værdi, der bruges til at repræsentere blanke linjer i henhold til POSIX :

Hvis RS er nul, derefter adskilles poster med sekvenser bestående af en <newline> plus en eller flere tomme linjer, ledende eller efterfølgende tomme linjer må ikke resultere i tomme poster i begyndelsen eller slutningen af input, og en <newline> skal altid være en feltadskiller, uanset hvilken værdi FS er.

Outputafsnittene vil ikke være adskilt, da udgangsseparatoren forbliver en enkelt ny linje. For at sikre, at der er en tom linje mellem outputafsnit, skal du indstille udgangspostseparatoren til to nye linjer:

awk -v RS="" -v ORS="\n\n" "/42B/" file 

Kommentarer

  • +1 for en elegant løsning. Du behøver ikke ' ikke omdirigere filen …
  • fingrene var på autopilot.
  • @jasonwryan, medmindre du har brug for adgang til filnavnet inden for awk (FILENAME), er det ' ikke en dårlig idé at bruge omdirigering, da det undgår problemer for filnavne, der indeholder = eller starter med - (eller er -), giver ensartede fejlmeddelelser og undgår at køre awk eller udføre andre omdirigeringer, hvis inputfilen ikke kan ' åbnes.

Svar

Under forudsætning af, at dataene er struktureret, så det altid er linjen før og efter det, du ønsker, kan du bruge grep “s -A (efter) og -B (før) skifter for at fortælle det at inkludere 1 linje før kampen og 1 linje efter den:

$ grep -A 1 -B 1 "42B" sample.txt Pseudo name=Apple Code=42B state=fault 

Hvis du vil have samme nummerlinjer før og efter søgeudtrykket kan du bruge -C (kontekst) switch:

$ grep -C 1 "42B" sample.txt Pseudo name=Apple Code=42B state=fault 

Hvis du “gerne vil være strengere, når du matcher de flere linjer, kan du bruge værktøjet pcregrep for at matche en mønster over flere linjer:

$ pcregrep -M "Pseudo.*\n.*42B.*\nstate.*" sample.txt Pseudo name=Apple Code=42B state=fault 

Ovenstående mønster matcher som følger:

  • -M – flere linjer
  • "Pseudo.*\n.*42B.*\nstate.*" – matcher en gruppe strenge, hvor den første streng starter med ordet "Pseudo" efterfulgt af eventuelle tegn op til slutningen af linjen \n, efterfulgt af alle tegn op indtil strengen "42B" efterfulgt af eventuelle tegn indtil en anden ende af linjen (\n) efterfulgt af strengen "state" efterfulgt af eventuelle tegn.

Kommentarer

  • -C (kontekst) kan bruges som en genvej, hvis -A og -B er de samme.
  • @DavidBaggerman – tak. Føjede det til svaret.
  • Hvorfor den nedstemte stemme? Dette besvarer spørgsmålet.

Svar

grep nogle varianter af Unix har -p flag for “afsnit”. Jeg ved, at AIX gør .

grep -p 42B <myfile> 

ville gøre præcis, hvad du beder om der YMMV og GNU grep har ikke dette flag.

Kommentarer

  • At have -p-flag ville være vidunderligt. Især hvis det bruges sammen med -v, så du kan udelukke hele afsnit fra output.

Svar

Der er sandsynligvis en lignende nem måde at gøre det med awk, men i perl:

cat file | perl -ne "BEGIN { $/="\n\n" }; print if $_ =~ /42B/;" 

Det siger grundlæggende at opdele filen i klumper afgrænset af tomme linjer og derefter kun udskrive de klumper, der matcher dit regulære udtryk.

Kommentarer

  • Dette kan forenkles ved at bruge indstillinger og stenografi og miste ubrugelig brug af cat ; perl -00 -ne 'print if /42B/' file

Svar

En anden perl-løsning uden en efterfølgende tom linje:

perl -00ne "if ($_ =~ /42B/) {chomp($_); printf "%s\n",$_}" foo 

Eksempel

% perl -00ne "if ($_ =~ /42B/) {chomp($_); printf "%s\n",$_}" foo Pseudo name=Apple Code=42B state=fault % cat foo Pseudo name=Apple Code=42B state=fault Pseudo name=Prance Code=43B state=good 

Kommentarer

  • Eller kortere (og dermed mere læsbar), som triplee skrev i en kommentar: perl -00 -ne 'print if /42B/' file.

Skriv et svar

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