直接用 echo 或 read 处理绝密多行文本很危险,因会截断换行、暴露进程参数、触发未预期的变量展开或命令替换;应使用 IFS= read -r -d '' 读入并 printf %s 输出。

为什么直接用 echo 或 read 处理绝密多行文本很危险
因为默认行为会意外截断、丢弃换行符,或把内容暴露在进程列表里(/proc/PID/cmdline 可被其他用户读取)。比如 echo "$secret" 在某些 Shell 版本中可能因 IFS 被重设而折叠空行;而 read secret 默认只读一行,且不处理首尾空白。更严重的是:如果变量值含未转义的 $、` 或 \,后续未加引号的展开会触发命令替换或路径扩展,导致信息泄露或执行任意代码。
read -r -d '' 是最稳妥的多行读入方式
它能完整捕获包括开头空行、结尾换行、内部制表符在内的所有原始字节,且完全禁用反斜杠转义和变量展开。关键点:
-
-r:禁止反斜杠作为续行符或转义字符 -
-d '':将“空字符”设为分隔符,使read一直读到输入流结束(而非默认的换行符) - 必须配合
IFS=使用,否则前导/尾随空白会被 trim 掉
正确写法:
IFS= read -r -d '' secret <<'EOF' -----BEGIN PGP MESSAGE----- Version: GnuPG v2 <p>hQEMA7... -----END PGP MESSAGE----- EOF
注意:<<'EOF' 的单引号至关重要——它禁用 here-document 中的所有变量扩展和命令替换,防止内容被意外解析。
输出时避免 echo,改用 printf %s
echo 对以 - 开头的字符串(如 -n、--help)会误判为选项;对含 \n 的变量,不加 -e 就原样输出反斜杠序列。而 printf %s "$secret" 行为确定、无歧义,且不会解释任何转义序列。
- 要保留原始换行符输出:用
printf %s "$secret" - 要确保末尾有换行(防止终端提示符粘连):用
printf '%s\n' "$secret" - 绝对不要用
echo "$secret"输出敏感内容
跨平台传输时必须检查并清理 \r
如果绝密文本是从 Windows 编辑器复制进来的,每行末尾可能混入 \r(显示为 ^M),这不仅破坏 PGP/SSH 密钥格式,还可能被某些解析器当作控制字符执行。验证方法:
printf '%s' "$secret" | od -c | head -5
若看到 \r \n 成对出现,说明是 CRLF 格式。安全清理方式:
- 用
tr -d '\r':轻量、可靠,适合脚本内联处理 - 避免
sed 's/\r$//':它依赖行尾锚定,在read -d ''读入的单块数据中可能失效 - 绝不用
dos2unix处理变量内容——它只接受文件路径参数
真正难处理的不是换行本身,而是你无法预知绝密文本里是否藏着未声明的控制字符、零宽空格或 UTF-8 BOM。所以只要涉及密钥、token、证书等,一律用 read -r -d '' + printf %s 组合,并在首次载入后立即用 od -c 抽样检查前 20 字节——这是多数人跳过、但线上事故最常见的缺口。


















