Sedin käyttäminen monimutkaisen merkkijonon etsimiseen ja korvaamiseen (mieluiten regexillä)

Minulla on tiedosto, jonka sisältö on seuraava:

<username><![CDATA[name]]></username> <password><![CDATA[password]]></password> <dbname><![CDATA[name]]></dbname> 

ja minun täytyy tehdä komentosarja, joka muuttaa ensimmäisen rivin” nimen ”” jotain ”,” toisen salasanan ”” jotain muuta ”ja” nimen ” kolmas rivi ”jotain erilaista”. En voi ”luottaa tiedostossa esiintyvien näiden järjestykseen, joten en voi” yksinkertaisesti korvata ”nimen” ensimmäistä esiintymistä ”jollakin” ja toista ”nimen” esiintymistä ”jotain erilaisella”. Minun on todella etsittävä ympäröiviä merkkijonoja varmistaakseni, että löydän oikean asian ja korvaan sen.

Olen toistaiseksi kokeillut tätä komentoa etsimään ja korvaamaan ensimmäinen ”nimi” esiintymä:

sed -i "s/<username><![CDATA[name]]><\/username>/something/g" file.xml 

se ei kuitenkaan toimi, joten ajattelen, että jotkut näistä hahmoista saattavat tarvita pakenemista jne.

Ihannetapauksessa minä ” Rakastan pystyä käyttämään regexiä vastaamaan vain kahta ”käyttäjänimi” esiintymää ja korvaamaan vain ”nimi”. Jotain tältä, mutta sed:

<username>.+?(name).+?</username> 

ja korvaa sulkeiden sisältö ”jollakin”.

Onko tämä mahdollista?

Kommentit

  • Huomaa, että melkein mikä tahansa regexp-pohjainen ratkaisu, ellei se ole äärimmäisen keksitty, voi vaarantaa rikkomatta milloin tahansa syötemuoto muuttuu. Regexps ovat huono valinta käsitellessäsi XML: ää, SGML: ää tai johdannaisia (mikä näyttää minulta).
  • Hyväksytty! Harkitse esimerkiksi XQueryn käyttöä: w3schools.com/xquery/default.asp . Tämä on W3C-standardi XML-sisällön hakemiseen ja käsittelyyn.

Vastaa

sed -i -E "s/(<username>.+)name(.+<\/username>)/\1something\2/" file.xml 

Tätä luulen etsimäsi.

Selitys:

  • ensimmäisen osan suluissa määritetään ryhmät (itse asiassa merkkijonot) voidaan käyttää uudelleen toisessa osassa
  • \1, \2 jne. toisessa osassa viitataan Ensimmäisen osan siepattu i-ryhmä (numerointi alkaa numerolla 1)
  • -E mahdollistaa laajennetut säännölliset lausekkeet (tarvitaan + ja ryhmittely).

