La question indique explicitement que les titres contiendront des espaces. Pour des raisons de sécurité, je suppose que les titres peuvent contenir des points (points); par exemple, “L’histoire de 3.14159” ou “Dr. Doolittle's Discovery ». Mes réponses supposent qu'il y a un caractère qui n'apparaîtra jamais dans la table des matières; en particulier, ils supposent que c'est @
. Si vous avez @
dans votre table, le remplacer par un caractère qui n'apparaît (par exemple, #
, ^
, _
, |
, etc.). Si vous utilisez réellement tous les caractères ASCII, vous devrez peut-être utiliser une séquence de caractères, comme <@>
.
Trois façons de le faire avec sed
:
Boucle:
sed 's/\(.*\)\( \)/\1@\2/; :loop; s/ @/ @./; t loop; s/@//'
s/\(.*\)\( \)/\1@\2/
trouve le dernier espace sur la ligne et insère un @
avant.
:loop
est une étiquette, comme un marqueur de mile.
s/ @/ @./
(c'est-à-dire s/␣␣@/␣@./
, pour la non-ambiguïté) dit, s'il y a deux espaces avant le @
, les remplace par ␣.
(espace et point) et déplacez-les @
entre eux.
t loop
si la substitution ci-dessus a réussi, dit de revenir au :loop
marqueur et de répéter. Sinon, continuez à
s/@//
, qui supprime le @
.
Donc, la foo bar
ligne dans votre table sera traitée comme suit:
Valeur initiale: foo bar url3
s / \ (. * \) \ (\) / \ 1 @ \ 2 / foo bar @ url3
s / @ / @. / foo bar @. url3
s / @ / @. / foo bar @ .. url3
s / @ / @. / foo bar @ .. url3 (La substitution échoue, ne faites pas de boucle)
s / @ // foo bar .. url3
Sortie finale: foo bar .. url3
Chiffres écrasants:
sed 's/\(.*\)\( \)/\1@@@@@@@@@@@@@@@@@@@@\2/; s/ [ @]\{20\}/ /; s/@/./g'
s/\(.*\)\( \)/\1@@@@@@@@@@@@@@@@@@@@\2/
est très similaire à la première s
sous-commande de la première solution; il trouve le dernier espace sur la ligne et insère une chaîne de 20 @
caractères devant elle. Cela devrait en fait être un nombre au moins aussi grand que le nombre maximum de points que vous devrez jamais insérer sur une seule ligne; par exemple, 80. La gestion d'une chaîne de 80 @
caractères serait délicate; vous voudrez peut-être remplacer ceci par
s/\(.*\)\( \)/\1<@><@><@><@><@>\2/; s/<@>/@@@@@@@@/g
qui insère une chaîne de cinq <@>
séquences, puis remplace chacune d’elles par une chaîne de 16 @
caractères, ce qui donne 5 × 16 = 80 @
caractères.
s/ [ @]\{20\}/ /
trouve une chaîne de 20 caractères consécutifs qui sont soit un espace, soit un @
précédé d'un espace et le remplace par le seul espace précédent. Remplacez-le 20
par le numéro de l'étape précédente.
s/@/./g
remplace chaque reste @
par un point.
Donc, la foo
ligne dans votre table sera traitée comme suit:
Initial value: foo url1
s/\(.*\)\( \)/\1@@@@...@@@@\2/ foo @@@@@@@@@@@@@@@@@@@@ url1
s/ [ @]\{20\}/ / _[↑↑↑↑↑↑remove↑↑↑↑↑↑]
foo @@@@@@ url1
s/@/./g foo ...... url1
Utilisez la "cale":
sed 's/.*[^ ] /&@/; h; s/ /./g; s/\(\.*\)\./\1 /; x; G; s/@.*@//'
s/.*[^ ] /&@/
est similaire aux commandes précédentes; il trouve la fin du titre - pour être précis, le dernier endroit où un caractère non vide est suivi d'un espace - et insère un @
après celui-ci.
h
copie la ligne dans l'espace réservé.
s/ /./g
remplace tous les espaces de la ligne par des points.
s/\(\.*\)\./\1 /
remplace le dernier point par un espace. (Cela devra changer si l'URL peut contenir des points, ce qui est probable, je suppose.)
x
échange l'espace motif et l'espace d'attente.
G
ajoute l'espace de maintien à l'espace du motif. Nous avons maintenant essentiellement deux copies de la ligne.
s/@.*@//
conserve la première partie de la première copie et la seconde partie de la deuxième copie, en éliminant le contenu au milieu.
Initial value: foo bar url3
Pattern space Hold space
s/.*[^ ] /&@/ foo bar @ url3
h foo bar @ url3 foo bar @ url3
s/ /./g foo.bar.@...url3 foo bar @ url3
s/\(\.*\)\./\1 / foo.bar.@.. url3 foo bar @ url3
x foo bar @ url3 foo.bar.@.. url3
G foo bar @ url3 foo.bar.@.. url3 foo.bar.@.. url3
s/@.*@// foo bar .. url3 foo.bar.@.. url3
Final output: foo bar .. url3