J'ai besoin de remplacer certains caractères non imprimables par des espaces dans le fichier.
Plus précisément, tous les caractères de 0x00
jusqu'à 0x1F
, sauf 0x09
(TAB), 0x0A
(nouvelle ligne), 0x0D
(CR)
Jusqu'à présent, j'avais juste besoin de remplacer le 0x00
personnage. Étant donné que mon système d'exploitation précédent était AIX (sans commandes GNU), je ne peux pas l'utiliser sed
(enfin, je le peux, mais il y avait quelques limitations). J'ai donc trouvé la prochaine commande utilisant perl
, qui a fonctionné comme prévu:
perl -p -e 's/\x0/ /g' $FILE_IN > $FILE_OUT
Maintenant, je travaille sur Linux, donc je m'attendais à pouvoir utiliser la sed
commande.
Mes questions:
Cette commande est-elle appropriée pour remplacer ces caractères? J'ai essayé, et cela semble fonctionner, mais je veux m'assurer:
perl -p -e 's/[\x00-\x08\x0B\x0C\x0E-\x1F]/ /g' $FILE_IN > $FILE_OUT
Je pensais
perl -p
que ça marchesed
. Alors, pourquoi la commande précédente fonctionne-t-elle (au moins, elle n'échoue pas) et la suivante non?sed -e 's/[\x00-\x08\x0B\x0C\x0E-\x1F]/ /g' $FILE_IN > $FILE_OUT
Ça me dit:
sed: -e expression # 1, caractère 34: caractère de classement non valide
perl -p
imprime le produit finalstdin
après avoir effectué les opérations souhaitées, dans ce cas, il s'agit simplement de remplacement.sed
Le regex de peut être différent deperl
.Réponses:
C'est un travail typique pour
tr
:Dans votre cas, cela ne fonctionne pas,
sed
car vous vous trouvez dans une région où ces plages n'ont aucun sens. Si vous voulez travailler avec des valeurs d'octets par opposition aux caractères et où l'ordre est basé sur la valeur numérique de ces octets, votre meilleur pari est d' utiliser les paramètres régionaux C . Votre code aurait fonctionné avecLC_ALL=C
GNUsed
, mais utilisersed
(sans parlerperl
) est un peu exagéré ici (et ceux\xXX
-ci ne sont pas portables sur toutes lessed
implémentations alors que cettetr
approche est POSIX).Vous pouvez également faire confiance à l'idée de votre région de ce que sont les caractères imprimables avec:
Mais avec GNU
tr
(comme on le trouve généralement sur les systèmes Linux), cela ne fonctionne que dans les paramètres régionaux où les caractères sont à un octet (donc généralement pas UTF-8).Dans les paramètres régionaux C, cela exclurait également DEL (0x7f) et toutes les valeurs d'octets ci-dessus (pas en ASCII).
Dans les locales UTF-8, vous pouvez utiliser GNU
sed
qui n'a pas le problème que GNUtr
a:(notez que ceux
\r
,\t
ne sont pas standard, et GNUsed
ne les reconnaîtra pas siPOSIXLY_CORRECT
est dans l'environnement (les traitera comme backslash, r et t faire partie de l'ensemble comme POSIX exige)).Cependant, il ne convertirait pas les octets qui ne forment pas de caractères valides.
la source
tr
commande. Je comprends (plus ou moins) ce quiLC_ALL = C
est, mais pas tous ensemble.tr -d
Supprime néanmoins ces caractères, mais je veux les remplacer par des espaces. Désolé, le titre était incorrect. Je viens de réaliser, quand @don_crissti a été modifié.XCOM
. Par exemple, les caractères non ASCII commeÉ
sont codifiés (en utilisantod -xa
) comme0xC9
, donc je suppose que ce le seraitISO-8859-1
.locale -a
pour voir s'il existe des paramètres régionaux avec iso8859-1 comme jeu de caractères sur votre système et utiliserLC_CTYPE=<that-locale> tr ...[:print:]...
pour convertir les éléments non imprimables dans ce paramètre régional. Ou vous pouvez utiliser iconv pour convertir ces fichiers en jeu de caractères de votre locale.LC_ALL=en_US.iso88591
. Ainsi, votre commande (tr -c '[:print:]\t\r\n' '[ *]'
) fonctionne parfaitement sans modifier les paramètres régionaux ou convertir le fichier. Merci beaucoup.J'essayais d'envoyer une notification via libnotify, avec du contenu pouvant contenir des caractères non imprimables. Les solutions existantes ne fonctionnaient pas tout à fait pour moi (utiliser une liste blanche de caractères utilisant des
tr
œuvres, mais supprime tous les caractères multi-octets).Voici ce qui a fonctionné, en passant le test 💩:
la source