Kommentit

  • + 1 -E-vaihtoehdolle
  • se jättää taaksepäin varmuuskopiotiedoston, jonka nimi on (original name) + "-E".
  • OSX: ssä saan ’ sed: 1: ” s / (< käyttäjänimi >. +) nimi (. + … ”: \ 1 ei määritelty RE ’. Liitin tämän kysymyksen tarkan esimerkin tiedostoon. sitten suoritin komennon tästä vastauksesta kyseisessä tiedostossa. Ehkä OSX: llä on erilainen syntakse?
  • Sedin gnu-versio tukee ” -E ” -parametria, mutta ei virallinen. Sitä ’ ei edes mainita sivulla. Jos haluat käyttää laajennettua lauseketta, sinun on käytettävä sen sijaan parametria ” -r ”.
  • @ deweydb tämän vastauksen mukaan sinun tulee käyttää \( ja \) ( ja ) sijaan.

Vastaa

sed -e "/username/s/CDATA\[name\]/CDATA\[something\]/" \ -e "/password/s/CDATA\[password\]/CDATA\[somethingelse\]/" \ -e "/dbname/s/CDATA\[name\]/CDATA\[somethingdifferent\]/" file.txt 

/username/ ennen s kertoo sed työskennellä vain rivillä, jotka sisältävät merkkijonon ”käyttäjänimi”.

Kommentit

  • Tyylikäs, tehokas ja täydellisesti sovitettu koteloon. +1

Vastaa

Jos sed ei ole vaikea vaatimus, käytä sen sijaan omistettua työkalua.

Jos tiedostosi on kelvollinen XML (ei vain ne 3 XML: n näköistä tagia), voit käyttää XMLStarlet :

xml ed -P -O -L \ -u "//username/text()" -v "something" \ -u "//password/text()" -v "somethingelse" \ -u "//dbname/text()" -v "somethingdifferent" file.xml 

Edellä mainittu toimii myös tilanteissa, jotka olisi vaikea ratkaista säännöllisten lausekkeiden avulla:

  • Voi korvata tunnisteiden arvot määrittämättä niiden nykyisiä arvoja.
  • Voi korvata arvot, vaikka ne olisi vain pakotettu eikä niitä ole CDATA: n sisällä.
  • Voi korvata arvot, vaikka tunnisteilla on määritteitä.
  • Voi helposti korvata vain tunnisteiden esiintymät, jos samannimisiä on useita.
  • Voi muotoilla muokatun XML: n sisennyttämällä sen.

Lyhyt osoitus yllä mainituista:

bash-4.2$ cat file.xml <sith> <master> <username><![CDATA[name]]></username> </master> <apprentice> <username><![CDATA[name]]></username> <password>password</password> <dbname foo="bar"><![CDATA[name]]></dbname> </apprentice> </sith> bash-4.2$ xml ed -O -u "//apprentice/username/text()" -v "something" -u "//password/text()" -v "somethingelse" -u "//dbname/text()" -v "somethingdifferent" file.xml <sith> <master> <username><![CDATA[name]]></username> </master> <apprentice> <username><![CDATA[something]]></username> <password>somethingelse</password> <dbname foo="bar"><![CDATA[somethingdifferent]]></dbname> </apprentice> </sith> 

vastaus

$ sed -e "1s/name/something/2" \ -e "3s/name/somethingdifferent/2" \ -e "s/password/somethingelse/2" sample.xml 

Voit käyttää yksinkertaisesti osoitteita a ”s” -merkkiä edeltävässä numerossa, joka osoittaa rivinumeron.

Myös lopussa oleva numero kertoo sed korvata toisen vastaavuuden ensimmäisen sijasta. ottelu.

vastaus

Sinun on lainattava \[.*^$/ s -komento ja \&/ korvaavassa osassa plus uudet rivit. Säännöllinen lauseke on säännöllinen peruslauseke , ja lisäksi sinun on lainattava s -komennon erotin.

Voit valita toisen erottimen, jotta sinun ei tarvitse lainata /. Sinun on lainattava kyseinen merkki sen sijaan, mutta yleensä erottimen vaihtamisen tarkoituksena on valita sellainen, jota ei esiinny korvattavassa tai korvaavassa tekstissä.

sed -e "s~<username><!\[CDATA\[name\]\]></username>~<username><![CDATA[something]]></username>~" 

Voit käyttää ryhmiä välttääksesi joidenkin osien toistamista korvaavassa tekstissä ja sovittaa muunnelmat näihin osiin.

sed -e "s~\(<username><!\[[A-Z]*\[\)name\(\]\]></username>\)~\1something\2~" sed -e "s~\(<username>.*[^A-Za-z]\[\)name\([^A-Za-z].*</username>\)~\1something\2~" 

Vastaa

Jos haluat korvata sanan ”nimi” sanalla ”jotain”, käytä:

sed "s/\(<username><\!\[[A-Z]*\[\)name\]/\1something/g" file.xml 

Se korvaa kaikki määritetyn sanan esiintymät.

Toistaiseksi kaikki on annettu vakiolähdöksi, voit käyttää:

sed "s/\(<username><\!\[[A-Z]*\[\)name\]/\1something/g" file.xml > anotherfile.xml 

tallentaa muutokset toiseen tiedostoon.

Vastaa

Usage: sed [OPTION]... {script-only-if-no-other-script} [input-file]... -r, --regexp-extended use extended regular expressions in the script. 

joten korvaa ominaisuustiedoston arvo

sed -i -r "s/MAIL\=(.+)/MAIL\[email protected]/" etc/service.properties 

Vastaa

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