脚本中iconv命令异常:部分文件变0字节且生成.bak文件
问题:批量转换非UTF-8文件时出现0字节文件及.bak后缀
原问题描述
我正在编写一个脚本,用于检测目录中包含非UTF-8字符的文件,若存在则获取该文件的编码类型并执行iconv转换操作。脚本代码如下:
find <directory> |sed '1d'>/<directory>/filelist.txt while read filename do file_nm=${filename%%.*} ext=${filename#*.} echo $filename q=`grep -axv '.*' $filename|wc -l` echo $q r=`file -i $filename|cut -d '=' -f 2` echo $r #file_repair=$file_nm if [ $q -gt 0 ]; then iconv -f $r -t utf-8 -c ${file_nm}.${ext} >${file_nm}_repaired.${ext} mv ${file_nm}_repaired.${ext} ${file_nm}.${ext} fi done< <directory>/filelist.txt
运行脚本后,多个文件变为0字节,且文件名被追加.bak后缀,执行ls| grep 'bak' | wc -l结果为36。请问哪里出错了?
错误原因分析
文件名处理逻辑错误:
${filename%%.*}会从右往左删除最后一个.及之后的所有内容,若文件名包含多个.(如doc.v2.txt),会错误截断文件名;若文件无后缀(如README),${filename#*.}会返回完整路径,拼接后得到README.README这种不存在的文件名,导致iconv读取失败,输出空文件,最终覆盖原文件造成0字节。- 未处理路径中的空格或特殊字符,
read filename会拆分带空格的文件名,导致后续操作错误。
UTF-8检测不可靠:
grep -axv '.*' $filename|wc -l逻辑存在问题:-x要求整行匹配,.*匹配任意UTF-8字符,反向匹配后统计的是无法被UTF-8解析的行数,但该方法误判率高(比如合法非UTF-8文本可能漏检,二进制文件会被误判),还会在处理目录时返回非零行数,触发错误转换。
编码检测与转换问题:
file -i返回的编码可能不被iconv兼容(比如返回unknown-8bit),此时iconv会报错,输出空文件,覆盖原文件后变成0字节。- 直接用
mv覆盖原文件,无备份机制,一旦转换失败就会丢失原文件内容;你看到的.bak后缀可能是系统或其他工具在文件被意外修改时自动生成的备份。
未过滤目录:
find <directory>会列出所有子目录和文件,脚本尝试处理目录时,grep和iconv会报错,生成空的_repaired文件,后续mv操作可能破坏目录结构或生成无效文件。
修正后的脚本
#!/bin/bash TARGET_DIR="<directory>" # 只查找普通文件,跳过目录,处理带空格的文件名 find "$TARGET_DIR" -type f -print0 | while IFS= read -r -d '' filename do # 检测文件是否为非UTF-8编码 if ! iconv -f utf-8 -t utf-8 -c "$filename" >/dev/null 2>&1; then # 获取文件编码,过滤出iconv兼容的编码名 encoding=$(file -i "$filename" | sed -n 's/.*charset=\([^;]*\).*/\1/p') # 处理file返回的unknown-8bit,默认用latin1 [[ "$encoding" == "unknown-8bit" ]] && encoding="latin1" # 生成备份文件名 backup_file="${filename}.bak" # 先备份原文件 cp "$filename" "$backup_file" # 执行编码转换 if iconv -f "$encoding" -t utf-8 -c "$backup_file" > "$filename"; then echo "成功转换:$filename(原文件备份为$backup_file)" else # 转换失败,恢复原文件 cp "$backup_file" "$filename" echo "转换失败,已恢复原文件:$filename" rm "$backup_file" fi fi done
修正说明
- 使用
find -type f -print0和read -r -d ''处理带空格或特殊字符的文件名,避免拆分错误。 - 用
iconv -f utf-8 -t utf-8 -c直接检测文件是否为UTF-8,更可靠。 - 对
file返回的编码做兼容处理,默认将unknown-8bit转为latin1,避免iconv报错。 - 先备份原文件到
.bak,转换成功则保留备份,失败则恢复原文件并删除备份,避免数据丢失。 - 只处理普通文件,跳过目录,避免无效操作。
内容的提问来源于stack exchange,提问作者noob
相关产品推荐
相关产品推荐

