Je voudrais remplacer un ensemble de caractères par des caractères correspondants d'un autre ensemble, quelque chose comme ceci:
original set: ots
"target" set: u.x
foobartest → fuubar.ex.
Les traductions / translittérations comme celle-ci sont la spécialité de la tr
commande:
$ echo 'foobartest' | tr 'ots' 'u.x'
fuubar.ex.
Malheureusement, tr
ne prend pas en charge la modification des fichiers sur place comme le sed
fait.
Je voudrais l'utiliser sed
pour ne pas avoir à réinventer la roue de jongler avec les fichiers temporaires.
tr
(correctement) ignore la récursivité dans les ensembles de remplacement:echo 'abc' | tr ab bx
→bxc
. Une solution primitive pourrait supprimer celaxxc
car elle réapplique la traduction aux caractères qui ont déjà été traduits.sed
contrairement à GNUtr
peut transliter des caractères multi-octets)Réponses:
sed
a lay
commande qui fonctionne commetr
:La
y
commande fait partie de la spécification POSIXsed
, elle devrait donc fonctionner sur à peu près n'importe quelle plate-forme.Et comme c'est le cas
sed
, vous pouvez le faire remplacer un fichier par sa version modifiée, vous épargnant les affaires de fichiers temporaires gênants (à condition que votre implémentation desed
prend en charge l'-i
option, qui n'est pas spécifiée par POSIX):la source
sed
que les autres fonctions le sont aussi. ;) La liste de diffusion Vim a un fil sur la recherche d'uny/abc/def/
équivalent; la meilleure option semble être:%call setline(".", tr(getline("."),"abc","def"))
.Si comme dans votre cas, vous translittérez des caractères sans changer leur taille (de toute façon, certaines implémentations comme GNU
tr
ne prennent en charge que les caractères à un octet), vous pouvez faire:Autrement dit,
tr
écrasez le fichier sur lui-même.C'est mieux que
sed -i
sur plusieurs comptes:Un inconvénient est que s'il est interrompu, le fichier finira par être à moitié traduit (dans ce cas, cependant, vous pouvez le réexécuter pour le terminer). Certaines
sed
implémentations géreraient cela correctement en s'assurant que le fichier d'origine reste inchangé à moins que la commande réussisse.la source
echo 'abc' | tr ab bx
.tr
et dans notre environnement PXE lourd de liens symboliques,sed -i
était une attente de vissage pour arriver…: /iconv -t cp437
semble plus approprié pour cela.iconv
se casse lorsque le fichier d'entrée contient déjà des octets encodés en cp437, ou un mélange de plusieurs encodages. Donc, bien qu'il soit préférable dans le cas général, il est plus robuste de faire des remplacements manuels sur ce cas.Comme autre alternative, si votre problème principal est le manque de support pour changer les fichiers sur place, vous pourriez être intéressé par l'
sponge
outil du paquet moreutils :va écrire dans
file
, mais ne sera ouvertfile
en écriture qu'une fois la saisie terminée. Depuis la page de manuel :Sauf si vous avez des fichiers vraiment volumineux qui ne peuvent pas être conservés en mémoire, cela
sponge
pourrait fonctionner pour vous.la source
sponge
est qu'il écrase toujours enfile
cas d'tr
échec (par exemple si vous aviez accès en écriture mais pas en lecturefile
)cat file >; file
opérateur de ksh93 qui écrit la sortie dans un fichier temporaire qui est renommé à la destination uniquement si la commande réussit (mais commesed -i
, cela crée un nouveau fichier au lieu d'écraser l'original).