Nedenfor er teksten i filen:
Pseudo name=Apple Code=42B state=fault Pseudo name=Prance Code=43B state=good
Jeg må grep for «42B» og få utdata fra teksten ovenfor som:
Pseudo name=Apple Code=42B state=fault
Er det noen som har ideer om hvordan du kan oppnå dette ved hjelp av grep
/ awk
/ sed
?
Kommentarer
- Du merket dette spørsmålet med bare " grep ". Leter du bare etter " grep " løsninger da? I spørsmålet angir du awk & sed også. Kan vi legge til disse kodene? Jeg var ikke ' ikke sikker på intensjonen din da jeg redigerte spørsmålet i går kveld.
- stackoverflow.com/ spørsmål / 12024410 / …
Svar
Med awk
awk -v RS="" "/42B/" file
RS=
endres separatoren for inngangspost fra en ny linje til tomme linjer. Hvis et felt i en post inneholder /42B/
skriv ut posten.
""
(nullstrengen) er en magi verdi brukt til å representere blanke linjer i henhold til POSIX :
Hvis RS er null, deretter skilles poster med sekvenser som består av en
<newline>
pluss ett eller flere blanke linjer, ledende eller etterfølgende tomme linjer skal ikke resultere i tomme poster i begynnelsen eller slutten av inngangen, og en<newline>
skal alltid være en feltseparator, uansett hvilken verdi FS er.
Utgangsparagrafene vil ikke separeres siden utgangsseparatoren forblir en enkelt ny linje. For å sikre at det er en tom linje mellom utgangsparagrafene, sett utskillingsutskilleren til to nye linjer:
awk -v RS="" -v ORS="\n\n" "/42B/" file
Kommentarer
- +1 for en elegant løsning. Du trenger ikke ' ikke å omdirigere filen skjønt …
- fingrene var på autopiloten.
- @jasonwryan, med mindre du trenger tilgang til filnavnet i awk (
FILENAME
), er det ' ikke en dårlig idé å bruke omdirigering, da det unngår problemer for filnavn som inneholder=
eller starter med-
(eller er-
), gir konsekvente feilmeldinger, og unngår å kjøreawk
eller utføre andre omdirigeringer hvis inndatafilen ikke kan ' ikke åpnes.
Svar
Forutsatt at dataene er strukturert slik at det alltid er linjen før og etter det du vil, kan du bruke grep «s -A
(etter) og -B
(før) bytter for å fortelle den å inkludere 1 linje før kampen og 1 linje etter den:
$ grep -A 1 -B 1 "42B" sample.txt Pseudo name=Apple Code=42B state=fault
Hvis du vil ha samme tallinjer før og etter søkeordet, kan du bruke -C
(kontekst) -bryteren:
$ grep -C 1 "42B" sample.txt Pseudo name=Apple Code=42B state=fault
Hvis du «vil være strengere når du samsvarer med flere linjer, kan du bruke verktøyet pcregrep
, for å matche en mønster over flere linjer:
$ pcregrep -M "Pseudo.*\n.*42B.*\nstate.*" sample.txt Pseudo name=Apple Code=42B state=fault
Ovennevnte mønster samsvarer med følgende:
-
-M
– flere linjer -
"Pseudo.*\n.*42B.*\nstate.*"
– samsvarer med en gruppe strenger der den første strengen starter med ordet"Pseudo"
etterfulgt av eventuelle tegn frem til slutten av linjen\n
, etterfulgt av alle tegn opp til strengen"42B"
etterfulgt av eventuelle tegn frem til en annen ende av linjen (\n
), etterfulgt av strengen"state"
etterfulgt av eventuelle tegn.
Kommentarer
-
-C
(kontekst) kan brukes som en snarvei, hvis-A
og-B
er de samme. - @ DavidBaggerman – takk. La det til i svaret.
- Hvorfor stemmer den ene ned? Dette svarer på spørsmålet.
Svar
grep
av noen smaker av Unix har -p
flagget for «avsnitt». Jeg vet at AIX gjør .
grep -p 42B <myfile>
ville gjort akkurat det du ber om der YMMV og GNU grep har ikke dette flagget.
Kommentarer
- Å ha -p-flagget ville være fantastisk. Spesielt hvis det brukes sammen med -v, slik at du kan ekskludere hele avsnitt fra utdata.
Svar
Det er sannsynligvis en like enkel måte å gjøre det med awk, men i perl:
cat file | perl -ne "BEGIN { $/="\n\n" }; print if $_ =~ /42B/;"
Som i utgangspunktet sier å dele filen i biter avgrenset av blanke linjer, og deretter bare skrive ut de biter som samsvarer med ditt vanlige uttrykk.
Kommentarer
- Dette kan forenkles ved å bruke alternativer og stenografi, og miste unyttig bruk av
cat
;perl -00 -ne 'print if /42B/' file
Svar
En annen perl-løsning, uten etterfø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 mer lesbar), som triplee skrev i en kommentar:
perl -00 -ne 'print if /42B/' file
.