shuf 是 GNU coreutils 提供的随机打乱行命令,默认将整个文件加载到内存并用 Fisher-Yates 算法重排,输出不修改原文件;支持 -n 采样、-e 参数输入、-r 允许重复(仅对 -e/-i 有效)、-o 输出到文件、-s 指定种子实现可重现结果,但始终依赖内存,不支持流式处理。

shuf 直接读文件、打乱、输出,不改原文件,也不需要额外依赖 —— 它是 GNU coreutils 的一部分,几乎所有 Linux 发行版都自带。
shuf 默认行为:整文件随机重排
运行 shuf file.txt 就会把 file.txt 每一行读进内存,用 Fisher-Yates 算法洗牌,再逐行输出。输出顺序每次不同,原文件不变。
- 如果文件为空或只有一行,输出就是原样(没得“乱”)
- 输入来自管道时(如
cat file.txt | shuf),效果一样,但多一次进程开销 - 不指定文件时,
shuf等待标准输入,比如echo -e "a\nb\nc" | shuf
shuf -n:只取前 N 行,不是“取前 N 行再打乱”
-n 是采样数,不是截断数 —— 它先全量加载、全局打乱,再输出前 N 行。这意味着:
-
shuf -n 5 big.txt和shuf big.txt | head -5行为不同:前者保证均匀采样(每行被选中概率相等),后者有偏(只取打乱后开头,但打乱本身已耗内存) - 对超大文件(几百 MB 以上),
-n仍会加载全文到内存,不是流式处理 - 想真正节省内存?得用
terashuf或 Python 分块实现,shuf不支持
shuf -r 和 -e:允许重复、直接传参,别混用
-r(repeat)只在输入源支持“行可复用”时生效,比如 -e 或 -i;对普通文件默认禁用,加了 -r 也无效(除非你手动复制行进 stdin)。
-
shuf -r -n 3 -e a b c可能输出a a c—— 这是唯一合法的重复场景 -
shuf -r file.txt实际等价于shuf file.txt,不会重复输出同一行 -
-e后面每个词是一行,空格分隔,中文需加引号:shuf -e "苹果" "香蕉" "橙子"
shuf -o 和 -s:保存结果、固定随机种子
-o 把输出写入文件,比 shell 重定向 > 更可靠(避免因信号中断导致截断);-s 指定种子,让结果可复现。
-
shuf -s 42 data.txt -o shuffled.txt:每次运行都生成完全相同的乱序结果 - 种子值任意整数,
0也合法,但通常避开负数(某些旧版本解析异常) -
-o文件若已存在,会被覆盖,不提示;不能指定目录路径,目标必须是完整文件名
shuf 的核心限制始终是内存 —— 它不做流式 shuffle,所有行必须进内存才能公平打乱。哪怕你只想取 1 行,它也得先把整个文件读完。这点容易被忽略,尤其在处理日志或导出数据时。

















