中文乱码、Windows 传过来的脚本换行不对、需要把二进制塞进文本接口、下载的文件要校验完整性,这四类问题分别对应 iconv、dos2unix、base64、md5sum 四条命令。它们看着不搭边,实际都是在处理"字节长什么样"的问题。这一篇把用法和常见坑过一遍。
一、iconv:字符编码转换
语法格式
iconv -f 原编码 -t 目标编码 [输入文件]
不写输入文件时从标准输入读。转换结果打到标准输出,要落盘用重定向。
常用参数
| 参数 | 说明 |
|---|---|
-f 编码 |
指定输入编码(from) |
-t 编码 |
指定输出编码(to) |
-l |
列出所有支持的编码名 |
-c |
丢弃无法转换的字符(不报错中断) |
-t UTF-8//IGNORE |
目标编码后加 //IGNORE,忽略转换不了的字节 |
示例与预期输出
把一份 GBK 编码的日志转成 UTF-8:
iconv -f GBK -t UTF-8 old_gbk.log > new_utf8.log
这条命令不会有任何输出(成功就是没输出)。想确认转得对不对,用 file 看一眼:
file new_utf8.log
预期输出:
new_utf8.log: UTF-8 Unicode text
反向把 UTF-8 转成 GBK,给老 Windows 程序读:
iconv -f UTF-8 -t GBK readme.txt > readme_gbk.txt
如果原文里有 GBK 表示不了的生僻字(比如某些 emoji、繁体字),iconv 会直接报错中断。这时候加 -c 跳过坏字节:
iconv -f UTF-8 -t GBK -c readme.txt > readme_gbk.txt
代价是那些字符会消失,转换前最好先备份原文。
⚠️ 常见坑
- 编码名写错 :
utf8和UTF-8不一样,iconv 认UTF-8。拿不准用iconv -l | grep -i utf查。 - 猜原编码 :
file -i 文件名能帮你猜,但不是 100% 准。中文乱码最常见的就是 UTF-8 和 GBK 互相转。 - 直接改原文件 :iconv 不支持原地编辑,一定要
> 新文件。想覆盖就先写到临时文件再 mv。
二、dos2unix / unix2dos:换行符转换
背景
Windows 的文本文件行尾是 \r\n(CRLF),Linux 是 \n(LF)。从 Windows 拷过来的 shell 脚本第一行就可能报:
bash: ./script.sh: /bin/bash^M: bad interpreter
那个 ^M 就是多出来的 \r。
语法格式
dos2unix [选项] 文件 # CRLF -> LF
unix2dos [选项] 文件 # LF -> CRLF
常用参数
| 参数 | 说明 |
|---|---|
-k |
保持原文件时间戳不变 |
-n 新文件 |
不原地修改,输出到新文件 |
-q |
安静模式 |
示例与预期输出
dos2unix script.sh
预期输出:
dos2unix: converting file script.sh to Unix format...
改完脚本就能直接 ./script.sh 跑了。
不想动原文件、想另存一份:
dos2unix -n script_win.sh script_unix.sh
没有 dos2unix 命令时
最小化安装的系统可能没装这个包。用第 56 篇讲过的 tr 也能干同样的事:
tr -d '\r' < script_win.sh > script_unix.sh
效果一样,缺点是没了批量处理和 -k 保时间戳这些便利功能。
三、base64:二进制和文本互转
语法格式
base64 [选项] 文件
常用参数
| 参数 | 说明 |
|---|---|
-d |
解码(decode) |
-i |
解码时忽略非法字符 |
-w 数字 |
编码后每行宽度,0 表示不折行 |
示例与预期输出
把图片编码成文本,塞进 JSON 配置:
base64 -w0 logo.png > logo.b64
-w0 让输出不折行,方便塞进单行配置。logo.b64 里就是一长串 aGVsbG8... 样子的字符。
解码还原:
base64 -d logo.b64 > logo_restored.png
再用 md5sum(下面讲)对比一下原始文件和解码后的文件,哈希值一致就说明没坏。
直接在命令行里编一段:
echo -n "hello" | base64
预期输出:
aGVsbG8=
-n 让 echo 不输出末尾换行,否则编出来的串会多两个字符。
⚠️ 注意
base64 不是加密,只是编码。任何人拿到串都能解回来,不要拿它当密码用。它的作用是让纯文本通道(邮件正文、JSON 字符串、HTTP header)能安全地传二进制数据。
四、md5sum:文件完整性校验
语法格式
md5sum [文件...]
常用参数
| 参数 | 说明 |
|---|---|
-c 校验文件 |
根据校验文件里的记录逐个核对 |
--tag |
输出 BSD 风格的校验串 |
示例与预期输出
算一个文件的 MD5 值:
md5sum logo.png
预期输出:
9a7b1c3d5e7f9a1b2c4d6e8f0a1b3c5d logo.png
左边是 32 位十六进制哈希,右边是文件名。这个哈希值可以理解成文件的"指纹"------文件内容动一个字节,哈希值就全变了。
生成校验清单并核对:
md5sum *.png > MD5SUMS
md5sum -c MD5SUMS
预期输出:
logo.png: OK
icon.png: OK
如果中途有人改了某个文件,对应的那行会显示 FAILED。下载发行版镜像时,官网给的 SHA256SUMS 文件就是这个用法。
⚠️ 用途边界
MD5 设计上不是为了防篡改,是为了快速发现意外损坏 (下载中断、磁盘坏道、传输丢包)。它算得快,但抗碰撞能力早就被攻破,别拿它做安全签名。需要防故意篡改的场景用 sha256sum:
sha256sum logo.png
输出的哈希串更长(64 位),算法也更可靠。日常校验完整性,sha256sum 是现在的默认选择,md5sum 留着兼容老脚本就行。
五、知识扩展:MD5 与 SHA 家族的区别
MD5、SHA-1、SHA-256、SHA-512 都是哈希算法,把任意长度的输入映射成固定长度的摘要。区别在摘要长度和抗碰撞强度:
| 算法 | 摘要长度 | 现状 |
|---|---|---|
| MD5 | 128 位(32 hex) | 已被攻破,不用于安全场景 |
| SHA-1 | 160 位(40 hex) | 2017 年实际碰撞,逐步淘汰 |
| SHA-256 | 256 位(64 hex) | 目前行业主流,安全可靠 |
| SHA-512 | 512 位(128 hex) | 更安全,计算略慢 |
为什么哈希被"碰撞"就算失效?因为攻击者能人为构造出两个不同内容、哈希值相同的文件。一旦这种文件存在,"哈希一致 = 文件没被改"的假设就崩了。下载 CentOS 镜像时官网给的是 sha256sum 文件而不是 md5sum,就是这个原因。
日常写脚本做完整性自检,sha256sum 替换 md5sum 几乎没有迁移成本,参数和用法一模一样。