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.