web-dev-qa-db-ja.com

bashシェルスクリプトで2つのスレッドを起動する方法

machineBで以下のシェルスクリプトを実行しているため、machineCおよびmachineAからmachineAにファイルをコピーしようとしています。

ファイルがmachineBにない場合は、確かにmachineCにあるはずなので、最初にmachineBからファイルをコピーしてみます。machineBにない場合は、machineCから同じファイルをコピーしてみます。

GNU並列ライブラリを使用してファイルを並列にコピーしていますが、正常に動作しています。現在、2つのファイルを並行してコピーしています。

現在、GNU並列を使用してPRIMARYフォルダー内の_PRIMARY_PARTITION_ファイルをコピーしています。これが完了すると、同じGNU並列を使用してSECONDARYフォルダー内の_SECONDARY_PARTITION_ファイルをコピーします。現在はwrt PRIMARYおよびSECONDARYフォルダーで順次です

以下は私のシェルスクリプトであり、すべてが正常に動作します-

_#!/bin/bash

export PRIMARY=/test01/primary
export SECONDARY=/test02/secondary
readonly FILERS_LOCATION=(machineB machineC)
export FILERS_LOCATION_1=${FILERS_LOCATION[0]}
export FILERS_LOCATION_2=${FILERS_LOCATION[1]}
PRIMARY_PARTITION=(550 274 2 546 278) # this will have more file numbers
SECONDARY_PARTITION=(1643 1103 1372 1096 1369) # this will have more file numbers

export dir3=/testing/snapshot/20140103

# delete primary files first and then copy
find "$PRIMARY" -mindepth 1 -delete

do_CopyInPrimary() {
  el=$1
  scp david@$FILERS_LOCATION_1:$dir3/new_weekly_2014_"$el"_200003_5.data $PRIMARY/. || scp david@$FILERS_LOCATION_2:$dir3/new_weekly_2014_"$el"_200003_5.data $PRIMARY/.
}
export -f do_CopyInPrimary
parallel -j 2 do_CopyInPrimary ::: "${PRIMARY_PARTITION[@]}"

# delete secondary files first and then copy
find "$SECONDARY" -mindepth 1 -delete

do_CopyInSecondary() {
  el=$1
  scp david@$FILERS_LOCATION_1:$dir3/new_weekly_2014_"$el"_200003_5.data $SECONDARY/. || scp david@$FILERS_LOCATION_2:$dir3/new_weekly_2014_"$el"_200003_5.data $SECONDARY/.
}
export -f do_CopyInSecondary
parallel -j 2 do_CopyInSecondary ::: "${SECONDARY_PARTITION[@]}"
_

問題ステートメント:-

2つのスレッドを起動できる方法はありますか?1つは上記と同じ設定を使用してPRIMARYフォルダー内のファイルをコピーする方法です。つまり、2つのファイルを並行してコピーします。そして、上記と同じ設定を使用してSECONDARYフォルダー内のファイルをコピーする2番目のスレッドは、同時に2つのファイルを並行してコピーする必要がありますか?

つまり、PRIMARYフォルダーが完成したら、SECONDARYフォルダーとPRIMARYフォルダーの両方に同時にファイルをコピーし、SECONDARYフォルダーにファイルをコピーする必要があります。

現在、PRIMARYフォルダーのファイルが作成されたら、SECONDARYフォルダーのファイルをコピーしようとしています。

つまり、2つのスレッドを起動するだけで、1つのスレッドでこれを実行できます。

_# delete primary files first and then copy
find "$PRIMARY" -mindepth 1 -delete

do_CopyInPrimary() {
  el=$1
  scp david@$FILERS_LOCATION_1:$dir3/new_weekly_2014_"$el"_200003_5.data $PRIMARY/. || scp david@$FILERS_LOCATION_2:$dir3/new_weekly_2014_"$el"_200003_5.data $PRIMARY/.
}
export -f do_CopyInPrimary
parallel -j 2 do_CopyInPrimary ::: "${PRIMARY_PARTITION[@]}"
_

そして2番目のスレッドがこれを実行します-

_# delete secondary files first and then copy
find "$SECONDARY" -mindepth 1 -delete

do_CopyInSecondary() {
  el=$1
  scp david@$FILERS_LOCATION_1:$dir3/new_weekly_2014_"$el"_200003_5.data $SECONDARY/. || scp david@$FILERS_LOCATION_2:$dir3/new_weekly_2014_"$el"_200003_5.data $SECONDARY/.
}
export -f do_CopyInSecondary
parallel -j 2 do_CopyInSecondary ::: "${SECONDARY_PARTITION[@]}"
_

