bash配列を埋めるために使用されたforループの結果をzenity --progressにパイプすると、なぜbash配列がまだ空になるのですか?

bash配列を埋めるために使用されたforループの結果をzenity --progressにパイプすると、なぜbash配列がまだ空になるのですか?

一部のデータを含む配列があります。

array1=( AAA BBB CCC DDD )

特定のAPIを呼び出した結果の配列をデータで埋めたいと思います。だから私は次のようにarray1使用しようとしていますzenity

i=0
prog=0

for c in ${array1[@]}; do
  echo $prog  #updates the text
  echo "# $c" #updates the percentage

  data_array[$i]=$(curl -s "https://hub.dummyapis.com/products?noofRecords=4&idStarts=1001&useless=$c" | jq .[$i].id | bc)

  (( prog=prog+30 ))
  (( i++ ))
done | zenity \
    --progress \
    --title="Title" \
    --text="Text" \
    --percentage=0 \
    --auto-close \
    --auto-kill

問題はdata_arrayまだ空であるということだ。

一方、zenityコマンドからパイプを省略すると埋められます。私が正しく理解したなら、パイプは新しいサブプロセスを生成するのでdata_array空です。

また、この構文を試しましたが、結果は同じでした。

zenity \
    --progress \
    --title="Title" \
    --text="Text" \
    --percentage=0 \
    --auto-close \
    --auto-kill < <(
for c in ${array1[@]}; do
  echo $prog
  echo "# $c"

  data_array[$i]=$(curl -s "https://hub.dummyapis.com/products?noofRecords=4&idStarts=1001&useless=$c" | jq .[$i].id | bc)

  (( prog=prog+30 ))
  (( i++ ))
done)

どうですか?

答え1

パイプラインのさまざまな部分がサブシェルで実行されます。 (Bashでは、lastpipe最後の部分がデフォルトシェルで実行されるようにするオプションを有効にできますが、ここでは役に立ちません。)プロセス置換もサブシェルで実行されますが、基本部分が同じ操作を実行することは強制しません。

zenityプロセス交換を入れて forメインシェルに保管してください。

for c in ${array1[@]}; do
  ...
  data_array[$i]=...
  ...
done > >( zenity \
    --progress \
    --title="Title" \
    --text="Text" \
    --percentage=0 \
    --auto-close \
    --auto-kill )

答え2

別の可能性:最初の例では交換

data_array[$i]=$(curl ... | jq ... | bc)

そして

curl ... | jq ... | bc >> /tmp/so-q

コードの後に​​次を追加します。

mapfile -t data_array < /tmp/so-q
rm /tmp/so-q
declare -p data_array

安全な一時ファイルを生成するには、mktemp を使用できます。望むよりman mktemp

答え3

おそらくこれは最もエレガントな解決策ではありませんが、うまくいきます。

teeこれは、ループの出力をファイルに書き込み、zenity同時にファイルにパイプする方法に依存します。

上記のダミーコードを使用すると、次のようになります。

array1=( AAA BBB CCC DDD )

curl_cmd() {
  curl -s "https://hub.dummyapis.com/products?noofRecords=4&idStarts=1001&useless=$1" | jq .[$2].id | bc
}

i=0
prog=0

for c in ${array1[@]}; do
  #updates the text
  echo $prog
  #updates the percentage
  echo "# $c"

  #echo the data I'm interested in, 
  #with a @ for later reference
  echo "@ $(curl_cmd $c $i)" 

  (( prog=prog+30 ))
  (( i++ ))
done | tee >(zenity \
    --progress \
    --title="Title" \
    --text="Text" \
    --percentage=0 \
    --auto-close \
    --auto-kill) > /tmp/so-q

data_array=( $(grep @ /tmp/so-q | cut -c 2-) )

今やdata_arrayついにその中に人が住んでいる

~ $ echo ${data_array[@]}
1001 1002 1003 1004

関連情報