Bagaimana menemukan penyandian file melalui skrip di Linux?

303

Saya perlu menemukan penyandian semua file yang ditempatkan di direktori. Apakah ada cara untuk menemukan pengkodean yang digunakan?

The fileperintah ini tidak dapat melakukan hal ini.

Pengkodean yang menarik bagi saya adalah: ISO-8859-1. Jika penyandiannya adalah hal lain, saya ingin memindahkan file ke direktori lain.

Manglu
sumber
1
Jika Anda memiliki gagasan tentang jenis bahasa scripting apa yang mungkin ingin Anda gunakan, beri tag pertanyaan Anda dengan nama bahasa itu. Itu mungkin membantu ...
MatrixFrog
1
Atau mungkin dia hanya mencoba membuat skrip shell?
Shalom Craimer
1
Yang akan menjadi jawaban untuk "bahasa scripting yang".
bignose
7
Mungkin tidak terkait dengan jawaban ini, tetapi tip secara umum: Ketika Anda dapat menggambarkan seluruh keraguan Anda dalam satu kata ("encoding", di sini), lakukan saja apropos encoding. Itu mencari judul dan deskripsi dari semua halaman buku. Ketika saya melakukan ini pada mesin saya, saya melihat 3 alat yang bisa membantu saya, dilihat deskripsi mereka: chardet, chardet3, chardetect3. Kemudian, dengan melakukan man chardetdan membaca halaman manual memberitahu saya bahwa chardetitu hanya utilitas yang saya butuhkan.
John Red
1
Pengkodean mungkin berubah ketika Anda mengubah konten file. misalnya In vi, ketika menulis program c sederhana, itu mungkin us-ascii, tetapi setelah menambahkan baris komentar bahasa Mandarin, itu menjadi utf-8. filedapat mengetahui penyandian dengan membaca konten file & tebak.
Eric Wang

Jawaban:

419

Sepertinya Anda sedang mencari enca. Itu bisa menebak dan bahkan mengkonversi antar pengkodean. Lihat saja halaman manualnya .

Atau, jika gagal, gunakan file -i(linux) atau file -I(osx). Itu akan menampilkan informasi tipe MIME untuk file, yang juga akan mencakup pengkodean karakter-set. Saya menemukan halaman manual untuk itu juga :)

Shalom Craimer
sumber
1
Menurut halaman manual, ia tahu tentang set ISO 8559. Mungkin membaca sedikit kurang
cursorily
5
Enca terdengar menarik. Sayangnya deteksi tampaknya sangat tergantung pada bahasa dan rangkaian bahasa yang didukung tidak terlalu besar.
Milik
1
Pos yang bagus pada alat-alat seperti enca, enconv, convmv
GuruM
6
encatampaknya sama sekali tidak berguna untuk menganalisis file yang ditulis dalam bahasa Inggris, tetapi jika Anda kebetulan melihat sesuatu dalam bahasa Estonia, itu mungkin menyelesaikan semua masalah Anda. Alat yang sangat membantu, itu ... </
sarcasm
6
@vladkras jika tidak ada karakter non-ascii di file utf-8 Anda, maka itu tidak dapat dibedakan dari ascii :)
vadipp
85
file -bi <file name>

Jika Anda suka melakukan ini untuk banyak file

for f in `find | egrep -v Eliminate`; do echo "$f" ' -- ' `file -bi "$f"` ; done
madu
sumber
Namun, jika file tersebut adalah file xml, dengan atribut "encoding = 'iso-8859-1' dalam deklarasi xml, perintah file akan mengatakan itu adalah file iso, bahkan jika pengkodean yang sebenarnya adalah utf-8 ...
Per
6
Mengapa Anda menggunakan argumen -b? Jika Anda hanya melakukan file -i * itu menghasilkan charset yang ditebak untuk setiap file.
Hans-Peter Störr
4
Saya ingin tahu tentang argumen -b juga. Halaman manual mengatakan itu berarti "singkat"Do not prepend filenames to output lines
craq
1
Tidak perlu mengurai output file, file -b --mime-encodinghanya output pengkodean charset
jesjimher
-b adalah singkatan dari 'be brief' yang pada dasarnya berarti tidak menampilkan nama file yang baru saja Anda berikan.
Nikos
36

uchardet - Pustaka detektor pengkodean porting dari Mozilla.

Pemakaian:

~> uchardet file.java 
UTF-8

Berbagai distribusi Linux (Debian / Ubuntu, OpenSuse-packman, ...) menyediakan binari.

