如果我将用于填充它的 for 循环的结果通过管道传输到 zenity --progress 中,为什么 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

管道的各个部分在子 shell 中运行。 (在 Bash 中,您可以启用该lastpipe选项以使最后一部分在主 shell 中运行,但这在这里没有帮助。)进程替换也在子 shell 中运行,但它们不会强制主要部分也这样做。

放入 zenity进程替换并将其保留for在主 shell 中:

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

相关内容