Suppression de tous les caractères non ascii d'un workflow (fichier)

13

Comment supprimer tous les caractères non ascii d'un fichier? Y aurait-il une commande spécifique pour effectuer cela?

grep --colour='auto' -P -n'[^\x00-\x7]' /usr/local/...

Je crois que cela trouve les personnages dans le flux de travail, mais comment supprimer toutes les instances des personnages en question?

Mizole Ni
la source
2
connexe: si vous voulez simplement éviter les problèmes avec les caractères de contrôle (au lieu de vous en débarrasser silencieusement), vous pouvez simplement les utiliser cat -vpour les représenter en représentation ASCII pour eux. (par exemple ^Gpour \007)
Matija Nalis
1
Lorsque vous dites "caractères non ascii", incluez-vous également les caractères accentués?
Captain Man
1
@MatijaNalis Plus d'informations sur la représentation: en.wikipedia.org/wiki/Caret_notation
wjandrea
1
Quel est le cas d'utilisation? Très souvent, il existe des outils spécifiques ou des approches différentes qui fonctionnent bien mieux que de simplement supprimer un groupe de caractères spéciaux. Veuillez noter que l'ASCII inclut plusieurs caractères "spéciaux" comme les tabulations verticales, la cloche et le NUL - êtes-vous sûr de ne pas parler de caractères imprimables ?
l0b0

Réponses:

26

Les caractères ASCII sont des caractères compris entre 0 et 177 (octal) inclusivement .

Pour supprimer des caractères hors de cette plage dans un fichier, utilisez

LC_ALL=C tr -dc '\0-\177' <file >newfile

La trcommande est un utilitaire qui fonctionne sur des caractères uniques , soit en les remplaçant par d'autres caractères simples (translittération), soit en les supprimant, soit en compressant des séquences du même caractère en un seul caractère.

La commande ci-dessus lit fileet écrit le contenu modifié dans newfile. L' -doption permettant à trl'utilitaire de supprimer les caractères (au lieu de les translittérer) et de le -cfaire considérer les caractères en dehors de l'intervalle donné (au lieu de l'intérieur).

LC_ALL=Cs'assure que chaque valeur d'octet constitue un caractère valide. Sans cela, certaines trimplémentations seraient abandonnées si elles trouvaient des séquences d'octets qui ne forment pas de caractères valides dans le codage de caractères des paramètres régionaux.


Pour remplacer le fichier d'origine par le fichier modifié, utilisez

LC_ALL=C tr -dc '\0-\177' <file >newfile &&
mv newfile file

Cela renomme le nouveau fichier au nom de l'ancien fichier une fois trterminé. Si trcela ne se termine pas correctement, soit parce qu'il n'a pas pu lire le fichier d'origine ou ne pas écrire dans le nouveau fichier, le fichier d'origine restera inchangé.

Alternativement, pour conserver autant que possible les métadonnées (autorisations, etc.) du fichier d'origine, utilisez

cp file tmpfile &&
LC_ALL=C tr -dc '\0-\177' <tmpfile >file &&
rm tmpfile
Kusalananda
la source
14

Avec perl

perl -pi -e 's/[^[:ascii:]]//g'
NotAnUnixNazi
la source
9

Si tout ce dont vous avez besoin est une expression régulière: [\x00-\x7F]que vous pouvez appliquer à plusieurs utilitaires:

<file LC_ALL=C   sed   's/[^\o0-\o177]//g'      # GNU sed without POSIXLY_CORRECT
<file LC_ALL=C   awk   '{gsub(/[^\0-\177]/,"");print}'
<file            perl  -pe 's/[^[:ascii:]]//g;'
<file LC_ALL=C   tr    -dc '\0-\177'

Comprenez que sed, awk et perl attendent des "fichiers texte" tels que définis dans Unix. Tous fonctionnent bien dans ce cas. Mais en particulier, awk ajoute une nouvelle ligne de fin (qu'elle existe ou non dans le fichier source) (l'utilisation de printf supprime TOUS les retours à la ligne en entrée). Le tr est conçu pour fonctionner avec n'importe quel type de fichier. Cependant, NUL ( \0) n'est pas un caractère valide dans un fichier texte POSIX et doit être évité:

Les lignes ne contiennent pas de caractères NUL ...

En fait, de nombreux caractères de contrôle généreraient d'autres problèmes dans certaines conditions spécifiques.
Donc, vous avez probablement besoin[\x07-\x0d\x20-\x7e]

<file LC_ALL=C   sed   's/[^\o007-\o015\o040-\o176]//g'            # GNU sed without POSIXLY_CORRECT
<file LC_ALL=C   awk   '{gsub(/[^\0-\15\40-\176]/,"");print}'
<file            perl  -pe 's/[^\x{7}-\x{d}\x{20}-\x{7e}]//g;'
<file LC_ALL=C   tr    -dc '\7-\15\40-\176'

La plage 7-13 (en décimal) est \a\b\t\n\v\f\r(dans l'ordre).
Une plage similaire (probablement plus portable) pourrait s'écrire [^[:space:][:print:]] (similar because it doesn't include\ a \ b` --bell et backspace--).

<file LC_ALL=C   sed   's/[^[:space:][:print:]]//g'  # GNU sed without POSIXLY_CORRECT
<file LC_ALL=C   awk   '{gsub(/[^[:space:][:print:]]/,"");print}'
<file            perl   -pe 's/[^[:space:][:print:]]//g;'
<file LC_ALL=C   tr     -dc '[:space:][:print:]'

En relation:
Regex n'importe quel caractère ASCII
Solution Perl
Fichier de texte Posix

NotAnUnixNazi
la source
Notez que l'entrée à trpeut être n'importe quel type de fichier, pas seulement des fichiers texte. awkd'autre part, prend un fichier texte.
Kusalananda
Il est assez difficile pour moi de trouver autre chose pour appeler un fichier "uniquement des caractères ascii" autre chose qu'un "fichier texte" (oui, oui: en termes simples). @Kusalananda (note sur awk ajoutée quand même).
NotAnUnixNazi
Notez que gensub()c'est une extension gawk. Vous voudriez gsub(...); print, et utilisez octal au lieu de séquences hexadécimales (et LC_ALL = C) pour être (plus) portable.
Stéphane Chazelas
@ StéphaneChazelas Quelle est la limitation de GNU sed qui rend la syntaxe GNU spécifique (je comprends le problème POSIXLY_CORRECT).
NotAnUnixNazi
[^\o0]est de faire correspondre les caractères autres que la barre oblique inverse, o et 0 dans POSIX sed(dans toutes les implémentations sauf GNU sed). Ce n'est pas une limitation de GNU sedmais une extension non conforme, c'est pourquoi elle est désactivée lorsque POSIXLY_CORRECT est dans l'environnement).
Stéphane Chazelas