J'ai plusieurs très gros fichiers XML et j'essaie de trouver les lignes contenant des caractères non-ASCII. J'ai essayé ce qui suit:
grep -e "[\x{00FF}-\x{FFFF}]" file.xml
Mais cela retourne chaque ligne du fichier, que la ligne contienne ou non un caractère dans la plage spécifiée.
Est-ce que la syntaxe est incorrecte ou est-ce que je fais autre chose? J'ai aussi essayé:
egrep "[\x{00FF}-\x{FFFF}]" file.xml
(avec des guillemets simples et doubles entourant le motif).
Vous pouvez utiliser la commande:
grep --color='auto' -P -n "[\x80-\xFF]" file.xml
Cela vous donnera le numéro de ligne et mettra en évidence les caractères non-ascii en rouge.
Dans certains systèmes, en fonction de vos paramètres, ce qui précède ne fonctionnera pas, vous pouvez donc effectuer un grep inverse.
grep --color='auto' -P -n "[^\x00-\x7F]" file.xml
Notez également que le bit important est l'indicateur -P
qui équivaut à --Perl-regexp
: il interprétera donc votre modèle comme une expression régulière Perl. Il dit aussi que
ceci est hautement expérimental et grep -P peut avertir qu’il n’a pas été implémenté fonctionnalités.
Au lieu de faire des hypothèses sur la plage d'octets de caractères non-ASCII, comme le font la plupart des solutions ci-dessus, il est légèrement préférable que IMO soit explicite sur la plage d'octets réelle de caractères ASCII.
Ainsi, la première solution, par exemple, deviendrait:
grep --color='auto' -P -n '[^\x00-\x7F]' file.xml
(qui utilise essentiellement les caractères externes à la plage hexadécimale ASCII: de\x00 à\x7F)
Sur Mountain Lion, cela ne fonctionnera pas (en raison du manque de prise en charge PCRE dans BSD grep) , mais avec pcre
installé via Homebrew, les éléments suivants fonctionneront tout aussi bien:
pcregrep --color='auto' -n '[^\x00-\x7F]' file.xml
Y at-il des avantages ou des inconvénients que quiconque peut penser?
Ce qui suit fonctionne pour moi:
grep -P "[\x80-\xFF]" file.xml
Les caractères non-ASCII commencent à 0x80 et passent à 0xFF lors de la recherche d'octets. Grep (et sa famille) ne font pas de traitement Unicode pour fusionner des caractères multi-octets dans une seule entité afin de faire correspondre les expressions rationnelles que vous semblez vouloir. L'option -P
dans mon grep permet d'utiliser des échappements \xdd
dans les classes de caractères pour accomplir ce que vous voulez.
En Perl
Perl -ane '{ if(m/[[:^ascii:]]/) { print } }' fileName > newFile
Le moyen le plus simple est de définir un caractère non-ASCII ... comme un caractère qui n'est pas un caractère ASCII.
LC_ALL=C grep '[^ -~]' file.xml
Ajoutez un onglet après le ^
si nécessaire.
Définir LC_COLLATE=C
évite les mauvaises surprises quant à la signification des plages de caractères dans de nombreux endroits. La définition de LC_CTYPE=C
est nécessaire pour faire correspondre les caractères à un octet - sinon, la commande omettrait des séquences d'octets non valides dans le codage actuel. Définir LC_ALL=C
évite les effets dépendants de la localisation.
Voici une autre variante que j'ai trouvée qui produit complètement des résultats différents de la recherche de grep pour [\x80-\xFF]
dans la réponse acceptée. Peut-être sera-t-il utile de trouver d'autres personnages non-ascii:
grep --color='auto' -P -n "[^[:ascii:]]" myfile.txt
Remarque: le grep (un Mac) de mon ordinateur ne disposant pas de l'option -P
, j'ai donc utilisé brew install grep
et démarré l'appel ci-dessus avec ggrep
au lieu de grep
.
Le code suivant fonctionne:
find /tmp | Perl -ne 'print if /[^[:ascii:]]/'
Remplacez /tmp
par le nom du répertoire dans lequel vous souhaitez effectuer la recherche.
Recherche de caractères non imprimables.
Je suis d'accord avec Harvey ci-dessus, dans les commentaires, il est souvent plus utile de rechercher des caractères non imprimables OR, il est facile de penser non ASCII alors que vous devriez vraiment penser non imprimable. Harvey suggère "utilisez ceci:" [^\n - ~] ". Ajoutez\r pour les fichiers texte DOS. Cela se traduit par" [^\x0A\x020-\x07E] "et ajoutez\x0D pour CR"
Il est également utile d’ajouter -c (nombre de motifs trouvés) à grep lors de la recherche de caractères non imprimables, car les chaînes correspondantes peuvent gâcher le terminal.
J'ai trouvé l'ajout de la plage 0-8 et 0x0e-0x1f (à la plage 0x80-0xff) est un motif utile. Ceci exclut les onglets TAB, CR et LF et un ou deux autres caractères imprimables inhabituels. Donc, à mon humble avis, un assez utile (bien que brut) modèle GREP est celui-ci:
grep -c -P -n "[\x00-\x08\x0E-\x1F\x80-\xFF]" *
panne:
\x00-\x08 - non-printable control chars 0 - 7 decimal
\x0E-\x1F - more non-printable control chars 14 - 31 decimal
\x80-1xFF - non-printable chars > 128 decimal
-c - print count of matching lines instead of lines
-P - Perl style regexps
Instead of -c you may prefer to use -n (and optionally -b) or -l
-n, --line-number
-b, --byte-offset
-l, --files-with-matches
Par exemple. exemple pratique d'utilisation find pour grep tous les fichiers du répertoire courant:
find . -type f -exec grep -c -P -n "[\x00-\x08\x0E-\x1F\x80-\xFF]" {} +
Vous voudrez peut-être ajuster le grep parfois. par exemple. BS (0x08 - backspace) utilisé dans certains fichiers imprimables ou pour exclure VT (0x0B - onglet vertical). Les caractères BEL (0x07) et ESC (0x1B) peuvent également être considérés comme imprimables dans certains cas.
Non-Printable ASCII Chars ** marks PRINTABLE but CONTROL chars that is useful to exclude sometimes Dec Hex Ctrl Char description Dec Hex Ctrl Char description 0 00 ^@ NULL 16 10 ^P DATA LINK ESCAPE (DLE) 1 01 ^A START OF HEADING (SOH) 17 11 ^Q DEVICE CONTROL 1 (DC1) 2 02 ^B START OF TEXT (STX) 18 12 ^R DEVICE CONTROL 2 (DC2) 3 03 ^C END OF TEXT (ETX) 19 13 ^S DEVICE CONTROL 3 (DC3) 4 04 ^D END OF TRANSMISSION (EOT) 20 14 ^T DEVICE CONTROL 4 (DC4) 5 05 ^E END OF QUERY (ENQ) 21 15 ^U NEGATIVE ACKNOWLEDGEMENT (NAK) 6 06 ^F ACKNOWLEDGE (ACK) 22 16 ^V SYNCHRONIZE (SYN) 7 07 ^G BEEP (BEL) 23 17 ^W END OF TRANSMISSION BLOCK (ETB) 8 08 ^H BACKSPACE (BS)** 24 18 ^X CANCEL (CAN) 9 09 ^I HORIZONTAL TAB (HT)** 25 19 ^Y END OF MEDIUM (EM) 10 0A ^J LINE FEED (LF)** 26 1A ^Z SUBSTITUTE (SUB) 11 0B ^K VERTICAL TAB (VT)** 27 1B ^[ ESCAPE (ESC) 12 0C ^L FF (FORM FEED)** 28 1C ^\ FILE SEPARATOR (FS) RIGHT ARROW 13 0D ^M CR (CARRIAGE RETURN)** 29 1D ^] GROUP SEPARATOR (GS) LEFT ARROW 14 0E ^N SO (SHIFT OUT) 30 1E ^^ RECORD SEPARATOR (RS) UP ARROW 15 0F ^O SI (SHIFT IN) 31 1F ^_ UNIT SEPARATOR (US) DOWN ARROW
Étrangement, je devais le faire aujourd'hui! J'ai fini par utiliser Perl car je ne pouvais pas faire fonctionner grep/egrep (même en mode -P). Quelque chose comme:
cat blah | Perl -en '/\xCA\xFE\xBA\xBE/ && print "found"'
Pour les caractères unicode (comme \u2212
dans l'exemple ci-dessous), utilisez ceci:
find . ... -exec Perl -CA -e '$ARGV = @ARGV[0]; open IN, $ARGV; binmode(IN, ":utf8"); binmode(STDOUT, ":utf8"); while (<IN>) { next unless /\N{U+2212}/; print "$ARGV: $&: $_"; exit }' '{}' \;
La recherche de tous les caractères non ASCII donne l’impression que l’on cherche des chaînes Unicode ou a l’intention de les effacer individuellement.
Dans le premier cas, essayez l’une de ces méthodes (la variable file
est utilisée pour l’automatisation):
file=file.txt ; LC_ALL=C grep -Piao '[\x80-\xFF\x20]{7,}' $file | iconv -f $(uchardet $file) -t utf-8
file=file.txt ; pcregrep -iao '[\x80-\xFF\x20]{7,}' $file | iconv -f $(uchardet $file) -t utf-8
file=file.txt ; pcregrep -iao '[^\x00-\x19\x21-\x7F]{7,}' $file | iconv -f $(uchardet $file) -t utf-8
Vanilla grep ne fonctionne pas correctement sans LC_ALL = C comme indiqué dans les réponses précédentes.
La plage ASCII est x00-x7F
, l'espace est x20
, puisque les chaînes ont des espaces, la plage négative l'omet.
La plage non-ASCII est x80-xFF
, puisque les chaînes ont des espaces, la plage positive l'ajoute.
La chaîne est supposée contenir au moins 7 caractères consécutifs dans la plage. {7,}
.
uchardet $file
renvoie une estimation du codage de fichier qui est passé à iconv pour une interpolation automatique.
Il pourrait être intéressant de savoir comment rechercher un caractère Unicode. Cette commande peut aider. Il vous suffit de connaître le code en UTF8
grep -v $'\u200d'