如何将tee的输出重定向到变量/数组而非文件(curl+jq场景)
如何将tee的输出重定向到变量/数组而非文件(curl+jq场景)
兄弟我太懂你这痛点了!之前我也踩过bash子shell变量隔离的坑,咱们一步步把这个问题解决掉~
首先得给你说清楚为什么你之前的read my_array[index]没用:bash里的>(...)这种进程替换会创建一个子shell,子shell里的变量(包括你的数组)和父shell是完全隔离的——子shell里就算把值存进去了,父shell根本看不到,所以读完之后你的数组还是空的,这是bash的固有特性,不是你写的有问题!
接下来给你两个靠谱的解决方案,你可以根据自己的习惯选:
方案一:先存整个响应,再分别处理(最推荐,逻辑清晰)
其实完全不用tee分流,咱们先把curl的整个JSON响应存到一个变量里,再用jq分别提取dataId和next_token就行,这样完全绕开子shell的问题:
# 初始化变量和数组 next_token="your_initial_token" # 这里填API要求的初始token,比如空字符串或者第一个请求的默认值 my_array=() index=0 while [[ "$next_token" != "null" ]]; do # 先把curl的完整响应抓下来存到变量 response=$(curl -u "$user:$password" "https://mylink.dot") # 从响应里提取所有dataId,逐个追加到数组 # 用while read处理jq输出的每一行(因为dataSummaries是数组,可能多个id) while read -r data_id; do my_array[index]="$data_id" index=$((index + 1)) done < <(echo "$response" | jq -r '.dataSummaries[] | .dataId') # 提取下一页的next_token next_token=$(echo "$response" | jq -r '.nextToken') done # 测试一下数组内容 echo "所有提取到的dataId:" printf "%s\n" "${my_array[@]}"
这个方案的好处就是逻辑直白,所有变量和数组都在父shell里操作,绝对不会出现“存了但看不到”的情况。要是你的API可能返回空的dataSummaries数组,记得把jq的表达式改成.dataSummaries[]? | .dataId,加个问号就能忽略空数组的报错了。
方案二:用命名管道实现tee式分流(适合非要保留tee逻辑的场景)
如果你特别想用tee来分流响应,那可以用命名管道代替进程替换的子shell,让父shell直接从管道里读数据:
# 初始化变量 next_token="your_initial_token" my_array=() index=0 while [[ "$next_token" != "null" ]]; do # 创建两个临时命名管道 mkfifo data_pipe next_token_pipe # 用tee把curl响应分流到两个管道,同时把curl后台运行避免阻塞 curl -u "$user:$password" "https://mylink.dot" | tee >(jq -r '.dataSummaries[] | .dataId' > data_pipe) >(jq -r '.nextToken' > next_token_pipe) > /dev/null & # 从data_pipe里读dataId到数组 while read -r data_id; do my_array[index]="$data_id" index=$((index + 1)) done < data_pipe # 从next_token_pipe里读下一页的token read -r next_token < next_token_pipe # 用完管道记得删掉,避免残留 rm data_pipe next_token_pipe done # 验证结果 printf "提取到的dataId列表:\n%s\n" "${my_array[@]}" echo "最后获取的next_token:$next_token"
这个方案用命名管道作为数据中转,父shell直接从管道读数据,变量和数组都能正常保存。不过要注意创建管道后记得删除,不然下次运行可能出问题。
总的来说,方案一的可读性和维护性更好,除非你有特殊需求,不然优先选方案一就对了~
备注:内容来源于stack exchange,提问作者dzafer
相关产品推荐
相关产品推荐