qwert2003
sumber
1
Terima kasih! Saya tidak senang dengan paket yang lebih banyak lagi, namun sudo apt-get install uchardetbegitu mudahnya sehingga saya memutuskan untuk tidak khawatir tentang hal itu ...
bijak
Seperti yang baru saja saya katakan dalam komentar di atas: uchardet palsu memberi tahu saya bahwa penyandian file adalah "windows-1252", meskipun saya secara eksplisit menyimpan file itu sebagai UTF-8. uchardet bahkan tidak mengatakan "dengan keyakinan 0.4641618497109827" yang setidaknya akan memberi Anda petunjuk bahwa itu memberitahu Anda omong kosong. File, enca dan encguess bekerja dengan benar.
Algoman
uchardetmemiliki kelebihan yang besar filedan enca, dalam hal ini menganalisis seluruh file (hanya mencoba dengan file 20GiB) sebagai lawan hanya awal.
tuxayo
10

di sini adalah contoh skrip menggunakan file -I dan iconv yang berfungsi di MacOsX Untuk pertanyaan Anda, Anda perlu menggunakan mv, bukan 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
Wolfgang Fahl
sumber
6
file -b --mime-encodinghanya menghasilkan charset, sehingga Anda dapat menghindari semua pemrosesan pipa
jesjimher
1
Terima kasih. Seperti yang ditunjukkan pada MacOS ini tidak akan berfungsi: file -b --mime-encoding ] file ... file -c -m magicfiles Coba `file --help 'untuk informasi lebih lanjut.
Wolfgang Fahl
6

Sangat sulit untuk menentukan apakah itu iso-8859-1. Jika Anda memiliki teks dengan karakter hanya 7 bit yang juga bisa iso-8859-1 tetapi Anda tidak tahu. Jika Anda memiliki 8 bit karakter maka karakter wilayah atas juga ada dalam penyandian urutan. Oleh karena itu Anda harus menggunakan kamus untuk mendapatkan tebakan yang lebih baik dari kata mana dan menentukan dari mana huruf itu harus. Akhirnya jika Anda mendeteksi bahwa itu mungkin utf-8 daripada Anda yakin itu bukan iso-8859-1

Pengkodean adalah salah satu hal tersulit untuk dilakukan karena Anda tidak pernah tahu jika tidak ada yang memberi tahu Anda

Norbert Hartl
sumber
Mungkin membantu untuk mencoba bersikap kasar. Perintah berikut akan mencoba untuk mengkonversi dari semua format ecncoding dengan nama yang dimulai dengan WIN atau ISO ke UTF8. Maka orang perlu memeriksa secara manual output mencari petunjuk ke pengkodean yang tepat. Tentu saja, Anda dapat mengubah format yang difilter menggantikan ISO atau WIN untuk sesuatu yang sesuai atau menghapus filter dengan menghapus perintah grep. untuk i in $ (iconv -l | tail -n +2 | grep "(^ ISO \ | ^ MENANG)" | sed -e 's / \ / \ ///'); lakukan echo $ i; iconv -f $ i -t UTF8 santos; dilakukan;
ndvo
5

Di Debian Anda juga dapat menggunakan encguess::

$ encguess test.txt
test.txt  US-ASCII
not2qubit
sumber
Saya menginstal uchardetdi Ubuntu dan memberitahu saya bahwa file saya WINDOWS-1252. Saya tahu ini salah karena saya menyimpannya sebagai UTF-16 dengan Kate, untuk diuji. Namun, encguesstebak dengan benar, dan sudah diinstal sebelumnya di Ubuntu 19.04.
Nagev
5

Untuk mengonversi pengkodean dari 8859 ke ASCII:

iconv -f ISO_8859-1 -t ASCII filename.txt
fimbulwinter
sumber
4

Dengan Python, Anda dapat menggunakan modul chardet: https://github.com/chardet/chardet

fccoelho
sumber
Domain tidak ada: feedparser.org
Rune
Pada komentar ini, itu masih tersedia di Github: github.com/dcramer/chardet
Rick Hanlon II
Pada komentar ini, ada di chardet / chardet di github. Jawaban yang diperbarui.
Quentin Pradet
laporan chardet "Tidak Ada", chardet3 tersedak pada baris pertama file dengan cara yang sama persis seperti yang dilakukan skrip python saya.
Joels Elf
3

Ini bukan sesuatu yang bisa Anda lakukan dengan cara yang sangat mudah. Satu kemungkinan adalah untuk memeriksa setiap karakter dalam file untuk memastikan bahwa itu tidak mengandung karakter apa pun dalam rentang 0x00 - 0x1fatau 0x7f -0x9ftetapi, seperti yang saya katakan, ini mungkin benar untuk sejumlah file, termasuk setidaknya satu varian lain dari ISO8859.

Kemungkinan lain adalah mencari kata-kata spesifik dalam file dalam semua bahasa yang didukung dan melihat apakah Anda dapat menemukannya.

Jadi, misalnya, temukan padanan dari bahasa Inggris "dan", "tetapi", "ke", "dari" dan seterusnya dalam semua bahasa yang didukung 8859-1 dan lihat apakah mereka memiliki banyak kemunculan dalam mengajukan.

Saya tidak berbicara tentang terjemahan literal seperti:

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

walaupun itu mungkin. Saya berbicara tentang kata-kata umum dalam bahasa target (yang saya tahu, bahasa Islandia tidak memiliki kata untuk "dan" - Anda mungkin harus menggunakan kata mereka untuk "ikan" [maaf itu agak stereotip, saya tidak berarti pelanggaran apa pun, hanya menggambarkan suatu poin]).

paxdiablo
sumber
2

Saya tahu Anda tertarik pada jawaban yang lebih umum, tetapi apa yang baik dalam ASCII biasanya baik dalam pengkodean lainnya. Berikut ini adalah satu-baris Python untuk menentukan apakah input standar adalah ASCII. (Saya cukup yakin ini berfungsi di Python 2, tapi saya baru mengujinya di 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
wkschwartz
sumber
2

Jika Anda berbicara tentang file XML (ISO-8859-1), deklarasi XML di dalamnya menentukan pengkodean: <?xml version="1.0" encoding="ISO-8859-1" ?>
Jadi, Anda dapat menggunakan ekspresi reguler (misalnya dengan perl) untuk memeriksa setiap file untuk spesifikasi tersebut.
Informasi lebih lanjut dapat ditemukan di sini: Cara Menentukan Encoding File Teks .

evgeny9
sumber
nah baris itu bisa disalin-n-ditempel oleh seseorang yang tidak tahu pengkodean apa yang dia gunakan.
Algoman
Kata hati-hati, tidak ada tentang deklarasi di atas menjamin file SEBENARNYA disandikan seperti itu. Jika Anda benar-benar peduli dengan pengkodean, Anda harus memvalidasinya sendiri.
Jazzepi
2

Di php Anda dapat memeriksa seperti di bawah ini:

Menentukan daftar penyandian secara eksplisit:

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" lebih akurat:

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

Di sini, dalam contoh pertama, Anda dapat melihat bahwa saya meletakkan daftar penyandian (deteksi urutan daftar) yang mungkin cocok. Untuk mendapatkan hasil yang lebih akurat, Anda dapat menggunakan semua kemungkinan penyandian melalui: mb_list_encodings ()

Catatan fungsi mb_ * membutuhkan php-mbstring

apt-get install php-mbstring
Mohamed23gharbi
sumber
0

Di Cygwin, ini sepertinya bekerja untuk saya:

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

Contoh:

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

Anda dapat menyalurkannya ke awk dan membuat perintah ikonv untuk mengonversi semuanya menjadi utf8, dari pengodean sumber apa pun yang didukung oleh ikonv.

Contoh:

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
skeetastax
sumber
0

Anda dapat mengekstrak penyandian satu file dengan perintah file. Saya memiliki file sample.html dengan:

$ file sample.html 

sample.html: Dokumen HTML, teks Unicode UTF-8, dengan garis yang sangat panjang

$ file -b sample.html

Dokumen HTML, teks UTF-8 Unicode, dengan garis yang sangat panjang

$ file -bi sample.html

teks / html; charset = utf-8

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

utf-8

Daniel Faure
sumber
1
output yang saya dapatkan hanyalah "file biasa"
Mordechai
0

Saya menggunakan skrip berikut untuk

  1. Temukan semua file yang cocok dengan FILTER dengan SRC_ENCODING
  2. Buat cadangannya
  3. Konversikan ke DST_ENCODING
  4. (opsional) Hapus cadangan

.

#!/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 {} \;
Matya
sumber
0

dengan perintah ini:

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

Anda dapat membuat daftar semua file dalam direktori dan subdirektori dan encoding yang sesuai.

danilo
sumber
-2

Dengan Perl, gunakan Encode :: Detect.

manu_v
sumber
7
Bisakah Anda memberi contoh cara menggunakannya di shell?
Lri
Poster lain (@fccoelho) menyediakan modul Python sebagai solusi yang mendapat +3 dan poster ini mendapat -2 untuk jawaban yang sangat mirip kecuali untuk modul Perl. Mengapa standar ganda ?!
Happy Green Kid Naps
4
Mungkin contoh kode perl one-liner akan membantu jawaban ini.
vikingsteve