通过在 for 循环中启动多个实例来加速 bash 脚本

通过在 for 循环中启动多个实例来加速 bash 脚本

我有这个脚本:

 for i in `find ! -newermt "2016-02-13" -name "*svgz"`; do
  inkscape --verb FitCanvasToDrawing --verb FileSave --verb FileClose ${i} --verb FileQuit
done

它等待 Inkscape 完成其工作,然后重新启动它并处理下一个文件。我想让四个 Inkscape 实例并行运行以加快处理速度(我有大约 5,000 个文件要处理)。这可能吗?如果可以,怎么做?提前致谢!

答案1

尝试 GNU Parallel。

sudo aptitude install parallel

我已经有一段时间没有使用它了,但是它的命令行应该类似于下面的命令行:

find ! -newermt "2016-02-13" -name "*svgz" | \
  parallel -j4 \
    inkscape \
    --verb FitCanvasToDrawing \
    --verb FileSave \
    --verb FileClose {} \
    --verb FileQuit

其中 4 是您想要在任何给定时间运行的进程数。

答案2

您可以使用 GNU parallel,如此处针对同样涉及 inkscape 的一个非常相似的问题所解释的那样: https://stackoverflow.com/questions/26572397/how-to-process-20k-svg-files-with-inkscape-cli-mode-align-and-merge-objects

我最近自己使用的另一个简单技巧如下:

  1. 创建一个 shellscript“process.sh”来处理作为参数传递给它的单个文件。
  2. 将 find 命令的结果存储在文本文件中

  3. 使用“split”命令将文件拆分为您想要并行运行的多个作业。

  4. 运行 process.sh 的多个实例,并通过生成的分割文件和 xargs 向其传递参数。

答案3

以下是我的方法。由于我没有相同的文件,下面的示例代码旨在使用 打开 4 个文本文件gedit

这是如何工作的?首先,我们在文件可能存储的硬编码位置(FILEPATH变量)中找到文件。然后我们将其传递给结构。注意和while read的使用。这在 bash 编程中非常常见,用于消除包含空格、不可打印字符等的有问题的文件名。-print0IFS= read -d''

每个gedit file &调用都gedit用 从脚本中分离出来&。这使得 while 循环不停地继续。

使循环停止的是 COUNT 变量。一旦我们从 0 计数到某个能被 4 整除的数字,变量MOD(由模数运算符计算得出)将变为 0。现在 shell 将等待弹出窗口(即zenity)以确认生成另外 4 个窗口。这样我们计数 4 次,重置变量,继续。

这里唯一的缺点是find不对文件进行排序,因此它们不一定按照命名顺序排列。如果顺序很重要,代码将需要额外的指令。否则,这就足够了。

#!/bin/bash

FILEPATH="/home/xieerqi/MYTEXTFILES"
COUNT=0

find $FILEPATH -type f -name "*.txt" -print0 | \
while IFS= read -d ''  FILE;
do
    gedit $FILE & 
    COUNT=$(( $COUNT+1 ))
    MOD=$(( $COUNT % 4 ))

    if [ $MOD -eq 0   ]
    then 
        zenity --question --text "Open 4 more files?"  || exit
    fi
done

相关内容