什么是 parallel?
parallel 是一个 shell 脚本工具,它允许你轻松地并行执行其他命令,你可以把它想象成一个“超级 xargs”,因为它不仅能做到 xargs 能做的事情,而且在并行处理、参数替换、错误处理等方面做得更好、更灵活。

它的核心思想是:将标准输入的数据流分割成多个小块,然后分配给多个并行的进程去处理。
为什么使用 parallel?(与 xargs 的对比)
假设你有一个包含 1000 个文件名的列表,需要对每个文件执行一个耗时操作(如压缩、转码、下载等)。
-
使用
xargs(串行):cat filelist.txt | xargs -I {} command {}这会一个接一个地处理 1000 个文件,非常慢。
(图片来源网络,侵删) -
使用
xargs(并行):cat filelist.txt | xargs -P 8 -I {} command {}xargs也可以并行,但功能相对有限。 -
使用
parallel(并行):cat filelist.txt | parallel -j 8 command {}parallel在并行处理方面更强大、更智能,语法也更简洁直观。
(图片来源网络,侵删)
parallel 的主要优势:
- 智能并行: 默认会尝试使用所有可用的 CPU 核心 (
-j +0)。 - 更好的输入处理: 可以自动识别行、空格、制表符等作为分隔符,比
xargs的-d选项更灵活。 - 丰富的替换字符串: 使用 作为占位符,功能比
xargs的-I更强大,你可以使用{1},{2}来引用参数, 会自动替换为整行。 - 强大的组合和生成功能: 可以从输入行生成多个参数,甚至可以组合多个输入行来生成一个命令。
- 进度显示和控制: 可以显示进度条 (
--bar)、控制任务提交速率 (--delay)、限制内存使用 (--memfree)。 - 内置的替换和引用: 可以轻松修改输入参数,如大写转换 ()、文件扩展名替换 (, )。
- 错误处理和重试: 可以指定失败时的重试次数 (
--retries)。
安装 parallel
parallel 通常不在 Linux 系统的默认最小安装中,但非常容易安装。
-
Debian / Ubuntu:
sudo apt-get install parallel
-
RHEL / CentOS / Fedora:
sudo yum install parallel # 或者对于较新的版本 sudo dnf install parallel
-
macOS (使用 Homebrew):
brew install parallel
安装完成后,建议运行一下初始化命令,它会下载一些额外的数据并设置 ~/.parallel/will-cite 文件,以符合其许可协议(通常不影响使用)。
# 这会创建一个引用文件,表明你同意使用 parallel parallel --citation
parallel 的基本语法和常用选项
parallel 的基本结构是:
cat input.txt | parallel [选项] [命令] [占位符]
或者直接处理文件:
parallel [选项] [命令] [占位符] ::: 参数1 参数2 参数3 ...
核心选项
| 选项 | 全称 | 描述 | 示例 |
|---|---|---|---|
-j |
--jobs |
指定并行任务的数量。+0 表示使用所有可用核心。 |
parallel -j 4 echo {} ::: 1 2 3 4 5 6 7 8 |
| 占位符,代表从输入中读取的一行。 | cat files \| parallel wc {} |
||
{1}, {2} |
代表命令行参数的第1、2个部分。 | parallel echo {1} is in {2} ::: A B C ::: /tmp /var |
|
| 用于分隔输入源,可以并列使用多个。 | parallel echo {1} {2} ::: a b c ::: 1 2 3 |
||
| 表示选项的结束,当输入数据可能以 开头时很有用。 | parallel -- -v {} ::: file1 file2 |
||
--dry-run |
只打印将要执行的命令,但不实际执行。 | cat files \| parallel --dry-run rm {} |
|
--bar |
显示一个进度条,非常直观。 | find . -type f \| parallel --bar gzip {} |
|
--colsep |
指定输入列的分隔符,类似于 awk 的 -F。 |
parallel --colsep ',' echo {1} is from {2} ::: data.csv |
|
将 之后的参数都当作普通参数,防止被 parallel 误认为是选项。 |
parallel -- -k echo {} ::: -a -b -c |
实用示例
示例 1:最简单的并行处理
目标: 对 1 到 10 的数字进行平方计算。
# 方法1:使用 ::: 传递参数
parallel echo {}^2 ::: 1 2 3 4 5 6 7 8 9 10
# 方法2:从文件中读取
seq 10 > numbers.txt
parallel echo {}^2 :::: numbers.txt # :::: 表示从文件读取
解释: parallel 会为 1 到 10 中的每一个数字都启动一个 echo {}^2 进程。 会被替换成当前的数字。
示例 2:并行处理文件列表
目标: 压缩当前目录下所有的 .log 文件。
# 查找所有 .log 文件,并并行执行 gzip 命令
find . -name "*.log" | parallel gzip {}
# 或者更安全的写法,使用 -- 确保文件名不会被当作选项
find . -name "*.log" | parallel -- gzip {}
**解释:find 命令将每个 .log 文件的路径通过管道传给 parallel, 被替换为文件路径,gzip 命令被并行执行。
示例 3:使用多个输入源(笛卡尔积)
目标: 将 a, b, c 分别与 1, 2, 3 组合并打印。
parallel echo {1} on {2} ::: a b c ::: 1 2 3
输出:
a on 1
a on 2
a on 3
b on 1
b on 2
b on 3
c on 1
c on 2
c on 3
解释: 分隔了两个参数列表。parallel 会生成所有可能的组合。
示例 4:处理 CSV 文件
目标: 读取一个 CSV 文件,并打印每行的第一列和第三列。
假设 data.csv 内容如下:
name,age,city
Alice,30,New York
Bob,25,Los Angeles
Charlie,35,Chicago
命令:
# 默认分隔符是逗号
parallel --colsep , echo "Name: {1}, City: {3}" :::: data.csv
输出:
Name: name, City: city
Name: Alice, City: New York
Name: Bob, City: Los Angeles
Name: Charlie, City: Chicago
解释: --colsep , 告诉 parallel 用逗号来分割输入行。{1} 指代第一列,{3} 指代第三列。
示例 5:强大的文件名替换
parallel 提供了许多有用的替换字符串,类似于 basename 和 dirname 命令。
假设文件列表为 path/to/file1.txt, path/to/file2.log。
| 替换符 | 描述 | 示例输入 | 示例输出 |
|---|---|---|---|
| 完整输入 | path/to/file.txt |
path/to/file.txt |
|
| 文件名(带扩展名) | path/to/file.txt |
file.txt |
|
| 目录名 | path/to/file.txt |
path/to |
|
| 文件名(不带扩展名) | path/to/file.txt |
file |
|
| 去掉最后一个扩展名 | path/to/file.tar.gz |
path/to/file.tar |
|
| 去掉所有扩展名 | path/to/file.tar.gz |
path/to/file |
目标: 将当前目录下所有 .jpg 文件转换为 .png 文件,并保留原始目录结构。
# 假设文件在 subfolder/ 中
find . -name "*.jpg" | parallel convert {.}.jpg {.}.png
解释: 对于输入 ./subfolder/image.jpg:
- 是
./subfolder/image.jpg - 是
./subfolder/image - 命令变为
convert ./subfolder/image.jpg ./subfolder/image.png
示例 6:组合多个输入行生成一个命令
这是一个高级功能,非常强大,可以使用 --link 或 --xapply。
目标: 从一个文件读取用户名,从另一个文件读取密码,然后创建用户。
假设 假设 命令: 解释: 学习建议: 一旦你掌握了 users.txt
alice
bob
charliepasswords.txt
pass123
secret456
secure789# --xapply 会将两个列表的对应元素配对
parallel --xargs -n 2 --link sudo useradd -p {2} {1} :::: users.txt passwords.txt
--link 会将两个输入源(users.txt 和 passwords.txt)的对应行配对。{1} 代表第一个输入源(users.txt)的当前行。{2} 代表第二个输入源(passwords.txt)的当前行。--xargs -n 2 确保每次只取两行输入(一个用户名,一个密码)。
parallel 是一个能极大提升你在命令行工作效率的“神器”,无论是处理日志、批量重命名文件、进行数据转换还是并行下载,它都能让你的脚本运行得更快、更简洁。
parallel echo {} ::: a b c。--colsep 处理结构化数据。--dry-run 和 --bar 这两个调试和监控利器。parallel,你可能会发现自己很少再想用 xargs 了。
