我尝试将 iconv 指向一个目录,无论当前编码如何,所有文件都将转换为 UTF-8
我正在使用这个脚本,但你必须指定你要使用的编码。我怎样才能让它自动检测当前编码?
dir_iconv.sh
#!/bin/bash
ICONVBIN='/usr/bin/iconv' # path to iconv binary
if [ $# -lt 3 ]
then
echo "$0 dir from_charset to_charset"
exit
fi
for f in $1/*
do
if test -f $f
then
echo -e "\nConverting $f"
/bin/mv $f $f.old
$ICONVBIN -f $2 -t $3 $f.old > $f
else
echo -e "\nSkipping $f - not a regular file";
fi
done
端子线
sudo convert/dir_iconv.sh convert/books CURRENT_ENCODING utf8
enca
:
Enca 是一个极其简单的字符集分析器。它检测文本文件的字符集和编码,还可以使用内置转换器或外部库和工具(如 libiconv、librecode 或 cstocs)将它们转换为其他编码。
目前它支持白俄罗斯语、保加利亚语、克罗地亚语、捷克语、爱沙尼亚语、匈牙利语、拉脱维亚语、立陶宛语、波兰语、俄语、斯洛伐克语、斯洛文尼亚语、乌克兰语、中文以及一些独立于语言的多字节编码。
请注意,一般来说,自动检测当前编码是一个困难的过程(相同的字节序列可以是多种编码中的正确文本)。
enca
根据您告诉它要检测的语言使用启发式方法(以限制编码数量)。您可以使用 enconv
将文本文件转换为单一编码。
file -bi .xsession-errors
给我: “文本/纯文本;字符集=us-ascii”所以
file -bi .xsession-errors |awk -F "=" '{print $2}'
给我 “us-ascii”我在像这样的脚本中使用它:
CHARSET="$(file -bi "$i"|awk -F "=" '{print $2}')"
if [ "$CHARSET" != utf-8 ]; then
iconv -f "$CHARSET" -t utf8 "$i" -o outfile
fi
我的解决方案,使用recode和uchardet来放置所有文件:
#!/bin/bash
apt-get -y install recode uchardet > /dev/null
find "$1" -type f | while read FFN # 'dir' should be changed...
do
encoding=$(uchardet "$FFN")
echo "$FFN: $encoding"
enc=`echo $encoding | sed 's#^x-mac-#mac#'`
set +x
recode $enc..UTF-8 "$FFN"
done
将其放入convert-dir-to-utf8.sh
并运行:
bash convert-dir-to-utf8.sh /pat/to/my/trash/dir
请注意,sed
是此处针对 mac 编码的解决方法。 许多不常见的编码需要像这样的解决方法。
dir2utf8.sh
:
#!/bin/bash
# converting all files in a dir to utf8
for f in *
do
if test -f $f then
echo -e "\nConverting $f"
CHARSET="$(file -bi "$f"|awk -F "=" '{print $2}')"
if [ "$CHARSET" != utf-8 ]; then
iconv -f "$CHARSET" -t utf8 "$f" -o "$f"
fi
else
echo -e "\nSkipping $f - it's a regular file";
fi
done
#!/bin/bash
find "<YOUR_FOLDER_PATH>" -name '*' -type f -exec grep -Iq . {} \; -print0 |
while IFS= read -r -d $'\0' LINE_FILE; do
CHARSET=$(uchardet $LINE_FILE)
echo "Converting ($CHARSET) $LINE_FILE"
# NOTE: Convert/reconvert to utf8. By Questor
iconv -f "$CHARSET" -t utf8 "$LINE_FILE" -o "$LINE_FILE"
# NOTE: Remove "BOM" if exists as it is unnecessary. By Questor
# [Refs.: https://stackoverflow.com/a/2223926/3223785 ,
# https://stackoverflow.com/a/45240995/3223785 ]
sed -i '1s/^\xEF\xBB\xBF//' "$LINE_FILE"
done
# [Refs.: https://justrocketscience.com/post/handle-encodings ,
# https://stackoverflow.com/a/9612232/3223785 ,
# https://stackoverflow.com/a/13659891/3223785 ]
进一步的问题:我不知道我的方法是否最安全。我这样说是因为我注意到某些文件未正确转换(字符将丢失)或被“截断”。我怀疑这与“iconv”工具或使用“uchardet”工具获得的字符集信息有关。我对@demofly提出的解决方案感到好奇,因为它可能更安全。 另一个答案
#!/bin/bash
find "<YOUR_FOLDER_PATH>" -name '*' -type f -exec grep -Iq . {} \; -print0 |
while IFS= read -r -d $'\0' LINE_FILE; do
CHARSET=$(uchardet $LINE_FILE)
REENCSED=`echo $CHARSET | sed 's#^x-mac-#mac#'`
echo "\"$CHARSET\" \"$LINE_FILE\""
# NOTE: Convert/reconvert to utf8. By Questor
recode $REENCSED..UTF-8 "$LINE_FILE" 2> STDERR_OP 1> STDOUT_OP
STDERR_OP=$(cat STDERR_OP)
rm -f STDERR_OP
if [ -n "$STDERR_OP" ] ; then
# NOTE: Convert/reconvert to utf8. By Questor
iconv -f "$CHARSET" -t utf8 "$LINE_FILE" -o "$LINE_FILE" 2> STDERR_OP 1> STDOUT_OP
STDERR_OP=$(cat STDERR_OP)
rm -f STDERR_OP
fi
# NOTE: Remove "BOM" if exists as it is unnecessary. By Questor
# [Refs.: https://stackoverflow.com/a/2223926/3223785 ,
# https://stackoverflow.com/a/45240995/3223785 ]
sed -i '1s/^\xEF\xBB\xBF//' "$LINE_FILE"
if [ -n "$STDERR_OP" ] ; then
echo "ERROR: \"$STDERR_OP\""
fi
STDOUT_OP=$(cat STDOUT_OP)
rm -f STDOUT_OP
if [ -n "$STDOUT_OP" ] ; then
echo "RESULT: \"$STDOUT_OP\""
fi
done
# [Refs.: https://justrocketscience.com/post/handle-encodings ,
# https://stackoverflow.com/a/9612232/3223785 ,
# https://stackoverflow.com/a/13659891/3223785 ]
第三个答案
#!/bin/bash
find "<YOUR_FOLDER_PATH>" -name '*' -type f -exec grep -Iq . {} \; -print0 |
while IFS= read -r -d $'\0' LINE_FILE; do
CHARSET=$(uchardet $LINE_FILE)
REENCSED=`echo $CHARSET | sed 's#^x-mac-#mac#'`
echo "\"$CHARSET\" \"$LINE_FILE\""
# NOTE: Convert/reconvert to utf8. By Questor
recode $REENCSED..UTF-8 "$LINE_FILE" 2> STDERR_OP 1> STDOUT_OP
STDERR_OP=$(cat STDERR_OP)
rm -f STDERR_OP
if [ -n "$STDERR_OP" ] ; then
# NOTE: Convert/reconvert to utf8. By Questor
bash -c "</dev/tty vim -u NONE +\"set binary | set noeol | set nobomb | set encoding=utf-8 | set fileencoding=utf-8 | wq\" \"$LINE_FILE\""
else
# NOTE: Remove "BOM" if exists as it is unnecessary. By Questor
# [Refs.: https://stackoverflow.com/a/2223926/3223785 ,
# https://stackoverflow.com/a/45240995/3223785 ]
sed -i '1s/^\xEF\xBB\xBF//' "$LINE_FILE"
fi
done
这是完美转化次数最多的解决方案。此外,我们没有任何被截断的文件。
sed -i '1s/^\xEF\xBB\xBF//' "$LINE_FILE"
可以在没有合并工具的转换后与合并工具进行初步比较后执行,因为它可能会导致“差异”。
注意:find
进行搜索会带来给定路径 ("") 及其子文件夹中的所有非二进制文件。
cat your_file | iconv -f (uchardet your_file ) -t UTF-8
bash shell
cat your_file | iconv -f $(uchardet your_file ) -t UTF-8
如果使用 bash 脚本
#!/usr/bin/bash
for fn in "$@"
do
iconv < "$fn" -f $(uchardet "$fn") -t utf8
done
作者:ubuntu 小组的@flowinglight。
查看 Linux cli 中可用于数据转换的工具:
此外,还需要找到 iconv
iconv --list
即可发现编码名称与
uchardet
工具返回的名称不同(例如:
uchardet
中的 x-mac-cyrillic 与
iconv
中的 mac-cyrillic)enca 命令不适用于我的 GB2312 编码的简体中文文本文件。
它需要
chardet
和iconv 命令。
detection_cat ()
{
DET_OUT=$(chardet $1);
ENC=$(echo $DET_OUT | sed "s|^.*: \(.*\) (confid.*$|\1|");
iconv -f $ENC $1
}