web-dev-qa-db-fra.com

Comprendre l'expression sed pour remplacer le dernier mot de chaque ligne par le premier

Je dois remplacer le dernier mot de chaque ligne par le premier. Le code est:

$ sed "s/\(^a-z,0-9]*\)\(.*\)\([a-z,0-9]*$\)/\1\2\1\g". 

Je ne comprends pas cette partie \(^a-z,0-9]*\)\(.*\)\([a-z,0-9]*$\) surtout \(.*\).

4
L.Robert

Après avoir corrigé les erreurs de syntaxe de base, vous avez:

sed "s/\(^[a-z,0-9]*\)\(.*\)\([a-z,0-9]*$\)/\1\2\1/g"
  • s/old/new/ remplace old par new
  • \(^[a-z,0-9]*\) enregistre un nombre quelconque de lettres minuscules ou de chiffres au début de la ligne (^ est le début de la ligne) pour une utilisation ultérieure (reportez-vous ultérieurement à \1)
  • \(.*\) Enregistrez n'importe quel nombre de caractères pour plus tard (pour qu'il soit appelé \2)
  • \([a-z,0-9]*$\) enregistre un nombre quelconque de lettres minuscules ou de chiffres à la fin de la ligne ($ est la fin de la ligne) pour une utilisation ultérieure (référence: \3)
  • \1\2\1 imprime le premier motif, puis le second, puis à nouveau le premier
  • g c'est inapproprié dans cette expression. Cela signifie agir sur plusieurs correspondances sur la même ligne, mais notre expression doit lire toute la ligne, donc g n'a pas de sens et doit être omis.

Cela ne fonctionnera toujours pas, car les expressions régulières sont gourmandes. Le milieu \(.*\) correspond à tout ce qui suit le premier mot, ce qui entraîne la réimpression du premier mot à la fin de la ligne sans rien remplacer.

Vous pouvez le réparer (en ajoutant également I pour une recherche insensible à la casse):

sed "s/\(^[a-z,0-9]*\) \(.*\) \([a-z,0-9]*$\)/\1 \2 \1/I"

Si vous souhaitez inclure d'autres caractères que des lettres et des chiffres:

sed -r 's/^([^ ]+) (.*) ([^ ]+)$/\1 \2 \1/'
  • -r use ERE (enregistre avec toutes ces barres obliques inverses)
  • [^ ]+ au moins un des caractères sauf les espaces
10
Zanna

Je ne pense pas que votre code va même fonctionner ici parce qu'il est simplement mal formé. Je réécrirais l'expression entière. En supposant que toutes les lignes commencent et finissent par des mots ne contenant que des chiffres et des lettres de l'alphabet, vous pouvez essayer ceci:

$ echo -en "foo bar baz\nThe Good, the Bad and the Ugly\n" | \
> sed 's/^\(\<[[:alpha:]]\+\>\)\(.*\)\<[[:alpha:]]\+\>$/\1\2\1/g'
foo bar foo
The Good, the Bad and the The

Brève explication:

s/PATTERN/SUBSTITUTION_STRING/g - PATTERN est ce que nous recherchons et SUBSTITUTION_STRING est ce que nous allons remplacer par ledit modèle. g signifie que toute la ligne sera analysée, par opposition à la première correspondance trouvée sur la ligne.

^\(\<[[:alpha:]]\+\>\) - si une ligne commence par une limite de mot suivie de plusieurs caractères alphanumériques suivis d'une autre limite de mot, enregistrez tout cela dans la variable \1.

\<[[:alpha:]]\+\>$ - exactement la même chose ici, mais nous ne l'utilisons que pour identifier l'emplacement du dernier mot.

\(.*\) - tout ce qui est entre les deux sera sauvegardé dans la variable \2.

\1\2\1 - la même ligne avec le dernier mot remplacé par le premier.

3
misha