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
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ä vastaamaanfoo
ja tee se, mikä on ristiriitojen sisällä vastaaville viivoille. Korvaafoo
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 vastaabar
. Korvaa mallin loppuosalla. -
N
liittää seuraavan rivin aktiiviseen puskuriin (sed
kutsuu tätä malliavaruudeksi) -
b start
haarautuu ehdoitta luomaammestart
-tunnisteeseen aikaisemmin niin, että seuraava rivi jatkuu niin kauan kuin kuviotila ei sisälläbar
. -
/your_regex/p
tulostaa kuviotilan, jos se vastaayour_regex
. Sinun tulisi korvatayour_regex
koko lausekkeella, jonka haluat yhdistää usealle riville.
Kommentit
- +1 Tämän lisääminen tooliktiin! Kiitos.
- Huomaa: MacOS: ssa tämä antaa
sed: 1: "/foo/{:start /bar/!{N;b ...": unexpected EOF (pending }'s)
-
sed: unterminated {
-virheen - @Nomaed Shot tässä pimeässä, mutta sisältääkö regexi ” {” merkkejä? Jos näin on, ’ sinun on poistettava heiltä vinoviiva.
- @Nomaed Vaikuttaa siltä, että se liittyy erot
sed
-toteutusten välillä. Yritin noudattaa kyseisen vastauksen suosituksia saadaksesi yllä olevan komentosarjan standardien mukaiseksi, mutta se kertoi minulle, että ” start ” oli määrittelemätön etiketti. Joten en ’ ole varma, voidaanko tämä tehdä standardien mukaisella tavalla. Jos hallitset sitä, muokkaa vastaustani vapaasti.
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, jostadef
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.8
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 toinengrep
), 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 muuttujallaall
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
-
/foo/{
laukaistaan, kun rivi sisältää merkin ”foo” -
n
korvaa kuviotila seuraavalla rivillä, eli sana ”täällä” -
b gotoloop
haara tunnisteeseen ”gotoloop” -
:gotoloop
määrittelee tunnisteen ”gotoloop” -
/bar/!{
, jos kuvio ei sisällä palkkia -
h
korvaa pitotila kuviolla, joten ”täällä” tallennetaan pitotilaan -
b loop
haara tunnisteeseen ”silmukka” -
:loop
määrittelee tunnisteen ”silmukka” -
N
liittää kuvion pitotilaan.
Nyt pitotila sisältää:
”tässä”
”on” -
:gotoloop
Olemme nyt vaiheessa 4 ja jatka, kunnes rivi sisältää ”palkin” -
/bar/
-silmukka on valmis, ”palkki” on löydetty, se ” s kuviotila - kuviotila korvataan pitotilalla, joka sisältää kaikki pääpiirin aikana tallentuneet rivit” foo ”ja” bar ”välillä
-
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.
grep
-palvelun kanssa. Ne ovat tiiviisti yhteydessä, mutta eivät duppeihin, IMO."grep"
ehdottaa verbiä ” grep ” ja suosituimmat vastaukset, mukaan lukien hyväksytty, älä ’ käytä grep-tiedostoa.