จะค้นหาการเข้ารหัสไฟล์ผ่านสคริปต์บน Linux ได้อย่างไร


303

ฉันต้องการค้นหาการเข้ารหัสของไฟล์ทั้งหมดที่อยู่ในไดเรกทอรี มีวิธีหาการเข้ารหัสที่ใช้หรือไม่

fileคำสั่งจะไม่สามารถที่จะทำเช่นนี้

การเข้ารหัสที่ฉันสนใจคือ: ISO-8859-1 หากการเข้ารหัสเป็นอย่างอื่นฉันต้องการย้ายไฟล์ไปยังไดเรกทอรีอื่น


1
หากคุณมีความคิดเกี่ยวกับภาษาสคริปต์ชนิดใดที่คุณอาจต้องการใช้ให้ติดแท็กคำถามของคุณด้วยชื่อของภาษานั้น ที่อาจช่วยให้ ...
MatrixFrog

1
หรือบางทีเขาแค่พยายามสร้างเชลล์สคริปต์
Shalom Craimer

1
ซึ่งจะเป็นคำตอบสำหรับ“ ภาษาสคริปต์ใด”
bignose

7
อาจจะไม่เกี่ยวข้องกับคำตอบนี้ แต่ปลายทั่วไป: เมื่อคุณสามารถอธิบายข้อสงสัยของคุณทั้งหมดในหนึ่งคำ ( "เข้ารหัส" ที่นี่) apropos encodingเพียงแค่ทำ มันค้นหาชื่อและคำอธิบายของ manpages ทั้งหมด เมื่อผมทำเช่นนี้ในเครื่องของฉันฉันเห็น 3 เครื่องมือที่อาจช่วยฉันตัดสินโดยคำอธิบายของพวกเขาchardet, ,chardet3 chardetect3จากนั้นโดยการทำman chardetและอ่าน manpage บอกฉันว่าchardetเป็นเพียงยูทิลิตี้ที่ฉันต้องการ
John Red

1
การเข้ารหัสอาจเปลี่ยนแปลงเมื่อคุณเปลี่ยนเนื้อหาของไฟล์ เช่นใน vi เมื่อเขียนโปรแกรม C ง่ายก็อาจจะแต่หลังจากเพิ่มบรรทัดของความคิดเห็นจีนมันจะกลายเป็นus-ascii สามารถบอกการเข้ารหัสได้โดยอ่านเนื้อหาไฟล์ & เดา utf-8file
Eric Wang

คำตอบ:


419

encaเสียงเหมือนคุณกำลังมองหา สามารถคาดเดาและแปลงระหว่างการเข้ารหัสได้ เพียงแค่ดูที่หน้าคน

หรือล้มเหลวนั้นใช้file -i(linux) หรือfile -I(osx) นั่นจะส่งข้อมูลประเภท MIME สำหรับไฟล์ซึ่งจะรวมถึงการเข้ารหัสชุดอักขระ ฉันพบman-pageสำหรับมันเช่นกัน :)


1
จากหน้า man page มันรู้เกี่ยวกับชุด ISO 8559 บางทีอ่านน้อยน้อยเผินๆ :-)
bignose

5
Enca ฟังดูน่าสนใจ น่าเสียดายที่การตรวจจับดูเหมือนจะขึ้นอยู่กับภาษามากและชุดของภาษาที่รองรับไม่ใหญ่มาก Mine (de) หายไป :-( เครื่องมือเจ๋ง ๆ
อยู่ดี

1
โพสต์ที่ดีเกี่ยวกับเครื่องมือเช่นenca, enconv, convmv
GuruM

6
encaดูเหมือนจะไร้ประโยชน์อย่างสมบูรณ์สำหรับการวิเคราะห์ไฟล์ที่เขียนด้วยภาษาอังกฤษ แต่ถ้าคุณบังเอิญมองบางอย่างเป็นภาษาเอสโทเนียอาจช่วยแก้ปัญหาทั้งหมดของคุณได้ เครื่องมือที่มีประโยชน์มากนั่นคือ ... </
sarcasm

6
@vladkras หากไม่มีตัวอักษรที่ไม่ใช่ ASCII ในไฟล์ utf-8 ของคุณดังนั้นจะแยกไม่ออกจาก ascii :)
vadipp

85
file -bi <file name>

หากคุณต้องการทำสิ่งนี้เพื่อกลุ่มไฟล์

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

