Bash参数扩展,间接引用和背景

时间:2017-05-10 01:45:34

标签: arrays bash for-loop associative-array variable-declaration

在这个问题上挣扎了好几个小时并在这里搜索并没有找到匹配的解决方案之后,现在是时候问:

在bash(4.3)中,我尝试组合以下内容:

  • 创建数组
  • 使用不超快的命令循环遍历数组的值(卷曲到Web服务器以获取值),因此我们将每个循环背景化以使所有内容并行化以加速它。
  • 将数组中值的名称设置为分配给从命令重定向到的值的变量,通过" read"
  • 后台每个循环并将其PID转换为常规数组,将每个PID与关联数组中的相关数组值相关联,因此我将数组值名称的键=值对与PID
  • 使用"等待"等待每个PID退出0或抛出一个错误,告诉我们数组中的哪个值名称无法通过引用关联数组退出0
  • 我需要能够导出原始数组中的所有VAR名称及其现在关联的值(来自curl命令结果),因为我从另一个将使用结果导出的bash脚本中获取此脚本的VAR /值。

我使用"读"的原因而不只是" export"用"导出var = $(命令)"或类似的,是因为我在后台并获得PID使用"等待"在下一个for循环中,我实际上(错误地)得到" export"的PID。总是退出0的命令,所以我没有检测到错误。当我使用带有重定向的read来设置VAR的值(来自数组中的名称)和背景时,它实际上获得了命令的PID,并且我在下一个循环中捕获了任何错误" wait&#34 ;命令。

所以,基本上,这似乎很有效,除了我意识到"阅读"命令实际上似乎没有正确地将变量替换为数组名称值,重定向命令将其输出发送到该名称,以便将替换的VAR名称设置为值。或者,也许命令完全错误,所以我没有正确地将我的命令结果重定向到我尝试设置的VAR名称。

当我运行卷曲时,它的价值是什么手动python命令(拉取值然后解析JSON输出)它肯定是成功的,所以我知道它正在工作,我只是无法获得重定向以将结果输出发送到VAR名称

以下是我尝试做的一个例子: 在父脚本中:

# Source the child script that has the functions I need
source functions.sh

# Create the array
VALUES=(
VALUE_A
VALUE_B
VALUE_C
)

# Call the function sourced from the script above, which will use the above defined array
function_getvalues

在子(源)脚本中:

function_getvalues()
{
  curl_pids=( )
  declare -A value_pids
  for value in "${VALUES[@]}"; do
    read ${value} < <(curl -f -s -X GET http://path/to/json/value | python3 -c "import sys, json; print(json.load(sys.stdin)['data']['value'])") & curl_pids+=( $! ) value_pids+=([$!]=${value})
  done
  for pid in "${curl_pids[@]}"; do
    wait "$pid" && echo "Successfully retrieved value ${value_pids[$pid]} from Webserver." || { echo "Something went wrong retrieving value ${value_pids[$pid]}, so we couldn't get the output data needed from Webserver. Exiting." ; exit 1 ; }
  done
}

1 个答案:

答案 0 :(得分:1)

问题在于read,在后台运行时,isn't connected为标准。 [details] 请考虑这个简化的工作示例,注释如何削弱它:

VALUES=( VALUE_A VALUE_B )
for value in "${VALUES[@]}"; do
    read ${value} < <(echo ${RANDOM}) # add "&" and it stops working
done
echo "VALUE_A=${VALUE_A}"
echo "VALUE_B=${VALUE_B}"

可能能够使用coproc或使用read -u with automatic file descriptor allocation执行此操作,但实际上这是临时文件的作业:

tmpdir=$(mktemp -d)

VALUES=( VALUE_A VALUE_B )
for value in "${VALUES[@]}"; do
    (sleep 1; echo ${RANDOM} > "${tmpdir}"/"${value}") &
done
for value in "${VALUES[@]}"; do
    wait_file "${tmpdir}"/"${value}" && {
        read -r ${value} < "${tmpdir}"/"${value}";
    }
done
echo "VALUE_A=${VALUE_A}"
echo "VALUE_B=${VALUE_B}"

rm -r "${tmpdir}"

此示例使用wait_file helper,但如果您不介意操作系统的某些依赖项,则可以使用inotifywait