Come trovare la codifica di un file tramite script su Linux?


303

Devo trovare la codifica di tutti i file inseriti in una directory. C'è un modo per trovare la codifica utilizzata?

Il filecomando non è in grado di farlo.

La codifica che mi interessa è: ISO-8859-1. Se la codifica è qualcos'altro, voglio spostare il file in un'altra directory.


1
Se hai un'idea del tipo di linguaggio di script che potresti voler usare, tagga la tua domanda con il nome di quella lingua. Ciò potrebbe aiutare ...
— MatrixFrog il

1
O forse sta solo cercando di creare uno script di shell?
— Shalom Craimer,

1
Quale sarebbe una risposta a "quale linguaggio di scripting".
— bignose il

7
Forse non è correlato a questa risposta, ma un suggerimento in generale: quando puoi descrivere tutto il tuo dubbio in una parola ("codifica", qui), fallo apropos encoding. Cerca i titoli e le descrizioni di tutte le manpage. Quando faccio questo sulla mia macchina, vedo 3 strumenti che mi potrebbero aiutare, a giudicare dalle loro descrizioni: chardet, chardet3, chardetect3. Quindi, facendo man chardete leggendo la manpage mi dice che chardetè solo l'utilità di cui ho bisogno.
— John Red,

1
La codifica potrebbe cambiare quando si cambia il contenuto di un file. ad es. in vi, quando si scrive un semplice programma c, è probabilmente us-ascii, ma dopo aver aggiunto una riga di commento cinese, diventa utf-8. filepuò dire la codifica leggendo il contenuto del file e indovina.
— Eric Wang,

Risposte:


419

Sembra che tu stia cercando enca. Può indovinare e persino convertire tra codifiche. Guarda la pagina man .

Oppure, in mancanza, utilizzare file -i(linux) o file -I(osx). Ciò genererà informazioni di tipo MIME per il file, che includerà anche la codifica del set di caratteri. Ho trovato anche una man-page :)


1
Secondo la pagina man, conosce il set ISO 8559. Forse leggi un po 'meno in modo cursore :-)
— bignose il

5
Enca sembra interessante. Sfortunatamente il rilevamento sembra essere molto dipendente dalla lingua e l'insieme delle lingue supportate non è molto grande. Il mio (de) è mancante :-( Comunque
— ottimo

1
Buon post su strumenti come enca, enconv, convmv
— GuruM

6
encasembra essere completamente inutile per analizzare un file scritto in inglese, ma se ti capita di guardare qualcosa in estone, potrebbe risolvere tutti i tuoi problemi. Strumento molto utile, che ... </
— sarcasm

6
@vladkras se non ci sono caratteri non ascii nel tuo file utf-8, allora è indistinguibile da ascii :)
— vadipp

85
file -bi <file name>

Se ti piace farlo per un mucchio di file

for f in `find | egrep -v Eliminate`; do echo "$f" ' -- ' `file -bi "$f"` ; done

Tuttavia, se il file è un file xml, con l'attributo "encoding = 'iso-8859-1' nella dichiarazione xml, il comando file dirà che si tratta di un file iso, anche se la vera codifica è utf-8 ...
— Per

6
Perché usi l'argomento -b? Se si esegue semplicemente il file -i *, viene emesso il set di caratteri indovinato per ogni file.
— Hans-Peter Störr,

4
Ero curioso anche dell'argomento -b. La pagina man dice che significa "breve"Do not prepend filenames to output lines
— craq

1
Non è necessario analizzare l'output del file, file -b --mime-encodinggenera solo la codifica del set di caratteri
— jesjimher,

-b sta per 'essere breve', che in pratica significa non produrre il nome del file che hai appena dato.
— Nikos

36

uchardet - Una libreria di rivelatori di codifica portata da Mozilla.

Uso:

~> uchardet file.java 
UTF-8

Varie distribuzioni Linux (Debian / Ubuntu, OpenSuse-packman, ...) forniscono binari.


1
Grazie! Non sono contento di altri pacchetti, ma sudo apt-get install uchardetè così facile che ho deciso di non preoccuparmene ...
— saggio

Come ho appena detto in un commento sopra: uchardet mi dice erroneamente che la codifica di un file era "windows-1252", anche se ho salvato esplicitamente quel file come UTF-8. uchardet non dice nemmeno "con fiducia 0.4641618497109827" che almeno ti darebbe un suggerimento che ti sta dicendo completa assurdità. file, enca e encguess funzionavano correttamente.
— Algoman

