Úgy tűnik, hogy visszaélek a grep / egrep fájlokkal.

Próbáltam többsoros húrokat keresni, és nem találtam egyezést, miközben tudom, hogy a keresettnek egyeznie kell. Eredetileg azt gondoltam, hogy a regexeim tévesek, de végül olvastam, hogy ezek az eszközök soronként működnek (a regexeim is annyira triviálisak voltak, hogy nem ez lehet a probléma).

Tehát melyik eszközt használja a minták több soron történő keresésére?

Megjegyzések

  • a többsoros minta egyezésének sed, awk vagy grep használatával
  • @CiroSantilli – Nem hiszem, hogy ez a Q és az, amelyhez linkeltél, duplikátumok. A másik Q azt kérdezi, hogy ‘ hogyan csinálod a többsoros mintát (azaz milyen eszközt kell / lehet? használd erre), miközben ez azt kérdezi, hogyan lehet ezt megtenni a grep kapcsolattal. Ezek szorosan kapcsolódnak egymáshoz, de nem dup, IMO.
  • @sim ezek az esetek nehéz eldönteni: Látom az értelmét.Szerintem ez a konkrét eset jobb, mint egy ismétlődő becau se a felhasználó azt mondta, hogy "grep" azt javasolja a ” igének, hogy ” és a legfelsõbb válaszokat kapja, beleértve az elfogadottakat, ne használja a grep-et.
  • Nincs arra utaló jel, hogy itt többsoros reguláris kifejezésre lenne szükség. Fontolja meg egy tényleges példa bemutatását a bemeneti adatokkal és a várható kimeneti adatokkal, valamint a korábbi erőfeszítéseivel.

Válasz

Itt “sa sed olyan, amely grep -szerű viselkedést kölcsönöz több vonalon:

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

Hogyan működik

  • -n elnyomja az összes sor nyomtatásának alapértelmezett viselkedését.
  • /foo/{} utasítja, hogy illeszkedjen a foo, és tedd meg azt, ami a mocorgásokban található az egyező sorokhoz. Cserélje le a foo szót a minta kezdő részével.
  • :start egy elágazó címke, amely segít folytatni a hurkolást, amíg meg nem találjuk a regexünk végét.
  • /bar/!{} végrehajtja a mozzanatok mibenlétét azok a sorok, amelyek nem egyeznek bar. Cserélje le az a minta befejező részével.
  • N a következő sort hozzáadja az aktív pufferhez (sed ezt mintatérnek hívja)
  • b start feltétel nélkül elágazik az általunk létrehozott start címkéhez korábban, hogy folyamatosan fűzze a következő sort, mindaddig, amíg a mintaterület nem tartalmaz bar.
  • /your_regex/p kinyomtatja a mintateret, ha az megegyezik a your_regex ponttal. A (z) your_regex szöveget ki kell cserélnie az egész kifejezésre, amelyet több sorban szeretne egyeztetni.

