Ú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
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 afoo
, és tedd meg azt, ami a mocorgásokban található az egyező sorokhoz. Cserélje le afoo
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 egyeznekbar
. 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étrehozottstart
címkéhez korábban, hogy folyamatosan fűzze a következő sort, mindaddig, amíg a mintaterület nem tartalmazbar
. -
/your_regex/p
kinyomtatja a mintateret, ha az megegyezik ayour_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 adef
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 asecond_line_word
a harmadik sorban van, akkor nemcsak az első sor hiányzik ( a másodikgrep
), 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
-
/foo/{
akkor jelenik meg, amikor a sor “foo” -ot tartalmaz -
n
cserélje ki a mintateret a következő sorra, vagyis az “itt” szó -
b gotoloop
elágazást a “gotoloop” címkére -
:gotoloop
meghatározza a “gotoloop” címkét -
/bar/!{
, ha a minta nem tartalmaz “sávot” -
h
cserélje ki a tartási helyet mintával, így az “itt” a tárolt térbe kerül mentésre -
b loop
elágazás a “hurok” címkéhez -
:loop
meghatározza a “hurok” címkét -
N
hozzáfűzi a mintát a tartási térhez.
Most a szóköz tartalmaz:
“itt”
“a” -
:gotoloop
Most a 4. lépésnél tartunk, és addig folytatjuk a ciklust, amíg egy sorban a “bár” van. -
/bar/
ciklus elkészül, a “sáv” megtalálható, ez ” s a mintateret - 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.
-
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.
grep
kapcsolattal. Ezek szorosan kapcsolódnak egymáshoz, de nem dup, IMO."grep"
azt javasolja a ” igének, hogy ” és a legfelsõbb válaszokat kapja, beleértve az elfogadottakat, ne használja a grep-et.