web-dev-qa-db-ja.com

複数のフォルダでコマンドを連続して実行する

親フォルダ「parent」があります。このフォルダー内には、サブフォルダーと「names.txt」という名前のファイルがあります。このファイルには、次のようにこれらのサブフォルダーの名前が含まれています。

Parent_folder
folder1
folder2
folder3
folder4
.
.
.
.
names.txt

ファイル「names.txt」の内容は次のとおりです。

folder1
folder2
folder3
folder4
.
.
.

すべてのフォルダー内に画像があり、すべての画像に10個のスクリプトを連続して適用したいと思います(すべてのスクリプトはすべてのフォルダー内のジョブを終了する必要があり、次に2番目のスクリプトを実行する必要があります)。 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

すべてのコマンドが同時に実行されているため、このコードは効率的に機能していません。コマンドをすべてのフォルダーで一度に、しかし連続して実行したい。私が間違っていることは何ですか?

3
user88036

最初に、最初の(そして唯一の)コマンドライン引数で指定されたディレクトリに変更するラッパースクリプトを作成し、必要なセットアップ/変数の初期化などを実行してから、必要な引数を使用して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

find-mindepth 1オプションは、最上位ディレクトリ、つまり親ディレクトリ自体を除外します)

デフォルトでは、parallelは、使用しているCPUコアごとに./example-wrapper.shの1つのインスタンス(「ジョブ」)を実行します。各インスタンスは、1つの(-n 1)ディレクトリ名を取得します。ジョブが終了するとすぐに、別のジョブが開始されます(実行するジョブが残っている場合)。

これにより、CPU時間についてジョブを互いに競合させることなく、使用可能なCPUパワーを最大限に活用できます。

parallel-jオプションを使用して、一度に実行するジョブの数を調整できます。 CPUを集中的に使用するタスクの場合、システムコアごとにデフォルトの1つのジョブが必要になる可能性があります。

ジョブのCPU負荷はそれほど高くないが、I/Oバウンドが大きくなる傾向がある場合は、コアごとに2つまたは3つのジョブを実行することをお勧めします(入力ファイルの大きさ、ストレージの速度に応じて、また、そのストレージを構成するデバイスの種類(SSDはシーク遅延の影響を受けないため、ディスク全体からデータをシークする複数のプロセスによって速度が低下することはありません)。ハードディスクはシーク時間の影響を受け、速度が低下します。いたるところにランダムにシークするように作られています-Linuxのディスクバッファリング/キャッシングは役に立ちますが、問題を解決することはできません)。

これらのジョブの実行中に他の作業(通常のデスクトップの使用など)を実行する場合は、-jを使用して、システムよりも1つまたは2つ少ないコアを使用するようにparallelに指示します(例:-j 6 8コアシステムの場合)。

注:並列プロセスの調整は芸術であり、最良の結果を得るにはいくつかの実験が必要になる場合があります。

とにかく、man parallelから:

--jobs N-j N--max-procs N-P N

ジョブスロットの数。最大N個のジョブを並行して実行します。 0は可能な限り多くを意味します。デフォルトは100%で、CPUコアごとに1つのジョブを実行します。

--semaphoreが設定されている場合、デフォルトは1であるため、ミューテックスが作成されます。

これは、parallelの本当に基本的で原始的な使用法です。それはもっとたくさんのことができます。詳細については、manページを参照してください。

ところで、xargsには、ジョブを並行して実行するための-Pオプションもあります。このような単純な使用法では、xargs -Pparallelのどちらを使用してもほとんど違いはありません。ただし、要件がより複雑な場合は、parallelを使用してください。

parallelは、ほとんどのLinuxディストリビューション用にパッケージ化する必要があります。それ以外の場合は、 https://www.gnu.org/software/parallel/ から入手できます。

3
cas

「&」はサブスクリプトをバックグラウンドに配置します。そのため、サブスクリプトはすべて同時に実行されます。

おそらくやりたいことは、ループを反転することです。

for script in script1 script2 script3 …; do
    for folder in $(cat $path/names.txt); do
        ( cd $path/$folder; $script; ) &
    done
    wait
done
0
Edward Falk