Megjegyzések

  • +1 Ennek hozzáadása az toolikt-hoz! Köszönet.
  • Megjegyzés: MacOS rendszeren ez sed: 1: "/foo/{:start /bar/!{N;b ...": unexpected EOF (pending }'s)
  • sed: unterminated { hibát kap
  • @Nomaed Shot sötétben itt, de előfordul-e, hogy regexe tartalmaz ” {” karaktert? Ha igen, akkor ‘ vissza kell vágnia őket.
  • @Nomaed Úgy tűnik, hogy a a különbségek a sed megvalósítások között. Megpróbáltam követni a válasz ajánlásait, hogy a fenti szkript szabványos legyen, de azt mondta nekem, hogy a ” start ” meghatározatlan címke. Tehát ‘ nem vagyok biztos abban, hogy ezt meg lehet-e tenni a szabványnak megfelelő módon. Ha mégis kezeli, nyugodtan szerkessze a válaszomat.

Válasz

Általában eszközt használok az úgynevezett pcregrep, amely a linux aroma nagy részébe telepíthető a yum vagy apt segítségével.

Például.

Tegyük fel, hogy van testfile nevű fájl tartalommal

abc blah blah blah def blah blah blah 

A következő parancsot futtathatja:

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

a mintaillesztéshez több soron keresztül.

Ezenkívül ugyanezt megteheti a sed esetén is.

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

Megjegyzések

  • ezt a sed javaslatot kihagyja az a sor, ahol a def található

Válasz

Egyszerűen egy normál grep, amely támogatja a Perl-regexp paramétert, a P paramétert fogja megtenni.

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

(?s) DOTALL módosítónak hívják, amely a regexben pontot ad a karaktereknek, de a sortöréseknek is.

megjegyzések

  • Amikor megpróbálom ezt a megoldást, a kimenet nem ér véget ‘ def ‘, de a fájl végére megy ‘ blah ‘
  • talán a grep nem támogatja a -P opciót
  • Ez volt az egyetlen, ami nekem bevált – kipróbált minden sed javaslatot, de nem ment ‘ a grep alternatívák telepítéséig.
  • $ grep --version: grep (GNU grep) 3.1 a Windows Git Bash -ben van egy opció -P, --perl-regexp, de (?s) nem ‘ nem működik ott. Még mindig csak az első sort mutatja. Ugyanaz a minta ugyanazzal a tesztlánccal működik a regex101.com webhelyen. Van-e alternatíva a Git Bash-ben? sed? (sed (GNU sed) 4.8 itt)
  • Tudja, hogyan adhatja hozzá a kontextust a kimenethez? A grep -1 nem működik itt: ‘.

Válasz

Itt egy egyszerűbb megközelítés a Perl használatával:

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

vagy (mivel JosephR a sed útvonal , szégyentelenül ellopom javaslatát )

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

### Magyarázat

$f=join("",<>);: ez elolvassa a teljes fájlt, és elmenti annak tartalmát (új sorokat és minden) a $f. Ezután megpróbáljuk illeszteni a foo\nbar.*\n -t, és kinyomtatjuk, ha egyezik (a $& speciális változó tartalmazza az utoljára talált egyezést). A ///m szükséges ahhoz, hogy a reguláris kifejezés új vonalakon egyezik.

A -0 állítja be a bemeneti rekord elválasztót. Ha ezt 00 értékre állítja, aktiválja a “bekezdés módot”, ahol Perl egymást követő új sorokat (\n\n) fogja használni elválasztóként. Azokban az esetekben, amikor nincsenek egymást követő új sorok, a teljes fájl egyszerre beolvasásra kerül (slurped).

### Figyelmeztetés: Ne tegye ezt ne nagy fájlok esetén, ez betöltődik a teljes fájl a memóriába, és ez problémát jelenthet.

Megjegyzések

  • Nem ‘ t sokat tudna a Perl-ről, de nem lenne ‘ t, hogy szigorúan véve my $f=join("",<>); legyen?
  • Csak @Sapphire_Brick ha szigorú módban van (use strict;). ‘ jó szokás belelendülni, főleg nagyobb szkriptek írásakor, de ‘ túl van egy ilyen kis egyhajósnál. egyet.

Válasz

Tegyük fel, hogy megvan a fájl test.txt tartalmazza:

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

A következő kód használható:

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

A következő kimenethez:

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

Válasz

A grep alternatív szitálás támogatja a többsoros egyezést (felelősség kizárása: én vagyok a szerző).

Tegyük fel, hogy testfile a következőket tartalmazza:

 <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>' (mutassa a a leírás)

Eredmény:

 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 (kivonat és formázza újra a leírást)

Eredmény:

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

Megjegyzések

  • Nagyon jó eszköz. Gratulálunk! Próbálkozzon olyan disztribúciókkal, mint az Ubuntu.

Válasz

Ezt megoldottam a grep és a – használatával Opció másik grep-lel.

grep first_line_word -A 1 testfile | grep second_line_word 

Az -A 1 opció 1 sort nyomtat a megtalált sor után. Természetesen ez a fájljától és a szóösszetételtől függ. De számomra ez volt a leggyorsabb és legmegbízhatóbb megoldás.

Megjegyzések

  • alias grepp = ‘ grep –color = auto -B10 -A20 -i ‘, majd macskázzon | grepp blah | grepp foo | grepp bár … igen azok -A és -B nagyon praktikusak …neked van a legjobb válaszod
  • Ez nem ‘ nem szuper determinisztikus, és figyelmen kívül hagyja a teljes mintát annak érdekében, hogy csak egy másik sort kapj (csak annak közelsége alapján) az első sorig). ‘ jobb, ha azt mondjuk a programnak, hogy menjen bármennyire is, hogy menjen ahhoz, hogy valamilyen mintához jusson ‘ teljesen biztos, hogy vége annak a szövegnek, amelyet ‘ megpróbál egyeztetni. Például, ha a testfile úgy frissül, hogy a second_line_word a harmadik sorban van, akkor nemcsak az első sor hiányzik ( a második grep), de ‘ nem hiányzik az a sor, amely a kettő között elkezdett megjelenni.
  • Ez elég jó MO ad hoc parancsokhoz, ahol valóban csak egy sort akarsz a kimenetben, amit már értettél. Nem gondolom, hogy ‘ nem gondolom, hogy ‘ mi az, amit az OP követ, és valószínűleg ezen a ponton is egyszerűen másolhat / beilleszthet eseti jellegű.

Válasz

Ennek egyik módja a Perl. például. itt van egy foo nevű fájl tartalma:

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

Most itt van néhány Perl, amely meccs minden olyan sorral szemben, amely foo-val kezdődik, majd bárkivel kezdődő sor:

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

A Perl, lebontva:

  • while(<>){$all .= $_} Ez a teljes standard bemenetet a $all
  • Míg a all változó a reguláris kifejezéssel rendelkezik …
  • /^(foo[^\n]*\nbar[^\n]*\n)/m A regex: foo a sor elején, amelyet tetszőleges számú nem új vonalas karakter követ, majd egy új sor, majd azonnal a “bár”, majd a sor többi része bárral. A regex végén szereplő /m jelentése: “több soron egyezik”
  • print $1 A regex részének kinyomtatása ez zárójelben volt (ebben az esetben a teljes reguláris kifejezés)
  • s/^(foo[^\n]*\nbar[^\n]*\n)//m Törölje az első egyezést a regex számára, így a regex több esetét is egyeztethetjük a kérdéses fájlban

És a kimenet:

foo line 1 bar line 2 foo bar line 6 

megjegyzések

  • Csak beugrott, hogy azt mondhassa, a Perl-je lerövidülhet az idiomatikusabbra: perl -n0777E 'say $& while /^foo.*\nbar.*\n/mg' foo

Válasz

Ha meg akarjuk kapni a szöveget a két minta között, kivéve önmagukat.

Töltsük fel a test.txt tartalmazza:

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

A következő kód használható:

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

A következő kimenethez:

here is the text to keep between the 2 patterns 

Hogyan működik, hadd “s” lépésről lépésre készítsen

  1. /foo/{ akkor jelenik meg, amikor a sor “foo” -ot tartalmaz
  2. n cserélje ki a mintateret a következő sorra, vagyis az “itt” szó
  3. b gotoloop elágazást a “gotoloop” címkére
  4. :gotoloop meghatározza a “gotoloop” címkét
  5. /bar/!{, ha a minta nem tartalmaz “sávot”
  6. h cserélje ki a tartási helyet mintával, így az “itt” a tárolt térbe kerül mentésre
  7. b loop elágazás a “hurok” címkéhez
  8. :loop meghatározza a “hurok” címkét
  9. N hozzáfűzi a mintát a tartási térhez.
    Most a szóköz tartalmaz:
    “itt”
    “a”
  10. :gotoloop Most a 4. lépésnél tartunk, és addig folytatjuk a ciklust, amíg egy sorban a “bár” van.
  11. /bar/ ciklus elkészül, a “sáv” megtalálható, ez ” s a mintateret
  12. mintaterület helyére egy tartási szóköz tartozik, amely tartalmazza az összes sort a” foo “és a” bar “között, amelyeket a fő hurok mentett.
  13. p mintaterület másolása normál kimenetre

Kész!

Megjegyzések

  • Jól sikerült, +1. Általában kerülöm ezeket a parancsokat, ha tr ‘ beillesztem az új sorokat SOH-ba, és normál sed parancsokat hajtok végre, majd kicserélem az új sorokat.

Vélemény, hozzászólás?

Az email címet nem tesszük közzé. A kötelező mezőket * karakterrel jelöltük