Avec le bash
shell, dans un fichier avec des lignes comme les suivantes
first "line"
<second>line and so on
Je voudrais remplacer une ou plusieurs occurrences de "line"\n<second>
avec other characters
et obtenir à chaque fois:
first other characters line and so on
Je dois donc remplacer une chaîne à la fois par des caractères spéciaux tels que "
et <
et par un caractère de nouvelle ligne.
Après avoir cherché entre les autres réponses, j'ai trouvé que l' sed
on peut accepter les sauts de ligne dans le côté droit de la commande (donc, la other characters
chaîne), mais pas dans la gauche.
Existe-t-il un moyen (plus simple que cela ) d'obtenir ce résultat avec sed
ou grep
?
text-processing
sed
grep
newlines
BowPark
la source
la source
\n
déclaration ewline que vous faites est pourquoi je demande. les gens demandent rarement s'ils peuvent faire ces//\n/
que vous pouvez faire avec GNUsed
, bien que la plupart des autressed
rejetteront cette fuite du côté droit. néanmoins, l'\n
échappement fonctionnera à gauche dans n'importe quel POSIXsed
et vous pouvez les traduire de manière portable commey/c/\n/
si cela aurait le même effets/c/\n/g
et n'est donc pas toujours aussi utile.Réponses:
Trois
sed
commandes différentes :Ils s'appuient tous les trois sur la
s///
commande de base d' ubstitution:Ils essaient également tous de faire attention dans leur traitement de la dernière ligne, car les
sed
s ont tendance à différer sur leur sortie dans les cas de bord. Il s'agit de la signification d'$!
une adresse correspondant à chaque ligne qui n'est!
pas la$
dernière.Ils utilisent également tous la
N
commande ext pour ajouter la ligne d'entrée suivante à l'espace de motif à la suite d'un\n
caractère ewline. Quiconque travaillesed
depuis un certain temps aura appris à se fier au\n
caractère ewline - car la seule façon de l'obtenir est de le mettre explicitement là.Tous les trois essaient de lire le moins d'entrées possible avant d'agir -
sed
agissent dès que possible et n'ont pas besoin de lire l'intégralité d'un fichier d'entrée avant de le faire.Bien qu'ils fassent tout
N
, ils diffèrent tous les trois dans leurs méthodes de récursivité.Première commande
La première commande utilise une
N;P;D
boucle très simple . Ces trois commandes sont intégrées à tout compatible POSIXsed
et se complètent bien.N
- comme déjà mentionné, ajoute laN
ligne d'entrée ext à l'espace de motif après un\n
délimiteur ewline inséré .P
- commep
; ilP
imprime l'espace de motif - mais uniquement jusqu'au premier\n
caractère de ligne électronique apparaissant . Et donc, étant donné l'entrée / commande suivante:printf %s\\n one two | sed '$!N;P;d'
sed
P
rints seulement un . Cependant, avec ...D
- commed
; ilD
supprime l'espace modèle et commence un autre cycle linéaire. Contrairement àd
,D
ne supprime que jusqu'à la première ligne\n
électronique apparaissant dans l'espace de motif. S'il y a plus dans l'espace de motif suivant le\n
caractère ewline,sed
commence le cycle de ligne suivant avec ce qui reste. Si led
dans l'exemple précédent ont été remplacés par unD
, par exemple,sed
seraitP
Rint à la fois un et deux .Cette commande ne se reproduit que pour les lignes qui ne correspondent pas à l'
s///
instruction d'ubstitution. Étant donné que l's///
ubstitution supprime la ligne\n
électronique ajoutée avecN
, il ne reste plus rien lorsqu'ilsed
D
supprime l'espace de motif.Des tests pourraient être effectués pour appliquer le
P
et / ou deD
manière sélective, mais il existe d'autres commandes qui correspondent mieux à cette stratégie. Parce que la récursivité est implémentée pour gérer des lignes consécutives qui ne correspondent qu'à une partie de la règle de remplacement, les séquences consécutives de lignes correspondant aux deux extrémités de l's///
ubstitution ne fonctionnent pas bien .:Compte tenu de cette entrée:
... ça imprime ...
Il gère cependant
...ça va.
Deuxième commande
Cette commande est très similaire à la troisième. Les deux utilisent une étiquette
:b
ranch /t
est (comme cela est également démontré dans la réponse de Joeseph R. ici ) et y reviennent dans certaines conditions.-e :n -e
- lessed
scripts portables délimiteront une:
définition d'étiquette avec une ligne\n
électronique ou une nouvelle-e
instruction d'exécution en ligne .:n
- définit une étiquette nomméen
. Cela peut être retourné à tout moment avecbn
outn
.tn
- lat
commande est retourne à une étiquette spécifiée (ou, si aucune n'est fournie, quitte le script pour le cycle de ligne en cours) si toutes///
substitution depuis que l'étiquette a été définie ou depuis qu'elle a été appelée pour la dernière foist
ests a réussi.Dans cette commande, la récursivité se produit pour les lignes correspondantes. Si
sed
le modèle est remplacé avec succès par d' autres caractères ,sed
retourne à l':n
étiquette et réessaye. Sis///
aucune substitution n'est effectuée, l'sed
impression automatique de l'espace de motif commence le cycle de ligne suivant.Cela a tendance à mieux gérer les séquences consécutives. Là où le dernier a échoué, cela affiche:
Troisième commande
Comme mentionné, la logique ici est très similaire à la dernière, mais le test est plus explicite.
/"$/bn
- c'estsed
le test. Parce que lab
commande ranch est fonction de cette adresse,sed
ne fera queb
revenir ranch à la:n
suite d' un\n
ewline est ajouté et la structure de l' espace se termine toujours avec un"
guillemet.Il y a aussi peu de choses à faire entre
N
etb
que possible - de cette manière, voussed
pouvez très rapidement rassembler exactement autant de données que nécessaire pour vous assurer que la ligne suivante ne correspond pas à votre règle. L's///
ubstitution diffère ici en ce qu'elle utilise leg
drapeau lobal - et donc elle fera tous les remplacements nécessaires à la fois. Pour une entrée identique, cette commande est identique à la dernière.la source
DATA
et comment recevez-vous la saisie de texte?<<\DATA\ntext input\nDATA\n
est incrusté , mais ce n'est que du texte remissed
par le shell dans un document ici . Cela fonctionnerait aussi bien commesed 'script' filename
ouprocess that writes to stdout | sed 'script'
. Est ce que ça aide?D
chaque ligne modifiée est double? (Vous l'avez utilisé car il est nécessaire; peut-être que je ne sais passed
très bien)D
carD
sinon vousD
supprimez de la sortie ce que vous voyez maintenant doublé. Je viens de faire un montage - et je pourrai peut-être en parler aussi très bientôt.D
chose.Eh bien, je peux penser à quelques moyens simples, mais aucun n'implique
grep
(qui ne fait pas de substitution de toute façon) oused
.Perl
Pour remplacer chaque occurrence de
"line"\n<second>
avecother characters
, utilisez:Ou, pour traiter plusieurs occurrences consécutives
"line"\n<second>
comme une seule et les remplacer toutes par une seuleother characters
, utilisez:Exemple:
Le
-00
Perl de lire le fichier en mode « point » , qui signifie que « lignes » sont définies par la\n\n
place de\n
, pour l' essentiel, chaque point est considéré comme une ligne. La substitution correspond donc à travers une nouvelle ligne.awk
La même idée de base, nous avons défini le séparateur d'enregistrement (
RS
) pour\n\n
slurper le fichier entier, puis le séparateur d'enregistrement de sortie sur rien (sinon une nouvelle ligne supplémentaire est imprimée), puis utilisons lasub()
fonction pour effectuer le remplacement.la source
awk
devrait l'êtreprint;}' file
. Je dois éviter Perl et utiliser de préférencesed
, de toute façon vous avez suggéré de bonnes alternatives.lire l'intégralité du fichier et effectuer un remplacement global:
la source
${cmds}
est spécifique à GNU - la plupart des autressed
nécessitent une ligne\n
électronique ou une-e
pause entrep
et}
. Vous pouvez éviter les crochets tout à fait - et de manière portable - et même éviter d'insérer un\n
caractère ewline supplémentaire sur la première ligne comme:sed 'H;1h;$!d;x;s/"line"\n<second>/other characters /g'
sed -n '1{h;n};H; ${x; s/"line"\n<second>/other characters /g; p}'
- mais cela devient impossible à maintenir.Voici une variante de la réponse de glenn qui fonctionnera si vous avez plusieurs occurrences consécutives (fonctionne avec GNU
sed
uniquement):Le
:x
est juste une étiquette de branchement. Fondamentalement, ce que cela fait, c'est qu'il vérifie la ligne après substitution et s'il correspond toujours"line"
, il se ramifie à l':x
étiquette (c'est ce quibx
fait) et ajoute une autre ligne au tampon et commence à la traiter.la source
sed
qui prend sa gestion d'étiquette non-POSIX assez loin pour accepter un espace comme délimiteur pour la déclaration d'étiquette. Vous devez cependant noter que tout autresed
échouera là-bas - et échouera pourN
. GNUsed
rompt les directives POSIX pour imprimer l'espace de motif avant de quitter sur uneN
sur la dernière ligne, mais POSIX indique clairement que si uneN
commande est lue sur la dernière ligne, rien ne doit être imprimé.v
commande de GNU qui se casse les uns les autres,sed
mais est un no-op dans les versions 4 et supérieures de GNU.sed -e :x -e '/"line"/{$!N' -e '};s/"line"\n<second>/other characters/;/"line"/bx'
.