简体   繁体   English

Bash参数扩展,间接引用和后台处理

[英]Bash parameter expansion, indirect reference, and backgrounding

After struggling with this issue for several hours and searching here and failing to come up with a matching solution, it's time to ask: 在这个问题上挣扎了几个小时并在这里搜索并且没有找到匹配的解决方案之后,是时候问:

In bash (4.3) I'm attempting to do a combination of the following: 在bash(4.3)中我试图做以下的组合:

  • Create an array 创建一个数组
  • For loop through the values of the array with a command that isn't super fast (curl to a web server to get a value), so we background each loop to parallelize everything to speed it up. 对于使用不是超快的命令来循环遍历数组的值(卷曲到Web服务器以获取值),因此我们对每个循环进行后台处理以使所有内容并行化以加速它。
  • Set the names of the values in the array to variables assigned to values redirected to it from a command via "read" 将数组中的值的名称设置为分配给通过“read”从命令重定向到的值的变量
  • Background each loop and get their PID into a regular array, and associate each PID with the related array value in an associative array so I have key=value pairs of array value name to PID 后台每个循环并将它们的PID转换为常规数组, 并将每个PID与关联数组中的相关数组值相关联,因此我将数组值名称的键=值对与PID相关联
  • Use "wait" to wait for each PID to exit 0 or throw an error telling us which value name(s) in the array failed to exit with 0 by referencing the associative array 使用“wait”等待每个PID退出0或抛出错误,告诉我们通过引用关联数组,数组中的哪个值名称无法以0退出
  • I need to be able export all of the VAR names in the original array and their now-associated values (from the curl command results) because I'm sourcing this script from another bash script that will use the resulting exported VARs/values. 我需要能够导出原始数组中的所有VAR名称及其现在关联的值(来自curl命令结果),因为我从另一个将使用结果导出的VAR /值的bash脚本中获取此脚本。

The reason I'm using "read" instead of just "export" with "export var=$(command)" or similar, is because when I background and get the PID to use "wait" with in the next for loop, I actually (incorrectly) get the PID of the "export" command which always exits 0, so I don't detect an error. 我使用“read”而不是“export”与“export var = $(command)”或类似的原因,是因为当我在后台并获得PID在下一个for循环中使用“wait”时,我实际上(错误地)获取总是退出0的“export”命令的PID,所以我没有检测到错误。 When I use read with the redirect to set the value of the VAR (from name in the array) and background, it actually gets the PID of the command and I catch any errors in the next loop with the "wait" command. 当我使用带有重定向的read来设置VAR(来自数组中的名称)和后台的值时,它实际上获得了命令的PID,并且我使用“wait”命令在下一个循环中捕获任何错误。

So, basically, this mostly appears to work, except I realized the "read" command doesn't actually appear to be substituting the variable to the array name value properly in a way that the redirected command sends its output to that name in order to set the substituted VAR name to a value. 所以,基本上,这似乎很有效, 除了我意识到“读取”命令实际上似乎没有正确地将变量替换为数组名称值,重定向命令将其输出发送到该名称以便将替换VAR名称设置为值。 Or, maybe the command is just entirely wrong so I'm not correctly redirecting the result of my command to a VAR name I'm attempting to set. 或者,也许命令完全错误,所以我没有正确地将我的命令结果重定向到我试图设置的VAR名称。

For what it's worth, when I run the curl | 对于它的价值,当我运行卷曲| python command by hand (to pull the value and then parse the JSON output) it is definitely succeeding, so I know that's working, I just can't get the redirect to send the resulting output to the VAR name. 手工python命令(拉取值然后解析JSON输出)它肯定是成功的,所以我知道它正在工作,我只是无法获得重定向将结果输出发送到VAR名称。

Here's a example of what I'm trying to do: In parent script: 这是我正在尝试做的一个例子:在父脚本中:

# 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

In child (sourced) script: 在子(源)脚本中:

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
}

The problem is that read , when run in the background, isn't connected to a standard in. [details] Consider this simplified, working example with comment how to cripple it: 问题是,在后台运行时, read 没有连接到标准中。 [详情]请考虑这个简化的工作示例,注释如何削弱它:

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}"

You might be able to do this with coproc , or using read -u with automatic file descriptor allocation , but really this is a job for temporary files: 可以使用coproc执行此操作,或者使用带有自动文件描述符分配的read -u ,但实际上这是临时文件的作业:

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}"

This example uses wait_file helper , but you might use inotifywait if you don't mind some dependencies on OS. 此示例使用wait_file帮助程序 ,但如果您不介意操作系统的某些依赖项,则可以使用inotifywait

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM