J'ai remarqué que, si j'ajoute \n
un motif de substitution à l'aide de sed
, il ne correspond pas. Exemple:
$ cat > alpha.txt
This is
a test
Please do not
be alarmed
$ sed -i'.original' 's/a test\nPlease do not/not a test\nBe/' alpha.txt
$ diff alpha.txt{,.original}
$ # No differences printed out
Comment puis-je le faire fonctionner?
sed
regular-expression
utilities
Belmin Fernandez
la source
la source
Réponses:
Dans l'appel le plus simple de sed , il y a une ligne de texte dans l'espace modèle, c'est-à-dire. 1 ligne de
\n
texte délimité de l'entrée. La seule ligne dans l'espace des motifs n'a pas\n
... C'est pourquoi votre expression rationnelle ne trouve rien.Vous pouvez lire plusieurs lignes dans l'espace des motifs et manipuler les choses étonnamment bien, mais avec un effort supérieur à la normale. Sed dispose d'un ensemble de commandes permettant ce type de choses ... Voici un lien vers un résumé des commandes pour sed . C'est le meilleur que j'ai trouvé, et m'a fait rouler.
Cependant, oubliez l'idée "one-liner" une fois que vous commencez à utiliser les micro-commandes de sed. Il est utile de le présenter comme un programme structuré jusqu'à ce que vous en ressentiez la sensation ... C'est étonnamment simple et tout aussi inhabituel. Vous pourriez le considérer comme le "langage assembleur" de l'édition de texte.
Résumé: Utilisez sed pour des choses simples, et peut-être un peu plus, mais en général, quand on dépasse le travail avec une seule ligne, la plupart des gens préfèrent autre chose ...
Je laisserai quelqu'un d'autre suggérer quelque chose d'autre .. Je suis Je ne sais vraiment pas quel serait le meilleur choix (j'utiliserais sed, mais c'est parce que je ne connais pas assez bien le langage Perl.)
Ici, c’est le même scénario, condensé dans ce qui est évidemment plus difficile à lire et à utiliser, mais certains appelleraient sans aucun doute un one-liner
Voici ma commande "aide-mémoire"
la source
t
commande ici. Lorsqu'elle ne reçoit pas d'étiquette, elle se branche par défaut sur la fin du script. Ainsised '/^a test$/{$!{N;s/^a test\nPlease do not$/not a test\nBe/;t;P;D}}' alpha.txt
fait exactement la même chose que votre commande en toutes circonstances. Bien sûr, pour ce fichier particulier ,sed '/test/{N;s/.*/not a test\nBe/}' alpha.txt
fait la même chose, mais mon premier exemple est logiquement équivalent pour tous les fichiers possibles. Notez également que\n
dans une chaîne de remplacement ne produit pas de nouvelle ligne; pour ce faire, vous avez besoin d’une barre oblique inverse `\` suivie par une nouvelle ligne.#
commande non séparée de la précédente,\n
dans RHS ofs
). Avec GNU,sed
vous pouvez également utiliser des-z
enregistrements délimités par NUL (puis lisser toute l'entrée si c'est du texte (qui par définition ne contient pas de NUL)).Utilisez
perl
au lieu desed
:-pi -e
est votre séquence de ligne de commande standard "remplacer à la place" et -0777 fait en sorte que perl sculpte les fichiers en entier. Voir perldoc perlrun pour en savoir plus.la source
sed
et que les réponses utilisant awk ou perl apparaissent. Je pense que ce n'est pas sur le sujet, donc, désolé, mais j'ai tiré un moins.sed
réponse ci-dessus prouve qu'une réponse Perl est sur le sujet.Je pense qu'il est préférable de remplacer le
\n
symbole par un autre symbole, puis de continuer comme d'habitude:Exemple: code source non travaillé:
peut être changé en:
Si quelqu'un ne le sait pas, la
\n
ligne UNIX se termine-t\r\n
-elle sous Windows, sous\r
Mac OS classique. Le texte UNIX normal n'utilise pas de\r
symbole, vous pouvez donc l'utiliser en toute sécurité.Vous pouvez également utiliser un symbole exotique pour remplacer temporairement \ n. À titre d'exemple - \ f (symbole d'alimentation de formulaire). Vous pouvez trouver plus de symboles ici .
la source
\r
l'argumentsed
avec$(printf '\r')
.$
avant la chaîne sed pour l’empêcher de le convertir\r
en unr
. Court exemple:sed $'s/\r/~/'
. Exemple complet:cat alpha.txt | tr '\n' '\r' | sed $'s/a test\rPlease do not/not a test\rBe/' | tr '\r' '\n'
Tout bien considéré, engloutir le fichier entier peut être le moyen le plus rapide.
La syntaxe de base est la suivante:
Attention, engloutir le fichier entier peut ne pas être une option si le fichier est extrêmement volumineux. Dans de tels cas, les autres réponses fournies ici proposent des solutions personnalisées dont l’efficacité est garantie pour un faible encombrement de la mémoire.
Pour toutes les autres situations de hack et de slash, le fait d’ajouter des préfixes,
-e '1h;2,$H;$!d;g'
suivi de votresed
argument regex original, permet de faire le travail.par exemple
Que fait
-e '1h;2,$H;$!d;g'
-il?Le
1
,2,$
, les$!
parties sont en ligne spécificateurs qui limite les lignes de la commande suivante directement exécuté.1
: Première ligne seulement2,$
: Toutes les lignes à partir de la seconde$!
: Chaque ligne autre que dernièreTellement développé, c’est ce qui se passe sur chaque ligne d’une entrée de N ligne.
La
g
commande n'est pas donné une spécificateur de ligne, mais la précédented
commande a une clause spéciale « Début du prochain cycle. », Et cela empêcheg
de fonctionner sur toutes les lignes sauf la dernière.Quant à la signification de chaque commande:
h
suivi deH
s sur chaque ligne copie lesdites lignes d'entrée danssed
l' espace d'attente de . (Pensez à un tampon de texte arbitraire.)d
élimine chaque ligne pour empêcher l’écriture de ces lignes dans la sortie. L' espace d'attente est toutefois préservé.g
restaure l’accumulation de chaque ligne de l’ espace de réservation de manière àsed
pouvoir exécuter sa regex sur l’entrée entière (plutôt que ligne à la fois), et par conséquent correspondre à\n
s.la source
sed
a trois commandes pour gérer les opérations à plusieurs lignes:N
,D
etP
(les comparer à la normalen
,d
etp
).Dans ce cas, vous pouvez faire correspondre la première ligne de votre modèle, utilisez
N
pour ajouter la deuxième ligne à l' espace de modèle , puis utilisezs
pour effectuer votre substitution.Quelque chose comme:
la source
G
,H
,x
...). Vous pouvez également ajouter d'autres lignes dans l'espace de modèle à l'aide de las
commande.N
commandesVous pouvez mais c'est difficile . Je recommande de passer à un autre outil. S'il existe une expression régulière qui ne correspond jamais à aucune partie du texte que vous souhaitez remplacer, vous pouvez l'utiliser comme séparateur d'enregistrement awk dans GNU awk.
S'il n'y a jamais deux retours à la ligne consécutifs dans votre chaîne de recherche, vous pouvez utiliser le "mode paragraphe" de awk (une ou plusieurs lignes vides séparent les enregistrements).
Une solution simple consiste à utiliser Perl et à charger le fichier intégralement en mémoire.
la source
perl -0777 -pe '…' <input-file >output-file
. Pour modifier un fichier en place,perl -0777 -i -pe '…' filename
sed
de l'-z
option (ajoutée en 2012 après cette réponse a été publiée):seq 10 | sed -z 's/4\n5/a\nb/'
.Je pense que ceci est la solution sed pour 2 lignes correspondantes.
Si vous voulez 3 lignes correspondant alors ...
Si vous voulez 4 lignes correspondant alors ...
Si la pièce de remplacement dans la commande "s" réduit les lignes, un peu plus compliqué comme celui-ci
Si la partie repacement fait croître les lignes, alors un peu plus compliqué comme ça
la source
Ici
/a test/,/Please do not/
est considéré comme un bloc de texte (multi-lignes),c
la commande de changement suivie par un nouveau textenot a test \nBe
Dans le cas où le texte à remplacer est très long, je suggérerais une syntaxe ex .
la source
Élargissez un peu votre fenêtre d'entrée.
C'est assez facile. Outre la substitution standard; vous avez besoin seulement
$!N
,P
etD
ici.la source
Outre Perl, une approche générale et pratique pour l'édition multiligne des flux (et des fichiers) est la suivante:
Commencez par créer un nouveau séparateur de ligne UNIQUE à votre guise, par exemple
Ensuite, dans votre commande sed (ou tout autre outil), vous remplacez \ n par $ {S}, comme
(awk remplace le séparateur de lignes ASCII par le vôtre et inversement.)
la source
Voici une petite modification de la réponse intelligente de xara pour que cela fonctionne sous OS X (j'utilise la version 10.10):
Au lieu d'utiliser explicitement
\r
, vous devez utiliser$(printf '\r')
.la source
printf '\r'
(ouecho -e '\r'
) fonctionne correctement, veuillez noter que vous pouvez simplement utiliser la syntaxe du shell$'\r'
pour faire référence aux littéraux échappés. Par exemple,echo hi$'\n'there
fera écho une nouvelle ligne entrehi
etthere
. De même, vous pouvez envelopper la chaîne entière de sorte que chaque barre oblique inverse\
échappe à son caractère suivant:echo $'hi\nthere'
Je voulais ajouter quelques lignes de HTML à un fichier en utilisant sed, (et je l'ai fini ici). Normalement, je n'utilisais que du perl, mais j'étais sur une boîte qui avait sed, bash et pas grand chose d'autre. J'ai découvert que si je modifiais la chaîne en une seule ligne et laissais bash / sed interpoler le \ t \ n, tout se passait bien:
Il serait plus propre d’avoir une fonction permettant d’échapper aux guillemets et aux barres obliques, mais parfois l’abstraction est le voleur de temps.
la source
GNU
sed
a une-z
option qui permet d’utiliser la syntaxe que l’OP a tenté d’appliquer. ( page de manuel )Exemple:
Sachez que si vous utilisez
^
et$
qu’ils correspondent maintenant au début et à la fin des lignes délimitées par un caractère NUL (non\n
). Et, pour vous assurer que les correspondances de toutes vos\n
lignes ( séparées) sont remplacées, n'oubliez pas d'utiliser leg
drapeau pour les substitutions globales (par exemples/.../.../g
).Crédits: @ stéphane-chazelas a mentionné pour la première fois -z dans un commentaire ci-dessus.
la source
Sed interrompt les entrées sur les nouvelles lignes. Il ne conserve qu'une ligne par boucle.
Par conséquent, il n'y a aucun moyen de faire correspondre une
\n
(nouvelle ligne) si l'espace de modèle ne le contient pas.Il existe un moyen, cependant, d’obliger la boucle à conserver deux lignes consécutives dans l’espace du motif:
Ajoutez tout traitement nécessaire entre le N et le P (en remplacement du
l
).Dans ce cas (2 lignes):
Ou, pour trois lignes:
Cela suppose que le même nombre de lignes soit remplacé.
la source