Vaikuttaa siltä, että käytän väärin grep / egrep.

Yritin etsiä merkkijonoja usealla rivillä, enkä löytänyt vastaavuutta, vaikka tiedän, että etsimieni pitäisi vastata. Alun perin ajattelin, että regeksini olivat väärässä, mutta luin lopulta, että nämä työkalut toimivat riviä kohden (myös regexi olivat niin vähäpätöisiä, ettei se voinut olla ongelma).

Joten mitä työkalua käytettäisiin useiden rivien kuvioiden hakemiseen?

Kommentit

  • mahdollinen kaksoiskappale Monirivikuviosta käyttämällä sed, awk tai grep
  • @CiroSantilli – En usko, että tämä Q ja se, johon linkitit, ovat kaksoiskappaleita. Toinen Q kysyy, kuinka ’ d sopivat monirivimalliin (ts. Minkä työkalun pitäisi / voin käyttää) käytä tätä tekemään), kun taas tämä kysyy miten se tehdään grep -palvelun kanssa. Ne ovat tiiviisti yhteydessä, mutta eivät duppeihin, IMO.
  • @sim nämä tapaukset ovat vaikea päättää: näen mielipiteesi. Mielestäni tämä tapaus on parempi kuin kaksoiskappale se käyttäjä sanoi, että "grep" ehdottaa verbiä ” grep ” ja suosituimmat vastaukset, mukaan lukien hyväksytty, älä ’ käytä grep-tiedostoa.
  • Ei ole mitään viitteitä osoittamaan, että tässä tarvitaan monirivistä säännöllistä lauseketta. Harkitse todellisen esimerkin näyttämistä syötetiedoilla ja odotettavissa olevilla lähtötiedoilla sekä edellisellä työlläsi.

Vastaa

Tässä ”sa sed sellainen, joka antaa sinulle grep -tyyppisen käyttäytymisen useilla linjoilla:

sed -n "/foo/{:start /bar/!{N;b start};/your_regex/p}" your_file 

Kuinka se toimii

  • -n estää jokaisen rivin tulostamisen oletuskäyttäytymisen.
  • /foo/{} kehottaa sitä vastaamaan foo ja tee se, mikä on ristiriitojen sisällä vastaaville viivoille. Korvaa foo kuvion alkuosalla.
  • :start on haarautuva tunniste, joka auttaa meitä jatkamaan silmukointia, kunnes löydämme regexillemme lopun.
  • /bar/!{} suorittaa mitä ruuduissa on rivit, jotka eivät vastaa bar. Korvaa mallin loppuosalla.
  • N liittää seuraavan rivin aktiiviseen puskuriin (sed kutsuu tätä malliavaruudeksi)
  • b start haarautuu ehdoitta luomaamme start -tunnisteeseen aikaisemmin niin, että seuraava rivi jatkuu niin kauan kuin kuviotila ei sisällä bar.
  • /your_regex/p tulostaa kuviotilan, jos se vastaa your_regex. Sinun tulisi korvata your_regex koko lausekkeella, jonka haluat yhdistää usealle riville.

Kommentit

Vastaa

Käytän yleensä työkalua kutsutaan pcregrep, joka voidaan asentaa suurimmalle osalle linux-makua käyttämällä yum tai apt.

Esimerkiksi.

Oletetaan, että sinulla on tiedosto nimeltä testfile, jonka sisältö on

abc blah blah blah def blah blah blah 

Voit suorittaa seuraavan komennon:

$ pcregrep -M "abc.*(\n|.)*def" testfile 

tehdä kaavojen täsmäys useilla riveillä.

Lisäksi voit tehdä saman myös sed -palvelun kanssa.

$ sed -e "/abc/,/def/!d" testfile 

Kommentit

  • tämä sed -ehdotus ohitetaan rivi, josta def löytyy

Vastaa

Yksinkertaisesti normaali grep, joka tukee Perl-regexp -parametria P, suorittaa tämän työn.

$ echo "abc blah blah blah def blah blah blah" | grep -oPz "(?s)abc.*?def" abc blah blah blah def 

(?s) kutsutaan DOTALL-muokkaajaksi, joka tekee pisteestä regexissasi vastaamaan merkkien lisäksi myös rivinvaihtoja.

kommentit

  • Kun yritän tätä ratkaisua, tulos ei pääty kohtaan ’ def ’ mutta siirtyy tiedoston loppuun ’ blah ’
  • ehkä grep ei tue -P -vaihtoehtoa
  • Tämä oli ainoa, joka toimi minulle – kokeili kaikkia sed -ehdotuksia, mutta ei mennyt ’ t niin pitkälle kuin asennat grep-vaihtoehtoja.
  • $ grep --version: iv id = ”bbd9ce5411” Windows Git Bash -kohdassa>

