Come faccio a grep per tutti i caratteri non ASCII?

Ho diversi file XML molto grandi e sto cercando di trovare le righe che contengono caratteri non ASCII. Ho provato il seguente:

grep -e "[\x{00FF}-\x{FFFF}]" file.xml 

Ma questo restituisce ogni riga nel file, indipendentemente dal fatto che la linea contenga un carattere nell’intervallo specificato.

Ho sbagliato la syntax o sto sbagliando qualcos’altro? Ho anche provato:

 egrep "[\x{00FF}-\x{FFFF}]" file.xml 

(con virgolette singole e doppie che circondano il modello).

Puoi usare il comando:

 grep --color='auto' -P -n "[\x80-\xFF]" file.xml 

Questo ti darà il numero della linea, e metterà in evidenza i caratteri non ascii in rosso.

In alcuni sistemi, a seconda delle impostazioni, quanto sopra non funzionerà, quindi è ansible grep per l’inverso

 grep --color='auto' -P -n "[^\x00-\x7F]" file.xml 

Si noti inoltre che il bit importante è il flag -P che equivale a --perl-regexp : quindi interpreterà il pattern come un’espressione regolare Perl. Lo dice anche questo

questo è altamente sperimentale e grep -P potrebbe avvisare di funzionalità non implementate.

Invece di fare supposizioni sull’intervallo di byte di caratteri non ASCII, come fa la maggior parte delle soluzioni di cui sopra, è leggermente meglio IMO essere espliciti sull’intervallo di byte effettivo di caratteri ASCII.

Quindi la prima soluzione, ad esempio, diventerebbe:

 grep --color='auto' -P -n '[^\x00-\x7F]' file.xml 

(che sostanzialmente greps per qualsiasi carattere al di fuori dell’intervallo ASCII esadecimale: da \ x00 a \ x7F)

Su Mountain Lion che non funzionerà (a causa della mancanza del supporto PCRE in grep BSD) , ma con pcre installato tramite Homebrew, quanto segue funzionerà altrettanto bene:

 pcregrep --color='auto' -n '[^\x00-\x7F]' file.xml 

Qualche pro o contro che qualcuno possa pensare?

Il seguente funziona per me:

 grep -P "[\x80-\xFF]" file.xml 

I caratteri non ASCII iniziano da 0x80 e passano a 0xFF quando si guardano i byte. Grep (e famiglia) non eseguono l’elaborazione Unicode per unire caratteri multi-byte in una singola quadro per la corrispondenza delle espressioni regolari come sembra. L’opzione -P nel mio grep consente l’uso di \xdd nelle classi di caratteri per realizzare ciò che vuoi.

In perl

 perl -ane '{ if(m/[[:^ascii:]]/) { print } }' fileName > newFile 

Il modo semplice è definire un carattere non ASCII … come un carattere che non è un carattere ASCII.

 LC_ALL=C grep '[^ -~]' file.xml 

Aggiungi una scheda dopo ^ se necessario.

L’impostazione di LC_COLLATE=C evita brutte sorprese sul significato degli intervalli di caratteri in molte impostazioni locali. L’impostazione di LC_CTYPE=C è necessaria per far corrispondere i caratteri a byte singolo, altrimenti il ​​comando mancherebbe di sequenze di byte non valide nella codifica corrente. L’impostazione di LC_ALL=C evita del tutto gli effetti dipendenti dalla locale.

Ecco un’altra variante che ho trovato che ha prodotto risultati completamente diversi dalla ricerca di grep per [\x80-\xFF] nella risposta accettata. Forse sarà utile a qualcuno trovare altri caratteri non ascii:

grep --color='auto' -P -n "[^[:ascii:]]" myfile.txt

Nota: grep del mio computer (un Mac) non ha avuto l’opzione -P , quindi ho fatto l’ brew install grep e ho iniziato la chiamata sopra con ggrep invece di grep .

Il seguente codice funziona:

 find /tmp | perl -ne 'print if /[^[:ascii:]]/' 

Sostituisci /tmp con il nome della directory che vuoi cercare.

Stranamente, ho dovuto farlo oggi! Ho finito per usare Perl perché non potevo far funzionare grep / egrep (anche in modalità -P). Qualcosa di simile a:

 cat blah | perl -en '/\xCA\xFE\xBA\xBE/ && print "found"' 

Per i caratteri unicode (come \u2212 nell’esempio seguente) usa questo:

 find . ... -exec perl -CA -e '$ARGV = @ARGV[0]; open IN, $ARGV; binmode(IN, ":utf8"); binmode(STDOUT, ":utf8"); while () { next unless /\N{U+2212}/; print "$ARGV: $&: $_"; exit }' '{}' \; 

Ricerca di caratteri non stampabili.

Sono d’accordo con Harvey sopra sepolto nei commenti, è spesso più utile cercare caratteri non stampabili O è facile pensare non ASCII quando si dovrebbe davvero pensare non stampabili. Harvey suggerisce “usa questo:” [^ \ n – ~] “. Aggiungi \ r per i file di testo DOS. Questo si traduce in” [^ \ x0A \ x020- \ x07E] “e aggiungi \ x0D per CR”

Inoltre, l’aggiunta di -c (mostra il conteggio dei modelli abbinati) a grep è utile quando si cercano caratteri non stampabili poiché le stringhe corrispondenti possono rovinare il terminale.

Ho trovato che aggiungere l’intervallo 0-8 e 0x0e-0x1f (all’intervallo 0x80-0xff) è un modello utile. Questo esclude il TAB, CR e LF e uno o due caratteri più insoliti stampabili. Quindi IMHO è un modello abbastanza utile (anche se grezzo) di grep, QUESTO:

 grep -c -P -n "[\x00-\x08\x0E-\x1F\x80-\xFF]" * 

abbattersi:

 \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 

Ad esempio, pratico esempio di utilizzo trova a grep tutti i file nella directory corrente:

 find . -type f -exec grep -c -P -n "[\x00-\x08\x0E-\x1F\x80-\xFF]" {} + 

Potresti voler regolare il grep a volte. es. BS (0x08 – backspace) char usato in alcuni file stampabili o per escludere VT (0x0B – tab verticale). I caratteri BEL (0x07) e ESC (0x1B) possono anche essere considerati stampabili in alcuni casi.

 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 

Potrebbe essere interessante sapere come cercare un carattere unicode. Questo comando può aiutare. Hai solo bisogno di conoscere il codice in UTF8

 grep -v $'\u200d'