做什么

读 stdin,作为参数喂给指定命令。是管道里常被忽略的强工具。

痛点

# ❌ rm 不读 stdin,下面没用
find . -name "*.tmp" | rm

# ✓ xargs 把 stdin 转参数
find . -name "*.tmp" | xargs rm

常用参数

参数 含义
-n N 每次喂 N 个参数
-I {} 用 {} 占位,把输入逐个替换
-0 输入用 null 分隔(配 find -print0)
-P N 并行 N 个进程
-t 显示要执行的命令(调试)
-p 每条问确认

实战

基础

find . -name "*.log" | xargs rm                # 删所有 .log
find . -name "*.tmp" | xargs -p rm             # 删前问
echo "1 2 3" | xargs                           # 把多行 → 一行:1 2 3
echo "1 2 3 4" | xargs -n 2                    # 每行 2 个
# 1 2
# 3 4

含空格 / 特殊字符(安全姿势)

# ❌ 文件名带空格会乱
find . -name "*.log" | xargs rm

# ✓ 用 null 分隔
find . -name "*.log" -print0 | xargs -0 rm

占位符(精确控制位置)

# 给每个文件改名
find . -name "*.jpeg" | xargs -I {} mv {} {}.new
# 等同:mv file1.jpeg file1.jpeg.new ...

# 复制到多个目录
echo "/tmp /backup /elsewhere" | xargs -n 1 cp -r mydata

并行(加速)

# 4 个并行 gzip
find . -name "*.log" | xargs -P 4 -n 1 gzip

# 并行 ping
cat hosts.txt | xargs -P 10 -n 1 ping -c 1 -W 1

跟 -exec 的对比

find . -name "*.log" -exec rm {} \;            # 每个 fork 一次,慢
find . -name "*.log" -exec rm {} +              # 批量,快
find . -name "*.log" -print0 | xargs -0 rm    # 批量,快(和上面差不多)

-exec ... +xargs 效果近似——选哪个看习惯。含空格文件名永远 -print0 + -0

  • 默认空白分隔——含空格 / 换行的文件名要 -print0 + -0
  • xargs 默认会把所有输入塞一条命令——会撑爆 ARG_MAX,加 -n N 限制
  • cd 等 shell 内置不工作——cd 在 xargs 起的子 shell 没意义