使用 strace 命令可以明显看出二者区别。
根本原因在于 bash 和 dash 对 read 这个 shell 内建命令的具体实现不一样。
dash 的实现是 read(0, &c, 1)直接使用 read 系统调用,一个字符一个字符地读取;
https://git.kernel.org/pub/scm/utils/dash/dash.git/tree/src/miscbltin.c#n151而 bash 是使用 zreadc(fd, &c)实现的,其内部会有一个 4K 缓冲,每次执行 zreadc 会一次性从文件中读入 4K 内容。
http://git.savannah.gnu.org/cgit/bash.git/tree/builtins/read.def#n683http://git.savannah.gnu.org/cgit/bash.git/tree/lib/sh/zread.c#n132对于常规的磁盘文件,使用 read 系统调用也还好,因为内核层面其实也有一层 buffer ,顶多会频繁进/出内核,并不涉及随机读写的磁盘 io 瓶颈。
猜测/sys/firmware/qemu_fw_cfg/by_name/etc/cloud-init/vendor-data/raw 这个文件不是普通的常规硬盘文件,每一次执行 read 系统调用都会触发异常->qemu 处理->balabala 一顿操作才返回,绕了好大一圈,且相对常规文件也没有内核缓冲,等于是每读一个字符都来一遍