web-dev-qa-db-fra.com

Comment détecter la fin de ligne avec sed

Je cherche un moyen d'exécuter le remplacement uniquement lorsque le dernier caractère est une nouvelle ligne, en utilisant sed.

Par exemple:

lettersAtEndOfLine

est remplacé, mais ce n'est pas:

lettersWithCharacterAfter&

Puisque sed ne fonctionne pas bien avec les sauts de ligne, ce n'est pas aussi simple que

$ sed -E "s/[a-zA-Z]*\n/replace/" file.txt

Comment cela peut-il être accompli?

15

Avec la norme sed, vous jamais verrez une nouvelle ligne dans le texte lu à partir d'un fichier. Cela est dû au fait que sed lit ligne par ligne, et il n'y a donc pas de nouvelle ligne à la fin du texte de la ligne actuelle dans l'espace modèle de sed. En d'autres termes, sed lit les données délimitées par des sauts de ligne et les délimiteurs ne font pas partie de ce que voit un script sed.

Les expressions régulières peuvent être ancrées à la fin de la ligne en utilisant $ (ou au début, en utilisant ^). L'ancrage d'une expression au début/à la fin d'une ligne la force à correspondre exactement là, et pas seulement n'importe où sur la ligne.

Si vous souhaitez remplacer tout ce qui correspond au modèle [A-Za-z]* à la fin de la ligne avec quelque chose, puis ancrer le motif comme ceci:

[A-Za-z]*$

... le forcera à correspondre à la fin de la ligne et nulle part ailleurs.

Cependant, puisque [A-Za-z]*$ correspond également à rien (par exemple, la chaîne vide présente à la fin de chaque ligne), vous devez forcer la correspondance de quelque chose , par exemple en spécifiant

[A-Za-z][A-Za-z]*$

ou

[A-Za-z]\{1,\}$

Ainsi, votre ligne de commande sed sera donc

$ sed 's/[A-Za-z]\{1,\}$/replace/' file.txt

Je n'ai pas utilisé le -E basculez ici car ce n'est pas nécessaire. Avec ça, vous auriez pu écrire

$ sed -E 's/[A-Za-z]+$/replace/' file.txt

C'est une question de goût.

21
Kusalananda
sed "s/[a-zA-Z]*$/replace/" input.txt > result.txt

Ou, la manière inutile longue et complexe:

J'ai découvert que cela peut être fait, en utilisant toujours sed, avec l'aide de tr. Vous pouvez attribuer un autre caractère pour représenter la fin de la ligne. Un autre caractère temporaire doit être utilisé, dans ce cas "" ". Utilisons "~" pour représenter la fin de la ligne:

tr '\n' '`' <input.txt >output.txt
sed -i "s/`/~`/" output.txt
tr '`' '\n' <output.txt >result.txt

Et puis pour effectuer la recherche réelle et remplacer, utilisez "~" plutôt que "\ n":

sed -i -E "s/[a-zA-Z]*~/replace/" result.txt

Et puis nettoyez le caractère supplémentaire sur les autres lignes:

sed -i "s/~//" result.txt

De toute évidence, tout cela peut être canalisé, ce qui donne quelque chose comme:

tr '\n' '`' <input.txt | sed -e "s/`/~`/" | tr '`' '\n' | sed -E -e "s/[a-zA-Z]*~/replace/" | sed "s/~//" > result.txt

Pour trouver la fin de la ligne, utilisez simplement le signe $ -:

Sans ancrage de fin de ligne:

sed -n '/pattern/p' file 

Sans ancrage de fin de ligne:

sed -n '/pattern$/p' file
0
user unknown

À partir de l'extrait de code (cassé) que vous avez publié, vous semblez également vouloir remplacer la nouvelle ligne. Dans ce cas, l'ancrage regex par lui-même ne peut pas vous aider. Voici une solution:

sed '/[[:alpha:]]\+$/{N;s/[[:alpha:]]\+\n/replace/}' your_file

En panne:

  • /[a-zA-Z]\+$/{} signifie appliquer tout ce qui se trouve à l'intérieur des boucles aux lignes qui correspondent à l'expression régulière.
  • Le regex est celui qui utilise l'ancrage comme vu dans votre propre réponse , modifié pour prendre en compte les commentaires de glenn jackman .
  • A l'intérieur des curlies, N signifie "ajouter la ligne suivante au tampon actif" (ce que sed appelle "l'espace modèle")
  • Finalement, le s/// l'instruction est votre substitution requise. Cela fonctionne maintenant car l'espace de motif contient deux lignes successives et la nouvelle ligne en fait donc partie.
0
Joseph R.