そして、すべてのファイルが正常にコピーされると、すべてのファイルがコピーされたというメッセージがエコーされます。 Javaでは、2つのスレッドを起動する方法を知っており、各スレッドが特定のタスクを実行していますが、bashシェルスクリプトでこれがどのように機能するかわかりませんか?

私の主なタスクは、GNU並列を使用して、2つのファイルをPRIMARYフォルダーとSECONDARYフォルダーに同時にコピーすることですか?

これはbashシェルスクリプトで実行できますか?

3
arsenal

明白です:

parallel -j 2 do_CopyInPrimary ::: "${PRIMARY_PARTITION[@]}" &
parallel -j 2 do_CopyInSecondary ::: "${SECONDARY_PARTITION[@]}" &
wait

ただし、この方法では、セカンダリはプライマリが完了するのを待機せず、プライマリが成功したかどうかをチェックしません。 $ PRIMARY_PARTITION [1]が$ SECONDARY_PARTITION [1]に対応すると想定します($ PRIMARY_PARTITION [1]からファイルを読み取れない場合は、$ SECONDARY_PARTITION [1]から読み取ります-つまり、$ PRIMARY_PARTITIONおよび$ SECONDARY_PARTITION要素の数が同じです)。次に、$ PRIMARY_PARTITION [1]で$ SECONDARY_PARTITION [1]の実行を条件付けることができます。

do_Copy() {
  PRIMARY_PARTITION=(550 274 2 546 278) # this will have more file numbers
  SECONDARY_PARTITION=(1643 1103 1372 1096 1369) # this will have more file numbers
  pel=${PRIMARY_PARTITION[$1]}
  sel=${SECONDARY_PARTITION[$1]}
  do_CopyInPrimary $pel || 
    do_CopyInSecondary $sel || 
    echo Could not copy neither $pel nor $sel
}
export -f do_Copy
# Number of elements in PRIMARY_PARTITION == SECONDARY_PARTITION
seq ${#PRIMARY_PARTITION[@]} | parallel -j 2 do_Copy

これにより、依存関係は正しくなりますが、一度にコピーされるのは合計で2つだけです。 -j4 4つのプライマリを同時に実行するリスクがあるため、これも防ぐ必要があります。

do_Copy() {
  PRIMARY_PARTITION=(550 274 2 546 278) # this will have more file numbers
  SECONDARY_PARTITION=(1643 1103 1372 1096 1369) # this will have more file numbers
  pel=${PRIMARY_PARTITION[$1]}
  sel=${SECONDARY_PARTITION[$1]}
  sem -j2 --fg --id primary do_CopyInPrimary $pel || 
    sem -j2 --fg --id secondary do_CopyInSecondary $sel || 
    echo Could not copy neither $pel nor $sel
}
export -f do_Copy
# Number of elements in PRIMARY_PARTITION == SECONDARY_PARTITION
seq ${#PRIMARY_PARTITION[@]} | parallel -j 4 do_Copy

semは、プライマリの数を2に、セカンダリの数を2に制限します。

3
Ole Tange

Bashはスレッド化をサポートしていませんが、バックグラウンドのマルチプロセッシングをサポートしています。つまり、プロセスは、独自の環境、作業ディレクトリなどを備えた新しいプロセススペースに複製され、すべての通信は通常のIPCチャネルを通じて行われる必要があります。それ以外は、スレッディング。

これを行うには、コードブロックを「バックグラウンド」にします。このような:

#!/bin/bash
{
    echo "Foo"
    sleep 1
    echo "Foo: done"
}&    
echo "Bar"
sleep 1
echo "Bar: done"

出力

Bar
Foo
**[1 second delay]**
Bar: done
Foo: done

コードブロックを関数でラップし、その関数をバックグラウンドジョブとして実行することで、同じ効果を得ることができます。

または、中括弧の代わりに括弧でコードブロックをラップすることもできます。括弧内のステートメントは、明示的に(常に)別のプロセスで実行されます。通常、中括弧で囲まれたステートメントはグループ化されますが、分岐せずに実行されます。 &サフィックスを使用してバックグラウンドでコードを実行すると、そのコードは強制的に別のプロセスで実行されます。

6
tylerl

これには、scpの代わりにrsyncを使用することをお勧めします。ファイルごとにscpを実行するのではなく、1つのコマンドですべてのファイルをコピーすることで、時間と労力を大幅に節約し、データが正しくコピーされるようにします。また、machineCからの既存のファイルのコピーはスキップされます。このようなもの:

#!/bin/bash

files="one two three"
machines="machineB machineC"

for machine in machines
do
    ssh $machine -c "cd source_directory || exit 1; rsync -avPz --ignore-existing $files machineA:/receive_directory/"
done
0
blujay