如何在Linux上通过脚本查找文件的编码?


303

我需要找到放置在目录中的所有文件的编码。有没有办法找到使用的编码?

file命令无法执行此操作。

我感兴趣的编码是:ISO-8859-1。如果编码是其他方式,我想将文件移到另一个目录。


1
如果您对可能要使用的脚本语言有所了解,请用该语言的名称标记问题。这可能会有所帮助...
MatrixFrog

1
还是他只是想构建一个shell脚本?
Shalom Craimer 2009年

1
这将是“哪种脚本语言”的答案。
bignose

7
可能与该答案无关,但总的来说是一个提示:当您可以用一个词来描述整个疑问时(此处为“ encoding”),只需执行即可apropos encoding。它搜索所有手册页的标题和描述。当我这样做我的机器上,我看到3点的工具,可以帮助我,通过他们的描述来看:chardetchardet3chardetect3。然后,通过man chardet阅读并阅读联机帮助页,可以告诉我这chardet只是我需要的实用程序。
约翰·雷德

1
更改文件内容时,编码可能会更改。例如在vi中,编写一个简单的c程序时可能是us-ascii,但是在添加了一行中文注释后,它变为utf-8file可以通过读取文件内容和猜测来判断编码。
Eric Wang

Answers:


419

听起来好像您在寻找enca。它可以猜测甚至转换编码。只看手册页

或者,如果失败,请使用file -i(linux)或file -I(osx)。这将输出文件的MIME类型信息,其中还将包括字符集编码。我也找到了手册页 :)


1
根据手册页,它了解ISO 8559集。也许读起来少一些:-)
bignose

5
恩卡听起来很有趣。不幸的是,检测似乎非常依赖于语言,并且支持的语言集也不是很多。矿(DE)丢失:-(反正很酷的工具。
er4z0r


6
enca似乎对于分析用英语编写的文件完全没有用,但是如果您正巧用爱沙尼亚语查看内容,它可能会解决所有问题。很有帮助的工具,... </
sarcasm

6
@vladkras如果您的utf-8文件中没有非ascii字符,则它与ascii是没有区别的:)
vadipp

85
file -bi <file name>

如果您想对一堆文件这样做

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

但是,如果文件是xml文件,并且在xml声明中具有属性“ encoding ='iso-8859-1”,则文件命令将说它是iso文件,即使真正的编码是utf-8 ...
2012年

6
为什么使用-b参数?如果您只执行文件-i *,它将为每个文件输出猜测的字符集。
汉斯·彼得·斯特尔2013年

4
我也对-b参数感到好奇。手册页说它的意思是“简短”Do not prepend filenames to output lines
craq 2016年

1
无需解析文件输出,file -b --mime-encoding仅输出字符集编码
jesjimher

-b代表“简短”,基本上意味着不要输出您刚刚提供的文件名。
Nikos

36

uchardet-从Mozilla移植的编码检测器库。

用法:

~> uchardet file.java 
UTF-8

各种Linux发行版(Debian / Ubuntu,OpenSuse-packman等)都提供了二进制文件。


1
谢谢!我对更多的软件包不满意,但它sudo apt-get install uchardet是如此简单,以至于我决定不用担心它……
sage

正如我在上面的评论中所说:uchardet错误地告诉我文件的编码为“ windows-1252”,尽管我将文件明确保存为UTF-8。uchardet甚至没有说“充满信心0.4641618497109827”,这至少会提示您这完全是在胡说八道。文件,enca和encguess正常工作。
Algoman '18年

uchardetfile与和相比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上指出的那样,此方法不起作用:file -b --mime-encoding用法:file [-bchikLNnprsvz0] [-e测试] [-f namefile] [-F分隔符] [-m magicfiles] [-M magicfiles ] file ... file -C -m magicfiles尝试使用`file --help'了解更多信息。
Wolfgang Fahl

6

真的很难确定它是否是iso-8859-1。如果您的文本只有7位字符,也可能是iso-8859-1,但您不知道。如果您有8位字符,则高位字符也按顺序编码存在。因此,您将必须使用字典来更好地猜测它是哪个单词,并从那里确定它必须是哪个字母。最后,如果您检测到它可能是utf-8,则确定它不是iso-8859-1

编码是最难的事情之一,因为您永远不知道是否没有任何信息可以告诉您


尝试蛮力可能会有所帮助。以下命令将尝试将名称以WIN或ISO开头的所有ecncoding格式转换为UTF8。然后,需要手动检查输出,以寻找正确编码的线索。当然,您可以更改过滤格式以代替ISO或WIN进行适当的更改,或者通过删除grep命令来删除过滤器。for i in $(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。我知道这是错误的,因为我与Kate一起将其另存为UTF-16进行测试。但是,请encguess正确猜测,它已预装在Ubuntu 19.04中。
Nagev

5

要将编码从8859转换为ASCII:

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


3

这不是万无一失的方法。一种可能性是,以检查每一个字符的文件,以确保它不包含在范围中的任何字符0x00 - 0x1f0x7f -0x9f不过,正如我所说,这可能是真实的任何数量的文件,包括ISO8859的至少一个其他变种。

另一种可能性是使用所有受支持的语言在文件中查找特定单词,然后查看是否可以找到它们。

因此,例如,找到8859-1所有受支持的语言中英语“ and”,“ but”,“ to”,“ of”等的等价形式,并查看它们中是否存在大量的文件。

我不是在谈论直译,例如:

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

虽然有可能。我说的是目标语言中的常用字词(据我所知,冰岛语中没有“ and”一词-您可能不得不将其单词用于“ fish” [对不起,这有点陈规定型,我没有表示任何冒犯,只说明一点]]。


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 '18年

请注意,最上面的声明不保证文件ACTUALLY实际采用这种方式编码。如果您真的很在乎您需要自己验证的编码。
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命令,以将所有内容从iconv支持的任何源编码转换为utf8。

例:

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文档,UTF-8 Unicode文本,带有很长的行

$ file -b sample.html

HTML文档,UTF-8 Unicode文本,行很长

$ file -bi sample.html

text / html; 字符集= utf-8

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

utf-8


1
我得到的输出只是“常规文件”
Mordechai

0

我正在使用以下脚本

  1. 查找所有与SIL_ENCODING匹配的FILTER文件
  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
您能举个例子如何在shell中使用它吗?
Lri 2012年

另一个发布者(@fccoelho)提供了一个Python模块作为解决方案,该解决方案获得+3,而该发布者获得-2的答案非常相似,除了它是针对Perl模块的。为什么要双重标准?
快乐的绿色孩子午睡

4
也许一个perl线性代码示例可以帮助解决这个问题。
vikingsteve
By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.