find . -name "*.log" -print0 | xargs -0 ls -lh-print0 与 -0 配对,用 null 分隔,文件名带空格也不出错。
约 1176 字大约 4 分钟
2026-05-14
有些命令从标准输入读数据(grep、sort),有些命令只认命令行参数(rm、ls、cp)。当你想把前者的输出喂给后者时,管道直接接是不行的——这就是 xargs 的舞台:它把输入的文本转换成参数,再拼到命令后面执行。
理解 xargs 把标准输入转成命令参数的作用,掌握 -print0/-0 处理特殊文件名、-I 占位、-n 分批等关键用法。
find . -name "*.log" -print0 | xargs -0 ls -lh-print0 与 -0 配对,用 null 分隔,文件名带空格也不出错。
xargs -I{} mv {} /backup/-I{} 把每个输入放到 {} 的位置,参数不一定在末尾。
xargs -n 1 cmd把输入拆成一次一个参数地调用命令。
xargs -p cmd-p 在每次执行前让你确认,批量危险操作的保险。
看一个对比就懂了:
find . -name "*.tmp" | rm # 不行!rm 不读标准输入
find . -name "*.tmp" | xargs rm # 可以,xargs 把文件名拼成 rm 的参数xargs 站在管道中间,把上游传来的文本(一行行的文件名、ID 等)收集起来,拼接成下游命令的参数。它还很聪明:参数太多时会自动分批调用,避免“参数列表过长”的错误。
xargs 默认按空格和换行切分输入。于是 my file.txt 会被当成 my 和 file.txt 两个参数——批量操作时这是灾难。
解决方案是“用 null 字符(\0)当分隔符”,因为文件名里不可能有 \0:
find . -name "*.log" -print0 | xargs -0 rm
# ↑ find 用 \0 分隔 ↑ xargs 也用 \0 读-print0 和 -0 必须成对出现。凡是 find 接 xargs 处理文件,养成习惯都加上这对,不要等被空格坑了才想起来。grep -Z 配 xargs -0 同理。
xargs 默认把参数拼在命令最后。但有时参数要放在中间,比如 mv 文件 目标目录——目标目录在后面。这时用 -I{} 指定占位符:
find . -name "*.log" -print0 | xargs -0 -I{} mv {} /archive/
ls *.jpg | xargs -I{} cp {} {}.bak{} 出现在哪,每个输入项就被放到哪。注意:用了 -I{} 后,xargs 变成一次处理一个输入项,不再批量。
-n N:每次最多传 N 个参数给命令。-n 1 就是一次一个。-P N:并行跑 N 个进程,处理大量任务时能显著加速。cat urls.txt | xargs -n 1 -P 4 curl -O # 4 个并发下载批量操作前,先把命令换成 echo 预览
xargs 一旦接上 rm、mv、kill,作用范围是上游所有输出项,错一个就是批量事故。动手前的安全步骤:① 先单独跑上游命令(如 find ...),确认匹配列表正是你想要的;② 把下游命令换成 echo(xargs -0 echo rm),看看完整命令长什么样;③ 确认无误,再换回真实命令。不确定时加 -p 让它每次执行前问你一句。
| 误区 | 更稳妥的做法 |
|---|---|
find 接 xargs 不加 -print0 / -0 | 文件名带空格会被拆错,find 接 xargs 一律配 -print0 和 -0 |
| 以为参数总是拼在命令末尾 | 参数要放中间用 -I{} 占位 |
直接 xargs rm / xargs kill 一把梭 | 先用 echo 预览完整命令,或加 -p 逐个确认 |
| 上游没输出时不管 | 空输入时加 --no-run-if-empty(GNU 默认已是),避免空跑出意外 |
版权归属:Shuo Liu