uchardetha un grande vantaggio filee enca, in quanto analizza l'intero file (appena provato con un file 20GiB) al contrario solo all'inizio.
— tuxayo,

10

ecco uno script di esempio che utilizza il file -I e iconv che funziona su MacOsX Per la tua domanda devi usare mv invece di iconv

#!/bin/bash
# 2016-02-08
# check encoding and convert files
for f in *.java
do
  encoding=`file -I $f | cut -f 2 -d";" | cut -f 2 -d=`
  case $encoding in
    iso-8859-1)
    iconv -f iso8859-1 -t utf-8 $f > $f.utf8
    mv $f.utf8 $f
    ;;
  esac
done

6
file -b --mime-encodinggenera solo il set di caratteri, in modo da poter evitare tutta l'elaborazione del tubo
— jesjimher,

1
Grazie. Come sottolineato su MacOS, questo non funzionerà: file -b --mime-encoding Uso: file [-bchikLNnprsvz0] [-e test] [-f namefile] [-F separator] [-m magicfiles] [-M magicfiles ] file ... file -C -m file magici Prova `file --help 'per ulteriori informazioni.
— Wolfgang Fahl,

6

È davvero difficile determinare se è iso-8859-1. Se hai un testo con soli caratteri a 7 bit che potrebbe anche essere iso-8859-1 ma non lo sai. Se si dispone di caratteri a 8 bit, esistono anche i caratteri della regione superiore anche nelle codifiche dell'ordine. Quindi dovresti usare un dizionario per capire meglio quale parola sia e determinare da lì quale lettera deve essere. Infine, se rilevi che potrebbe essere utf-8 di quanto sei sicuro che non sia iso-8859-1

La codifica è una delle cose più difficili da fare perché non si sa mai se nulla ti sta dicendo


Potrebbe essere utile provare a forzare la forza. Il seguente comando proverà a convertire da tutti i formati di codifica elettronica con nomi che iniziano con WIN o ISO in UTF8. Quindi si dovrebbe controllare manualmente l'output alla ricerca di un indizio nella codifica corretta. Ovviamente, puoi cambiare i formati filtrati sostituendo ISO o WIN per qualcosa di appropriato o rimuovere il filtro rimuovendo il comando grep. per i in $ (iconv -l | tail -n +2 | grep "(^ ISO \ | ^ WIN)" | sed -e 's / \ / \ ///'); fare l'eco $ i; iconv -f $ i -t UTF8 santos; fatto;
— ndvo,

5

In Debian puoi anche usare encguess::

$ encguess test.txt
test.txt  US-ASCII

Ho installato uchardetin Ubuntu e mi ha detto che il mio file era WINDOWS-1252. So che era sbagliato perché l'ho salvato come UTF-16 con Kate, per testarlo. Tuttavia, encguessindovina correttamente ed è stato preinstallato in Ubuntu 19.04.
— Nagev,

5

Per convertire la codifica da 8859 a ASCII:

iconv -f ISO_8859-1 -t ASCII filename.txt


3

Questo non è qualcosa che puoi fare in modo infallibile. Una possibilità sarebbe quella di esaminare tutti i caratteri nel file per assicurarsi che non contenga caratteri negli intervalli 0x00 - 0x1fo 0x7f -0x9f, come ho già detto, questo può essere vero per qualsiasi numero di file, inclusa almeno un'altra variante di ISO8859.

Un'altra possibilità è cercare parole specifiche nel file in tutte le lingue supportate e vedere se riesci a trovarle.

Quindi, ad esempio, trova l'equivalente dell'inglese "e", "ma", "a", "di" e così via in tutte le lingue supportate di 8859-1 e vedi se hanno un gran numero di occorrenze all'interno del file.

Non sto parlando di traduzione letterale come:

English   French
-------   ------
of        de, du
and       et
the       le, la, les

sebbene sia possibile. Sto parlando di parole comuni nella lingua di destinazione (per quanto ne so, l'islandese non ha parole per "e" - probabilmente dovresti usare la loro parola per "pesce" [mi dispiace che sia un po 'stereotipato, non l'ho fatto significa qualsiasi offesa, solo illustrando un punto]).


2

So che sei interessato a una risposta più generale, ma ciò che è buono in ASCII di solito è buono in altre codifiche. Ecco un one-liner Python per determinare se l'input standard è ASCII. (Sono abbastanza sicuro che funzioni in Python 2, ma l'ho provato solo su Python 3.)

python -c 'from sys import exit,stdin;exit()if 128>max(c for l in open(stdin.fileno(),"b") for c in l) else exit("Not ASCII")' < myfile.txt

2

Se stai parlando di file XML (ISO-8859-1), la dichiarazione XML al loro interno specifica la codifica: <?xml version="1.0" encoding="ISO-8859-1" ?>
Quindi, puoi usare espressioni regolari (ad es. Con perl) per controllare ogni file per tale specifica.
Ulteriori informazioni sono disponibili qui: Come determinare la codifica dei file di testo .


bene quella linea potrebbe essere copiata e incollata da qualcuno che non sa quale codifica sta usando.
— Algoman

Un avvertimento, nulla sulla dichiarazione in alto garantisce che il file sia REALMENTE codificato in questo modo. Se davvero ti interessa davvero la codifica, devi convalidarla tu stesso.
— Jazzepi,

2

In php puoi controllare come di seguito:

Specificare esplicitamente l'elenco di codifica:

php -r "echo 'probably : ' . mb_detect_encoding(file_get_contents('myfile.txt'), 'UTF-8, ASCII, JIS, EUC-JP, SJIS, iso-8859-1') . PHP_EOL;"

"Mb_list_encodings" più accurati:

php -r "echo 'probably : ' . mb_detect_encoding(file_get_contents('myfile.txt'), mb_list_encodings()) . PHP_EOL;"

Qui nel primo esempio, puoi vedere che ho messo un elenco di codifiche (rileva l'ordine delle liste) che potrebbero corrispondere. Per ottenere risultati più precisi è possibile utilizzare tutte le codifiche possibili tramite: mb_list_encodings ()

Nota le funzioni mb_ * richiedono php-mbstring

apt-get install php-mbstring

0

In Cygwin, sembra che funzioni per me:

find -type f -name "<FILENAME_GLOB>" | while read <VAR>; do (file -i "$<VAR>"); done

Esempio:

find -type f -name "*.txt" | while read file; do (file -i "$file"); done

Potresti reindirizzarlo in awk e creare un comando iconv per convertire tutto in utf8, da qualsiasi codifica sorgente supportata da iconv.

Esempio:

find -type f -name "*.txt" | while read file; do (file -i "$file"); done | awk -F[:=] '{print "iconv -f "$3" -t utf8 \""$1"\" > \""$1"_utf8\""}' | bash

0

È possibile estrarre la codifica di un singolo file con il comando file. Ho un file sample.html con:

$ file sample.html 

sample.html: documento HTML, testo Unicode UTF-8, con righe molto lunghe

$ file -b sample.html

Documento HTML, testo Unicode UTF-8, con righe molto lunghe

$ file -bi sample.html

text / html; charset = utf-8

$ file -bi sample.html  | awk -F'=' '{print $2 }'

utf-8


1
l'output che ottengo è solo "file normale"
— Mordechai

0

Sto usando il seguente script per

  1. Trova tutti i file che corrispondono a FILTER con SRC_ENCODING
  2. Creane una copia di backup
  3. Convertili in DST_ENCODING
  4. (opzionale) Rimuovere i backup

.

#!/bin/bash -xe

SRC_ENCODING="iso-8859-1"
DST_ENCODING="utf-8"
FILTER="*.java"

echo "Find all files that match the encoding $SRC_ENCODING and filter $FILTER"
FOUND_FILES=$(find . -iname "$FILTER" -exec file -i {} \; | grep "$SRC_ENCODING" | grep -Eo '^.*\.java')

for FILE in $FOUND_FILES ; do
    ORIGINAL_FILE="$FILE.$SRC_ENCODING.bkp"
    echo "Backup original file to $ORIGINAL_FILE"
    mv "$FILE" "$ORIGINAL_FILE"

    echo "converting $FILE from $SRC_ENCODING to $DST_ENCODING"
    iconv -f "$SRC_ENCODING" -t "$DST_ENCODING" "$ORIGINAL_FILE" -o "$FILE"
done

echo "Deleting backups"
find . -iname "*.$SRC_ENCODING.bkp" -exec rm {} \;

0

con questo comando:

for f in `find .`; do echo `file -i "$f"`; done

puoi elencare tutti i file in una directory e le sottodirectory e la codifica corrispondente.


-2

Con Perl, utilizzare Encode :: Detect.


7
Puoi fare un esempio su come usarlo nella shell?
— Lri,

Un altro poster (@fccoelho) ha fornito un modulo Python come soluzione che ottiene un +3 e questo poster ottiene un -2 per una risposta molto simile tranne che è per un modulo Perl. Perché il doppio standard ?!
— Happy Green Kid Naps,

4
Forse un esempio di codice di un one-liner perl aiuterebbe questa risposta.
— vikingsteve,
Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.