on vaihtoehto-P, --perl-regexp, mutta(?s)ei ’ ei näytä toimivan siellä. Se näyttää edelleen vain ensimmäisen rivin. Sama malli samalla testimerkkijonolla toimii osoitteessa regex101.com . Onko Git Bashissa vaihtoehtoa?sed? (sed (GNU sed) 4.8täällä)

  • Tiedätkö kuinka lisätä konteksti lähtöön? grep -1 ei toimi ’ t täällä.
  • Vastaa

    Tässä on yksinkertaisempi lähestymistapa Perlillä:

    perl -e "$f=join("",<>); print $& if $f=~/foo\nbar.*\n/m" file 

    tai (koska JosephR otti sed reitti , varastan häpeämättömästi hänen -ehdotuksensa )

    perl -n000e "print $& while /^foo.*\nbar.*\n/mg" file 

    ### Selitys

    $f=join("",<>);: tämä lukee koko tiedoston ja tallentaa sen sisällön (uudet rivit ja kaikki) muuttujaan $f. Yritämme sitten sovittaa foo\nbar.*\n ja tulostaa sen, jos se vastaa (erikoismuuttuja $& pitää viimeksi löydetyn vastaavuuden). ///m tarvitaan, jotta säännöllinen lauseke sopisi yhteen uudella rivillä.

    -0 asettaa syötetietueen erottimen. Jos asetat tämän arvoon 00, aktivoidaan ”kappaletila”, jossa Perl käyttää peräkkäisiä uusia rivejä (\n\n) tietueiden erottimena. Tapauksissa, joissa ei ole peräkkäisiä uusia viivoja, koko tiedosto luetaan (sekoitetaan) kerralla.

    ### Varoitus: Älä älä tee tätä suurille tiedostoille, se latautuu koko tiedosto muistiin ja se voi olla ongelma.

    Kommentit

    • En ’ t tiedä paljon Perlistä, mutta eikö ’ t sen tarvitse olla my $f=join("",<>);, tarkkaan ottaen?
    • Vain @Sapphire_Brick jos olet tiukassa tilassa (use strict;). ’ on hyvä tapa päästä mukaan, varsinkin kun kirjoitetaan suurempia skriptejä, mutta se ’ ylittää tämän pienen yhden linjan yksi.

    Vastaa

    Lisää, että meillä on tiedosto test.txt sisältää:

    blabla blabla foo here is the text to keep between the 2 patterns bar blabla blabla 

    Seuraavaa koodia voidaan käyttää:

    sed -n "/foo/,/bar/p" test.txt 

    Seuraavalle lähdölle:

    foo here is the text to keep between the 2 patterns bar 

    vastaus

    Grep-vaihtoehto siivilöinti tukee monirivistä hakua (vastuuvapauslauseke: Olen kirjoittaja).

    Oletetaan ”d5f5b1251b”>

    sisältää:

     <book> <title>Lorem Ipsum</title> <description>Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua</description> </book> 

    sift -m '<description>.*?</description>' (näytä rivit, jotka sisältävät kuvaus)

    Tulos:

     testfile: <description>Lorem ipsum dolor sit amet, consectetur testfile: adipiscing elit, sed do eiusmod tempor incididunt ut testfile: labore et dolore magna aliqua</description> 

    sift -m '<description>(.*?)</description>' --replace 'description="$1"' --no-filename (poimi ja muotoile kuvaus uudelleen)

    Tulos:

    description="Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua" 

    Kommentit

    • Erittäin mukava työkalu. Onnittelut! Yritä sisällyttää se jakeluihin, kuten Ubuntu.

    Vastaus

    Ratkaisin tämän minulle grepin ja – avulla Vaihtoehto, jolla on toinen grep.

    grep first_line_word -A 1 testfile | grep second_line_word 

    Vaihtoehto -A 1 tulostaa 1 rivin löydetyn rivin jälkeen. Tietysti se riippuu tiedostostasi ja sanayhdistelmästäsi. Mutta minulle se oli nopein ja luotettava ratkaisu.

    Kommentit

    • alias grepp = ’ grep –color = auto -B10 -A20 -i ’ sitten kissa joku tiedosto | grepp blah | grepp foo | grepp-baari … kyllä ne -A ja -B ovat erittäin käteviä …sinulla on paras vastaus
    • Tämä ei ole ’ t superdeterministinen, ja se ohittaa koko mallin ja tukee vain yhden yksittäisen rivin saamista (vain sen läheisyyden perusteella) ensimmäiselle riville). ’ on parempi kertoa ohjelmalle mennä niin pitkälle kuin sen täytyy mennä päästäksesi jonkinlaiseen malliin, jonka ’ uudelleen on aivan varma, onko tekstin loppu, jota ’ yrität löytää. Esimerkiksi jos testfile päivitetään siten, että second_line_word on kolmannella rivillä, niin paitsi sinulta puuttuu nyt myös ensimmäinen rivi (johtuen toinen grep), mutta ’ ei puutu riviä, joka alkoi näkyä näiden kahden välillä.
    • Tämä olisi tarpeeksi hyvä MO ad hoc -komennoille, joissa todella haluat vain yhden rivin lähdössä, jonka olet jo ymmärtänyt. En ’ usko, että ’ s mitä toimenpide on, ja voit todennäköisesti myös vain kopioida / liittää siinä vaiheessa se on tapauskohtainen.

    Vastaa

    Yksi tapa tehdä tämä on Perl. esimerkiksi. tässä on tiedoston foo sisältö:

    foo line 1 bar line 2 foo foo foo line 5 foo bar line 6 

    Nyt, tässä on joitain Perl-tiedostoja, jotka ottelu mistä tahansa rivistä, joka alkaa foo: lla, jota seuraa mikä tahansa rivi, joka alkaa pylvästä:

    cat foo | perl -e "while(<>){$all .= $_} while($all =~ /^(foo[^\n]*\nbar[^\n]*\n)/m) { print $1; $all =~ s/^(foo[^\n]*\nbar[^\n]*\n)//m; }" 

    Perl, eriteltynä:

    • while(<>){$all .= $_} Tämä lataa koko vakiotulon muuttujaan $all
    • while($all =~ Vaikka muuttujalla all on säännöllinen lauseke …
    • /^(foo[^\n]*\nbar[^\n]*\n)/m Regex: foo rivin alussa, minkä jälkeen seuraa mikä tahansa määrä ei-uuden rivin merkkejä, jota seuraa uusi rivi, jota seuraa välittömästi ”palkki”, ja loput rivistä, jossa on palkki. /m regexin lopussa tarkoittaa ”täsmää useita rivejä”
    • print $1 Tulosta regexin osa se oli sulkeissa (tässä tapauksessa koko säännöllinen lauseke)
    • s/^(foo[^\n]*\nbar[^\n]*\n)//m Poista regexin ensimmäinen osuma, jotta voimme yhdistää useita regex-tapauksia kyseisessä tiedostossa

    Ja lähtö:

    foo line 1 bar line 2 foo bar line 6 

    kommentit

    • Halusin vain sanoa, että Perlisi voidaan lyhentää idiomaattisemmaksi: perl -n0777E 'say $& while /^foo.*\nbar.*\n/mg' foo

    Vastaa

    Jos haluamme saada tekstin kahden kuvion väliin, lukuun ottamatta itseään.

    Täydennä meillä tiedosto test.txt sisältää:

    blabla blabla foo here is the text to keep between the 2 patterns bar blabla blabla 

    Seuraavaa koodia voidaan käyttää:

     sed -n "/foo/{ n b gotoloop :loop N :gotoloop /bar/!{ h b loop } /bar/{ g p } }" test.txt 

    Seuraavalle lähdölle:

    here is the text to keep between the 2 patterns 

    Kuinka se toimii, anna ”s” tee se askel askeleelta

    1. /foo/{ laukaistaan, kun rivi sisältää merkin ”foo”
    2. n korvaa kuviotila seuraavalla rivillä, eli sana ”täällä”
    3. b gotoloop haara tunnisteeseen ”gotoloop”
    4. :gotoloop määrittelee tunnisteen ”gotoloop”
    5. /bar/!{, jos kuvio ei sisällä palkkia
    6. h korvaa pitotila kuviolla, joten ”täällä” tallennetaan pitotilaan
    7. b loop haara tunnisteeseen ”silmukka”
    8. :loop määrittelee tunnisteen ”silmukka”
    9. N liittää kuvion pitotilaan.
      Nyt pitotila sisältää:
      ”tässä”
      ”on”
    10. :gotoloop Olemme nyt vaiheessa 4 ja jatka, kunnes rivi sisältää ”palkin”
    11. /bar/ -silmukka on valmis, ”palkki” on löydetty, se ” s kuviotila
    12. kuviotila korvataan pitotilalla, joka sisältää kaikki pääpiirin aikana tallentuneet rivit” foo ”ja” bar ”välillä
    13. p kopioi kuviotila vakiotulostukseen

    Valmis!

    kommentit

    • Hyvin tehty, +1. Vältän yleensä näiden komentojen käyttämistä tr ’ lisäämällä uudet rivit SOH: ksi ja suorittamalla normaalit sed-komennot ja korvaamalla uudet rivit.

    Vastaa

    Sähköpostiosoitettasi ei julkaista. Pakolliset kentät on merkitty *