if条件を並列に実行

if条件を並列に実行

次のスクリプトがあります。

#!/bin/bash

if findmnt --source UUID=309689b5-ea5c-4175-84c7-192631553eab --source PARTLABEL=WDPurple8TB --mountpoint /media/ismail/WDPurple8TB --types ext4 --noheadings; then
    udisksctl unmount -b /dev/disk/by-label/WDPurple8TB
    udisksctl power-off -b /dev/disk/by-label/WDPurple8TB
    echo "Power-Off /dev/disk/by-label/WDPurple8TB"
fi

if findmnt --source UUID=151cf7f0-461a-416f-8e44-63d799418958 --source PARTLABEL=WDPurple6TB --mountpoint /media/ismail/WDPurple6TB --types ext4 --noheadings; then
    udisksctl unmount -b /dev/disk/by-label/WDPurple6TB
    udisksctl power-off -b /dev/disk/by-label/WDPurple6TB
    echo "Power-Off /dev/disk/by-label/WDPurple6TB"
fi

ここでは、2つのif-fiブロックを並列に実行する方が良いでしょう。ただし、if-fiブロックのstdoutとstderrはグループ化する必要があります(両方の出力が重複してはいけません)。私の言葉は:

最後に達すると、次の3行のstdoutとstderrが表示されます。最初if-fiコードブロック。

udisksctl unmount -b /dev/disk/by-label/WDPurple8TB
udisksctl power-off -b /dev/disk/by-label/WDPurple8TB
echo "Power-Off /dev/disk/by-label/WDPurple8TB"

最後に達すると、次の3行のstdoutとstderrが表示されます。第二if-fiコードブロック。

udisksctl unmount -b /dev/disk/by-label/WDPurple6TB
udisksctl power-off -b /dev/disk/by-label/WDPurple6TB
echo "Power-Off /dev/disk/by-label/WDPurple6TB"

どうすればいいですか?

ベストアンサー1

これらの出力(およびエラー)をシリアル化するには、その出力の1つ以上を一時的に保存する必要があります。

#! /bin/zsh -
ret=0
umask 077 # for temp files that we recreate
if findmnt --source UUID=309689b5-ea5c-4175-84c7-192631553eab --source PARTLABEL=WDPurple8TB --mountpoint /media/ismail/WDPurple8TB --types ext4 --noheadings; then
    udisksctl unmount -b /dev/disk/by-label/WDPurple8TB &&
      udisksctl power-off -b /dev/disk/by-label/WDPurple8TB &&
      echo "Power-Off /dev/disk/by-label/WDPurple8TB"
fi & pid=$!

out==() err==()
if findmnt --source UUID=151cf7f0-461a-416f-8e44-63d799418958 --source PARTLABEL=WDPurple6TB --mountpoint /media/ismail/WDPurple6TB --types ext4 --noheadings; then
    udisksctl unmount -b /dev/disk/by-label/WDPurple6TB &&
      udisksctl power-off -b /dev/disk/by-label/WDPurple6TB &&
      echo "Power-Off /dev/disk/by-label/WDPurple6TB"
fi > $out 2> $err || ret=$?

wait $pid || ret=$?

# dump the second job's errors on stderr
cat<$err >&2

# and its output to stdout:
cat<$out

# clean up the temp files
rm -f -- $out $err

# report failure if any of any of those two jobs
exit $ret

ここでは、プロセスzsh置換を使用して一時ファイルが作成されます=(...)。 shまたはbashを使用すると、mktempシステムで利用可能なすべてのコマンドを使用して一時ファイルを安全に生成できます。

厳密に言えば、=(cmd)拡張コマンドが完了するとzshは一時ファイルを削除するため、これは使用されていません。ここでは、後で同じパスを使用してファイルを再生成するため、悪意のある攻撃者がファイルをシンボリックリンクとして再生成できる小さなウィンドウがあるため、厳密に安全ではありません。

並列オフロードの数に関係なく、状況を少し細分化できます。削除したい一時ファイルを最初から削除し、上記の問題を解決してクリーンアップするためにfdsを開くこともできます。

#! /bin/zsh -
zmodload zsh/system || exit
out=() err_read=() err_write=() out_read=() out_write=() pid=()
n=1 ret=0

stop_disk() {
  local uuid=$1 label=$2
  if
    findmnt --source UUID=$uuid \
            --source PARTLABEL=$label \
            --mountpoint /media/ismail/$label \
            --types ext4 \
            --noheadings
  then
    udisksctl unmount -b /dev/disk/by-label/$label &&
      udisksctl power-off -b /dev/disk/by-label/$label &&
      print -r "Power-Off /dev/disk/by-label/$label"
  fi
}

for uuid label (
  309689b5-ea5c-4175-84c7-192631553eab WDPurple8TB
  151cf7f0-461a-416f-8e44-63d799418958 WDPurple6TB
) {
  () {
     sysopen -wo cloexec -u out -- $1 &&
       sysopen -ro cloexec -u in -- $1 &&
       err_write[n]=$out err_read[n]=$in &&
       sysopen -wo cloexec -u out -- $2 &&
       sysopen -ro cloexec -u in -- $2 &&
       out_write[n]=$out out_read[n]=$in
  } =() =() || exit

  stop_disk $uuid $label >&$out_write[n] 2>&$err_write[n] &
  pid[n++]=$!
}

for (( i = 1; i <= n; i++ )) {
  wait $pid[i] || ret=$?
  cat <&$err_read[i] >&2
  cat <&$out_read[i]
}

exit $ret

(テストされていません)

おすすめ記事