Folosind sed pentru a găsi și înlocui șiruri complexe (preferabil cu regex)

Am un fișier cu următorul conținut:

și trebuie să creez un script care schimbă„ numele ”din prima linie în„ ceva ”,„ parola ”din a doua linie în„ ceva diferit ”și„ numele ”din a treia linie către „ceva diferit”. Nu mă pot baza pe ordinea acestora care apar în fișier, așa că nu pot înlocui pur și simplu prima apariție a „nume” cu „ceva” și a doua apariție „nume” cu „ceva diferit”. De fapt, trebuie să fac o căutare a șirurilor din jur, pentru a mă asigura că găsesc și înlocuiesc ceea ce este corect.

Până acum am încercat această comandă pentru a găsi și a înlocui prima apariție „nume”:

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

totuși nu funcționează, așa că cred că unele dintre aceste personaje ar putea avea nevoie să scape etc.

În mod ideal, eu ” Îmi place să pot folosi regex pentru a potrivi doar cele două apariții „nume de utilizator” și a înlocui doar „numele”. Ceva de genul acesta, dar cu sed:

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

și înlocuiți conținutul dintre paranteze cu „ceva”.

Este posibil?

Comentarii

  • Rețineți că aproape orice soluție bazată pe regexp, cu excepția cazului în care este extrem de inventată, va risca întreruperea oricând se modifică formatul de intrare. Regexps sunt o alegere slabă pentru tratarea XML, SGML sau derivate (ceea ce mi se pare).
  • Aprobat! Luați în considerare utilizarea XQuery, de exemplu: w3schools.com/xquery/default.asp . Acesta este standardul W3C pentru recuperarea și manipularea conținutului XML.

Răspuns

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

Acesta este, cred, ceea ce căutați.

Explicație:

  • parantezele din prima parte definesc grupuri (șiruri de fapt) care pot fi refolosite în a doua parte
  • \1, \2 etc. în a doua parte sunt referințe la Primul grup capturat în prima parte (numerotarea începe cu 1)
  • -E activează expresii regulate extinse (necesare pentru + și grupare).

Comentarii

  • +1 pentru opțiunea -E
  • it lasă în urmă un fișier de rezervă, cu numele (original name) + "-E".
  • Pe OSX primesc ‘ sed: 1: ” s / (< nume de utilizator >. +) nume (. + … „: \ 1 nu definit în RE ‘. Am lipit exemplul exact din această întrebare într-un fișier. apoi am executat comanda din acest răspuns pe acel fișier. Poate că OSX are o sintaxă diferită?
  • Versiunea gnu a sed acceptă parametrul ” -E „, dar nu oficial. ‘ nici măcar nu este menționat în pagina de manual. Dacă doriți să utilizați regexul extins, trebuie să utilizați parametrul ” -r „.
  • @ deweydb Conform acest răspuns , ar trebui să utilizați \( și \) în loc de ( și ).

Răspuns

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/ înainte de s spune sed să funcționeze numai pe liniile care conțin șirul „nume de utilizator”.

Comentarii

  • Elegant, eficient și perfect potrivit pentru carcasă. +1

Răspuns

Dacă sed nu este greu cerință, folosiți mai bine un instrument dedicat.

Dacă fișierul dvs. este XML valid (nu doar acele 3 etichete cu aspect XML), puteți utiliza XMLStarlet :

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

Cele de mai sus vor funcționa și în situații care ar fi greu de rezolvat cu expresii regulate:

  • Poate înlocui valorile etichetelor fără a specifica valorile actuale ale acestora.
  • Poate înlocui valorile chiar dacă sunt doar evadate și nu sunt incluse în CDATA.
  • Poate înlocui valorile chiar dacă etichetele au atribute.
  • Poate înlocui cu ușurință doar aparițiile etichetelor, dacă există mai multe cu același nume.
  • Poate formata XML modificat prin indentare.

Scurtă demonstrație a celor de mai sus:

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> 

Răspuns

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

Puteți utiliza pur și simplu adrese a s în numărul care precedă „s” care indică numărul liniei.

De asemenea, numărul din final îi spune sed să înlocuiască a doua potrivire în loc să o înlocuiască pe prima. Meci.

Răspuns

Trebuie să citați \[.*^$/ în partea de expresie regulată a s comandă și \&/ în partea de înlocuire, plus linii noi. Expresia regulată este o expresie regulată de bază și, în plus, trebuie să citați delimitatorul pentru comanda s.

Puteți alege un alt delimitator pentru a evita să citați /. În schimb, va trebui să citați acel caracter, dar de obicei scopul schimbării delimitatorului este să alegeți unul care nu apare fie în textul de înlocuit, fie în textul de înlocuire.

Puteți utiliza grupuri pentru a evita repetarea unor părți din textul de înlocuire și pentru a adapta variațiile acestor părți.

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

Răspuns

Pentru a înlocui cuvântul „nume” cu cuvântul „ceva”, utilizați:

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

Asta va înlocui toate aparițiile cuvântului specificat.

Până în prezent totul este trimis la ieșirea standard, puteți utiliza:

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

pentru a salva modificările într-un alt fișier.

Răspunde

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

deci pentru a înlocui valoarea într-un fișier de proprietăți

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

Lasă un răspuns

Adresa ta de email nu va fi publicată. Câmpurile obligatorii sunt marcate cu *