我有父文件夹“parent”。在这个文件夹中,我有子文件夹和一个名为“names.txt”的文件。该文件包含这些子文件夹的名称,如下所示:
Parent_folder
folder1
folder2
folder3
folder4
.
.
.
.
names.txt
文件“names.txt”的内容如下:
folder1
folder2
folder3
folder4
.
.
.
在每个文件夹中我都有图像,并且我想在每个图像上连续应用 10 个脚本(每个脚本必须在每个文件夹中完成它的工作,然后必须运行第二个脚本)。These scripts have different names and they are exist in one folder. I set an environment by sourcing a file then I can call these scripts by its name from terminal
.同时,我想立即对所有文件夹应用此过程。即当脚本 #1 运行时,我希望它同时在所有文件夹上运行。完成后,脚本 #2 将启动。我希望它立即在所有文件夹中启动等等......为了实现这一点,我编写了以下代码:
#!/bin/bash
path=PATH/TO/THE/PARENT/FOLDER
for i in $(cat $path/names.txt); do
{
script#1
} &
{
script#2
} &
.
.
.
done
该代码无法有效运行,因为所有命令都同时运行。我希望命令同时在所有文件夹上连续运行。我做错了什么?
答案1
首先,创建一个包装器脚本,该脚本更改为第一个(也是唯一一个)命令行参数中给出的目录,执行它需要的任何设置/变量初始化/等,然后使用它们需要的任何参数按顺序运行 10 个脚本。
例如,如果每个脚本处理目录中的所有 .jpg、.png 和 .gif 文件:
#! /bin/bash
# example-wrapper.sh
cd "$1"
script1 *.{jpg,png,gif}
script2 *.{jpg,png,gif}
script3 *.{jpg,png,gif}
script4 *.{jpg,png,gif}
script5 *.{jpg,png,gif}
script6 *.{jpg,png,gif}
script7 *.{jpg,png,gif}
script8 *.{jpg,png,gif}
script9 *.{jpg,png,gif}
script10 *.{jpg,png,gif}
接下来,使用find
管道将目录列表传输到parallel
.
find /path/to/parent/ -mindepth 1 -type -d -print0 |
parallel -0 -n 1 ./example-wrapper.sh
(-mindepth 1
中的选项find
不包括顶级目录,即父目录本身)
./example-wrapper.sh
默认情况下,并行将为您拥有的每个 CPU 核心运行一个实例(一项“作业”) 。每个实例将获得一个 ( -n 1
) 目录名称。一旦一个作业完成,另一个作业就会开始(如果还有任何剩余作业要运行)。
这可以最大限度地利用可用的 CPU 能力,而不会让作业相互竞争 CPU 时间。
您可以使用parallel
的-j
选项来调整一次运行的作业数量。对于 CPU 密集型任务,每个系统核心一个作业的默认设置可能就是您想要的。
如果您的作业不是 CPU 密集型的,但往往更受 I/O 限制,您可能需要为您拥有的每个核心运行 2 或 3 个作业(取决于您的输入文件有多大、存储速度有多快、以及构成该存储的设备类型 - 例如,SSD 不会受到寻道延迟的影响,因此不会因从整个磁盘查找数据的多个进程而减慢硬盘的速度,并且会因寻道时间而减慢。随机地到处寻找——Linux 的磁盘缓冲/缓存会有所帮助,但不会消除问题)。
如果您想在这些作业运行时完成其他工作(例如正常的桌面使用),请使用-j
告诉parallel
您使用比您的系统少一两个的内核(例如-j 6
在 8 核系统上)。
注意:调整并行进程是一门艺术,需要进行一些实验才能获得最佳结果。
无论如何,从man parallel
:
--jobs N
,-j N
,--max-procs N
,-P N
职位数量。并行运行最多 N 个作业。 0 表示尽可能多。默认值为 100%,即每个 CPU 核心运行一个作业。
如果
--semaphore
设置默认值为 1,则创建互斥锁。
这确实是 的基本和原始用法parallel
。它可以做更多事情。有关详细信息,请参阅手册页。
顺便说一句,xargs
还可以-P
选择并行运行作业。对于像这样的简单用法,使用xargs -P
或没有什么区别parallel
。但如果您的要求更复杂,请使用parallel
.
parallel
应该为大多数 Linux 发行版打包,否则可以从https://www.gnu.org/software/parallel/
答案2
“&”将您的子脚本置于后台,这就是它们同时运行的原因。
您可能想要做的是反转循环:
for script in script1 script2 script3 …; do
for folder in $(cat $path/names.txt); do
( cd $path/$folder; $script; ) &
done
wait
done