【问题标题】:Bash parameter expansion, indirect reference, and backgroundingBash 参数扩展、间接引用和背景
【发布时间】:2017-10-08 12:05:01
【问题描述】:

在为这个问题苦苦挣扎了几个小时并在此处搜索并未能提出匹配的解决方案之后,是时候提问了:

在 bash (4.3) 中,我尝试结合以下操作:

  • 创建数组
  • For 使用不是超快的命令循环遍历数组的值(卷曲到 Web 服务器以获取值),因此我们将每个循环置于后台以并行化所有内容以加快速度。
  • 将数组中的值的名称设置为分配给通过“读取”命令从命令重定向到它的值的变量
  • 将每个循环作为背景并将它们的 PID 放入一个常规数组中,并且将每个 PID 与关联数组中的相关数组值相关联,这样我就有了 PID 的数组值名称的键=值对李>
  • 使用“wait”等待每个 PID 退出 0 或抛出错误,告诉我们数组中的哪个值名称未能通过引用关联数组以 0 退出
  • 我需要能够导出原始数组中的所有 VAR 名称及其现在关联的值(来自 curl 命令结果),因为我从另一个 bash 脚本中获取此脚本,该脚本将使用生成的导出 VAR/价值观。

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

所以,基本上,这似乎主要工作,除了我意识到“读取”命令实际上并没有以重定向的方式正确地将变量替换为数组名称值命令将其输出发送到该名称,以便将替换的 VAR 名称设置为一个值。或者,也许该命令完全错误,所以我没有正确地将命令的结果重定向到我尝试设置的 VAR 名称。

对于它的价值,当我运行 curl |手动 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
}

【问题讨论】:

  • 我尝试添加 echo 命令以查看 var(从数组中循环的变量名称)设置为什么,它们是空白的。我不确定这是否意味着它们根本没有使用读取命令声明(即替换不起作用),或者我的读取重定向中的错误是否无法将命令的输出发送到 VAR名称来设置它。
  • 抱歉,python json 解析后 curl 命令的预期输出是一个字符串。如果我手动运行 curl |python,我会得到预期的输出,而不是读取重定向。
  • 另外我使用 python 而不是 jq,因为 a) 我对 python 更满意,b) 我试图将依赖关系保持在最低限度,我们的团队都有 python。跨度>
  • 哦,& 在

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


【解决方案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

【讨论】:

  • 有趣的解决方案,感谢 Bishop。阅读失去与标准输入的联系是完全有道理的;当我最初考虑使用“导出”命令时,我也有同样的担忧。我对这个解决方案确实有一点不满:我们的许多将运行它的开发人员都在 OS X 上,而且我读到 mktemp 在那里的行为不同。有什么见解吗?我当然也可以研究这个。
  • 是的,mktemp 存在可移植性问题。有关分辨率,请参阅例如 unix.stackexchange.com/a/84980/50240
  • 我能够测试 'mktemp -d' 在 OS X(最新)和 Linux 上的工作方式相同,至少在我们的开发人员使用的系统上,所以这对我来说足够好和便携.
  • 太棒了。如果此答案解决了问题,请接受并投票。欢迎来到 SO!
  • 我成功地将我的函数转换为使用描述的临时文件,它运行良好。谢谢!
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2012-10-10
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多