อย่างไรก็ตามหากไฟล์นั้นเป็นไฟล์ xml โดยมีแอตทริบิวต์ "encoding = 'iso-8859-1' ในการประกาศ xml คำสั่ง file จะบอกว่าเป็นไฟล์ iso แม้ว่าการเข้ารหัสที่แท้จริงคือ utf-8 ...
ต่อ

6
ทำไมคุณถึงใช้อาร์กิวเมนต์ -b หากคุณเพิ่งทำไฟล์ -i * มันจะส่งออกชุดอักขระที่เดาได้สำหรับทุกไฟล์
Hans-Peter Störr

4
ฉันอยากรู้เกี่ยวกับอาร์กิวเมนต์ -b ด้วย หน้าคนบอกว่ามันหมายถึง "สั้น"Do not prepend filenames to output lines
craq

1
ไม่จำเป็นต้องแยกวิเคราะห์ไฟล์ที่ส่งออกfile -b --mime-encodingเอาท์พุทเพียงแค่การเข้ารหัสตัวอักษร
jesjimher

-b ย่อมาจาก 'be brief' ซึ่งโดยทั่วไปหมายความว่าอย่าส่งชื่อไฟล์ที่คุณเพิ่งให้
Nikos

36

uchardet - ไลบรารีตัวตรวจจับการเข้ารหัสที่พอร์ตจาก Mozilla

การใช้งาน:

~> uchardet file.java 
UTF-8

ลีนุกซ์รุ่นต่าง ๆ (Debian / Ubuntu, OpenSuse-packman, ... ) จัดเตรียมไบนารี


1
ขอบคุณ! ฉันไม่พอใจเกี่ยวกับแพคเกจเพิ่มเติมยังsudo apt-get install uchardetเป็นเรื่องง่ายมากที่ฉันตัดสินใจที่จะไม่กังวลเกี่ยวกับมัน ...
ปราชญ์

ตามที่ฉันเพิ่งพูดในความคิดเห็นด้านบน: uchardet บอกฉันว่าการเข้ารหัสไฟล์เป็น "windows-1252" อย่างไม่เป็นทางการถึงแม้ว่าฉันจะบันทึกไฟล์นั้นอย่างชัดเจนในรูปแบบ UTF-8 uchardet ไม่แม้แต่จะพูดว่า "ด้วยความมั่นใจ 0.4641618497109827" ซึ่งอย่างน้อยก็ทำให้คุณมีคำใบ้ว่ามันบอกคุณเรื่องไร้สาระสมบูรณ์ ไฟล์, enca และ encguess ทำงานอย่างถูกต้อง
Algoman

uchardetมีข้อได้เปรียบมากกว่าfileและencaในการวิเคราะห์ไฟล์ทั้งหมด (ลองด้วยไฟล์ 20GiB) ซึ่งต่างจากการเริ่มต้นเท่านั้น
tuxayo

10

นี่คือตัวอย่างสคริปต์โดยใช้ไฟล์ -I และ iconv ซึ่งทำงานบน MacOsX สำหรับคำถามของคุณคุณต้องใช้ mv แทน 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-encodingเอาต์พุตเพียงชุดอักขระดังนั้นคุณสามารถหลีกเลี่ยงการประมวลผลไปป์ทั้งหมด
jesjimher

