Sed: comment replace le symbole nextline \ n dans les files text?

Je dois corriger une erreur et replace la deuxième balise </time> par </tags> dans un file XML avec la structure suivante:

 <time>20260664</time> <tags>substancesummit ss</time> <geo>asdsadsa</geo> <time>20260664</time> <tags>substancesummit ss</time> <geo>asdsadsa</geo> 

J'essaie de le faire en utilisant sed et depuis que j'ai 2 </time> fermeture de balise par item, mon idée est de replace </time><geo> par </tags><geo> .

Cependant, il y a un symbole de ligne suivante entre les deux, donc j'utilise \n mais ça ne marche pas:

 sed 's/time>\n<geo>/tags>\n<geo>/g' old.xml > new.xml 

De l'aide?

Sed traite son input ligne par ligne, de sorte qu'un caractère de nouvelle ligne n'apparaîtra jamais spontanément dans l'input. Ce que vous pourriez faire est de mettre des lignes se terminant par </time on hold; alors si la ligne suivante commence par <geo> , faites la substitution dans la ligne précédente. (Ceci est possible dans sed, en utilisant le "hold space", mais je recommand de tourner awk ou perl quand vous avez besoin de l'espace de cale.)

Cependant, count tenu de votre input d'échantillon, vous pouvez simplement changer </time> en </tags> lorsque la ligne commence par <tags> .

 sed -e '/^<tags>/ s!</time>$!</tags>!' 

Bien que la solution à votre problème puisse être facilement obtenue par d'autres moyens, la réponse à votre question est simple. sed , par défaut, travaille une ligne à la fois sur 2 buffers – un cycle persistant sur plusieurs lignes appelé l'ancien espace et un cycle rafraîchi au less une fois par cycle appelé l'espace du motif – et le dernier est l'endroit où toutes les modifications sont effectuées.

Regarder de l'avant peut être obtenu de deux façons: vous pouvez sauvegarder les anciennes lignes et suivre le cycle de ligne afin de mieux utiliser les commands pour échanger et comparer les tampons. Cela implique des primitives de command telles que [hH] old, [gG] et e x change – qui sauvegardent, copynt et échangent respectivement le buffer hold – et les forms minuscules écrasent et majuscules ajoutent à leur buffer cible.

Ou vous pouvez travailler les lignes futures dans un algorithm d'édition constante dans lequel vous supprimez systématiquement autant de lignes d'input que vous lisez par cycle. Ce dernier serait ma preference ici – surtout parce que sed rend si facile et efficace – en particulier avec les commands N;P;D

Voici une démo utilisant vos données d'exemple:

 sed '$!N;s/ime\(>\n<geo\)/ags\1/;P;D ' <<\IN <time>20260664</time> <tags>substancesummit ss</time> <geo>asdsadsa</geo> <time>20260664</time> <tags>substancesummit ss</time> <geo>asdsadsa</geo> IN 

N ext, P rint et D elete, comme leurs équivalents minuscules n;p;d obtiennent respectivement la ligne suivante d'input, d'printing et de suppression dans / de l'espace de motif. Contrairement à leurs homologues en minuscules (si un peu less différent dans le cas de N ) , ces trois travaux sur les limites de nouvelles lignes plutôt que l'espace de motif dans son set.

  • N appenda la prochaine ligne d'input à l'espace des motifs suivant un caractère \n ewline.
  • P n'imprimera que le premier caractère de la première occurrence dans l'espace des motifs.
  • D ne supprime que le premier \n ewline existant dans l'espace des patterns avant de quitter le script pour le cycle en cours et en queue le suivant avec tout ce qui rest dans l'espace des motifs ou, si rien ne rest après son action de suppression, ligne en attente sur input comme d'habitude.

Ces trois peuvent travailler set pour étendre la window d'édition de sed sur un file de manière très simple et efficace – sed glisse dans une file d'printing par cycle seulement le plus ancien d'une série de lignes qu'il supprime et reconstitue constamment selon les instructions d'un scripteur – sed der en charge du cycle de la ligne.

Et une prochaine ligne lookahead est facilement élargie. Si vous vouliez une window d'espace de motif de 4 lignes tout au long du script, vous pourriez faire:

 sed -e '1{N;N' -e '};N;...;P;D' 

… ou, peut-être plus utile …

 sed -e ':next $!{/\(.*\n\)\{3\}/!{ N;b next' -e '} };...cmds...;P;D' 

… dans lequel sed ne dessine qu'une ligne d'input – et continue à le faire jusqu'à ce qu'il en ait assez avant d'exécuter d'autres commands – s'il y a less de trois \n caractères d'ewline dans l'espace du motif et que la ligne courante n'est pas la dernière. Cela se produit quelles que soient les modifications effectuées par les commands suivantes.

Pour littéraire répondre à la question:

Je résous ce problème (le text à éditer s'étend sur plusieurs lignes) par un petit truc:

 cat input.txt | tr '\n' '@' | sed -e 's/txt@iam@interestdin/iaminterestd@intxt/g' | tr '@' '\n' > output.txt 

La seule chose dont vous devez être sûr est que le personnage avec lequel vous remplacez la nouvelle ligne n'existe pas encore dans votre saisie.