1
ขอบคุณ. ดังที่อธิบายไว้ใน MacOS สิ่งนี้จะใช้งานไม่ได้: ไฟล์ -b - การเข้ารหัสแบบไมม์: ไฟล์ [-bchikLNnprsvz0] [-e test] [-f namefile] [-F ตัวคั่น] [-m magicfiles] [-M magicfiles ] file ... ไฟล์ -C -m magicfiles ลอง `file --help 'สำหรับข้อมูลเพิ่มเติม
Wolfgang Fahl

6

เป็นการยากที่จะตรวจสอบว่าเป็น iso-8859-1 หากคุณมีข้อความที่มีอักขระเพียง 7 บิตที่อาจเป็น iso-8859-1 แต่คุณไม่รู้ หากคุณมีอักขระ 8 บิตแสดงว่าอักขระภูมิภาคด้านบนมีการเข้ารหัสตามลำดับเช่นกัน ดังนั้นคุณจะต้องใช้พจนานุกรมเพื่อเดาคำที่ดีกว่าและกำหนดจากที่นั่นต้องใช้ตัวอักษรใด ในที่สุดหากคุณตรวจพบว่ามันอาจเป็น utf-8 กว่าคุณแน่ใจว่าไม่ใช่ iso-8859-1

การเข้ารหัสเป็นสิ่งที่ยากที่สุดที่ต้องทำเพราะคุณไม่มีทางรู้ว่าไม่มีอะไรบอกคุณ


มันอาจช่วยให้พยายามดุร้ายกำลัง คำสั่งต่อไปนี้จะพยายามแปลงจากทุกรูปแบบ ecncoding ด้วยชื่อที่ขึ้นต้นด้วย WIN หรือ ISO เป็น UTF8 จากนั้นจะต้องตรวจสอบผลลัพธ์ด้วยตนเองเพื่อค้นหาเบาะแสในการเข้ารหัสที่ถูกต้อง แน่นอนคุณสามารถเปลี่ยนรูปแบบที่กรองแทนที่ ISO หรือ WIN สำหรับสิ่งที่เหมาะสมหรือลบตัวกรองโดยการลบคำสั่ง grep สำหรับฉันใน $ (iconv -l | tail -n +2 | grep "(^ ISO \ | ^ WIN)" | sed -e 's / \ / \ ///'); ทำเสียงก้อง $ i; iconv -f $ i -t UTF8 santos; ทำ;
ndvo

5

ใน Debian คุณสามารถใช้encguess:

$ encguess test.txt
test.txt  US-ASCII

ผมติดตั้งuchardetใน Ubuntu WINDOWS-1252และมันบอกว่าไฟล์ของฉันคือ ฉันรู้ว่ามันผิดเพราะฉันบันทึกเป็น UTF-16 กับ Kate เพื่อทำการทดสอบ อย่างไรก็ตามencguessคาดเดาอย่างถูกต้องและติดตั้งล่วงหน้าใน Ubuntu 19.04
Nagev


4

ด้วย Python คุณสามารถใช้โมดูล chardet: https://github.com/chardet/chardet


โดเมนที่ไม่มีอยู่: feedparser.org
Rune

ในฐานะที่เป็นความคิดเห็นนี้ก็ยังคงมีอยู่ใน Github: github.com/dcramer/chardet
Rick Hanlon II

จากความคิดเห็นนี้มันอยู่ใน chardet / chardet บน github อัปเดตคำตอบ
Quentin Pradet

รายงาน chardet "ไม่มี" ฉายา chardet3 ในบรรทัดแรกของไฟล์ในที่แน่นอนเช่นเดียวกับที่สคริปต์หลามของฉันไม่
Joels Elf

3

นี่ไม่ใช่สิ่งที่คุณสามารถทำได้ในทางที่จะเข้าใจผิด ความเป็นไปได้อย่างหนึ่งคือการตรวจสอบตัวละครทุกตัวในไฟล์เพื่อให้แน่ใจว่าไม่มีตัวอักษรใด ๆ อยู่ในช่วง0x00 - 0x1fหรือ0x7f -0x9fตามที่ฉันได้กล่าวมาสิ่งนี้อาจเป็นจริงสำหรับไฟล์จำนวนเท่าใดก็ได้

ความเป็นไปได้อีกอย่างหนึ่งคือการค้นหาคำเฉพาะในไฟล์ในทุกภาษาที่รองรับและดูว่าคุณสามารถค้นหา

ตัวอย่างเช่นค้นหาเทียบเท่าภาษาอังกฤษ "และ", "แต่", "ถึง", "ของ" และอื่น ๆ ในภาษาที่รองรับทั้งหมดของ 8859-1 และดูว่าพวกเขามีเหตุการณ์จำนวนมากภายใน ไฟล์.

ฉันไม่ได้พูดถึงการแปลตามตัวอักษรเช่น:

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

แม้ว่าจะเป็นไปได้ ฉันกำลังพูดถึงคำทั่วไปในภาษาเป้าหมาย (สำหรับทุกอย่างที่ฉันรู้ไอซ์แลนด์ไม่มีคำว่า "และ" - คุณอาจต้องใช้คำของพวกเขาสำหรับ "ปลา" [ขอโทษที่มันเป็นโปรเฟสเซอร์เล็ก ๆ น้อย ๆ ฉันไม่ได้ หมายถึงความผิดใด ๆ เพียงแสดงจุด])


2

ฉันรู้ว่าคุณสนใจคำตอบทั่วไปมากขึ้น แต่สิ่งที่ดีใน ASCII มักจะดีในการเข้ารหัสอื่น ๆ นี่คือ Python หนึ่งบรรทัดเพื่อดูว่าอินพุตมาตรฐานเป็น ASCII หรือไม่ (ฉันค่อนข้างมั่นใจว่ามันใช้งานได้ใน Python 2 แต่ฉันเพิ่งทดสอบบน 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

หากคุณกำลังพูดถึงไฟล์ XML (ISO-8859-1) การประกาศ XML ภายในไฟล์นั้นจะระบุการเข้ารหัส: <?xml version="1.0" encoding="ISO-8859-1" ?>
ดังนั้นคุณสามารถใช้นิพจน์ทั่วไป (เช่นกับperl) เพื่อตรวจสอบทุกไฟล์สำหรับสเปคดังกล่าว
ข้อมูลเพิ่มเติมสามารถพบได้ที่นี่: วิธีการตรวจสอบการเข้ารหัสไฟล์ข้อความ


บรรทัดนั้นสามารถคัดลอกวางโดยคนที่ไม่ทราบว่าเขาใช้การเข้ารหัสอะไร
Algoman

คำเตือนไม่มีอะไรเกี่ยวกับการประกาศที่ด้านบนรับประกันว่าไฟล์จะถูกเข้ารหัสด้วยวิธีดังกล่าว ถ้าคุณสนใจการเข้ารหัสที่คุณต้องตรวจสอบด้วยตัวเอง
Jazzepi

2

ใน php คุณสามารถตรวจสอบได้ดังนี้:

การระบุรายการเข้ารหัสอย่างชัดเจน:

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" ที่แม่นยำยิ่งขึ้น:

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

ในตัวอย่างแรกคุณจะเห็นว่าฉันใส่รายการการเข้ารหัส (ตรวจจับลำดับรายการ) ที่อาจจับคู่ หากต้องการผลลัพธ์ที่แม่นยำยิ่งขึ้นคุณสามารถใช้การเข้ารหัสที่เป็นไปได้ทั้งหมดผ่าน: mb_list_encodings ()

หมายเหตุฟังก์ชัน mb_ * ต้องการ php-mbstring

apt-get install php-mbstring

0

ใน Cygwin สิ่งนี้ดูเหมือนจะใช้ได้กับฉัน:

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

ตัวอย่าง:

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

คุณสามารถไพพ์นั้นเพื่อ awk และสร้างคำสั่ง iconv เพื่อแปลงทุกอย่างเป็น utf8 จากการเข้ารหัสซอร์สที่สนับสนุนโดย iconv

ตัวอย่าง:

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

คุณสามารถแยกการเข้ารหัสไฟล์เดียวด้วยคำสั่ง file ฉันมีไฟล์ sample.html ด้วย:

$ file sample.html 

sample.html: เอกสาร HTML, ข้อความ Unicode UTF-8 ที่มีบรรทัดที่ยาวมาก

$ file -b sample.html

เอกสาร HTML, UTF-8 Unicode text มีบรรทัดที่ยาวมาก

$ file -bi sample.html

text / html; charset = UTF-8

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

UTF-8


1
ผลลัพธ์ที่ฉันได้รับคือ "ไฟล์ปกติ"
Mordechai

0

ฉันใช้สคริปต์ต่อไปนี้เพื่อ

  1. ค้นหาไฟล์ทั้งหมดที่ตรงกับ FILTER ด้วย SRC_ENCODING
  2. สร้างการสำรองข้อมูลของพวกเขา
  3. แปลงเป็น DST_ENCODING
  4. (ไม่บังคับ) ลบข้อมูลสำรอง

.

#!/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

ด้วยคำสั่งนี้:

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

คุณสามารถแสดงรายการไฟล์ทั้งหมดในไดเรกทอรีและไดเรกทอรีย่อยและการเข้ารหัสที่สอดคล้องกัน


-2

ด้วย Perl ให้ใช้ Encode :: Detect


7
คุณยกตัวอย่างวิธีใช้มันในเปลือกได้ไหม?
Lri

โปสเตอร์อื่น (@fccoelho) ให้โมดูล Python เป็นวิธีการแก้ปัญหาที่ได้รับ +3 และโปสเตอร์นี้ได้รับ -2 สำหรับคำตอบที่คล้ายกันมากยกเว้นว่ามันเป็นโมดูล Perl ทำไมต้องเป็นสองมาตรฐาน!
Happy Green Kid Naps

4
บางทีโค้ดตัวอย่างของ perl one-liner จะช่วยให้คำตอบนี้
vikingsteve
โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.