首页
学习
活动
专区
圈层
工具
发布
社区首页 >问答首页 >使用yq更新数组值

使用yq更新数组值
EN

Stack Overflow用户
提问于 2022-01-31 20:22:25
回答 2查看 321关注 0票数 0

我有两个yaml文件正在使用。第一个yaml文件如下所示:

spring.yml

代码语言:javascript
复制
spring:
  cloud:
    gateway:
      routes:
      - id: someid
        uri: someUri
        predicates:
        - Path=/somePath
        filters:
        - RewritePath=/someOtherPath

我有另一个文件,它只包含路由,如下所示:

routes.yml

代码语言:javascript
复制
routes:
  - id: someid
    uri: someOtherUri
    predicates:
    - Path=/somePath
    filters:
    - RewritePath=/someNewPath

我的目标是用第二个文件中路由的值更新第一个文件中的路由。注意,实际中的第一个文件将有许多路由,但为了演示目的,我只显示本例中的第一个。我有下面的脚本,当id匹配时,它循环起来更新路由:

代码语言:javascript
复制
#!/bin/sh
OVERRIDE_ROUTE_IDS=$(yq eval '.routes.[].id' routes.yml)
GENERATED_ROUTE_IDS=$(yq eval '.spring.cloud.gateway.routes.[].id' spring.yml)

SAVEIFS=$IFS   # Save current IFS (Internal Field Separator)
IFS=$'\n'      # Change IFS to newline char
OVERRIDE_ROUTE_IDS=($OVERRIDE_ROUTE_IDS) # split the `OVERRIDE_ROUTE_IDS` string into an array by the same name
GENERATED_ROUTE_IDS=($GENERATED_ROUTE_IDS) # split the `GENERATED_ROUTE_IDS` string into an array by the same name
IFS=$SAVEIFS   # Restore original IFS

for (( i=0; i<${#OVERRIDE_ROUTE_IDS[@]}; i++ ))
do
   if [[ "${GENERATED_ROUTE_IDS[*]}" =~ "${OVERRIDE_ROUTE_IDS[$i]}" ]]
   then
      echo "route ID ${OVERRIDE_ROUTE_IDS[$i]} exists in generated routes"
      for (( j=0; j<${#GENERATED_ROUTE_IDS[@]}; j++ ))
      do
         if [[ "${GENERATED_ROUTE_IDS[$j]}" == "${OVERRIDE_ROUTE_IDS[$i]}" ]]
         then
            echo "index of route ${GENERATED_ROUTE_IDS[$j]} is $j"
            echo "$i"
            ROUTE_TO_USE=$(yq eval ".routes.[$i]" routes.yml)
            $(yq ".spring.cloud.gateway.routes.[$j] = $ROUTE_TO_USE" spring.yml)
         fi
      done
   else
      echo "no match so add to top of routes"
   fi
done

我的假设是,这个命令应该用新的路径来更新spring.yml文件,而不是用相同的id标识的路径:

代码语言:javascript
复制
$(yq ".spring.cloud.gateway.routes.[$j] = $ROUTE_TO_USE" application.yml)

但是我得到了以下错误

代码语言:javascript
复制
Error: Parsing expression: Lexer error: could not match text starting at 1:37 failing at 1:39 unmatched text: "id"

我被困在这件事上,不知道自己在做什么。作为参考,我使用的是yq版本4.17.2。

EN

回答 2

Stack Overflow用户

发布于 2022-02-01 13:40:53

请注意,yq不会发出数据结构,它会发出一个字符串。例如,$ROUTE_TO_USE将是,

代码语言:javascript
复制
id: someid
uri: someOtherUri
predicates:
  - Path=/somePath
filters:
  - RewritePath=/someNewPath

这是YAML的来源。将其粘贴到以下yq命令中将导致无效语法;yq的表达式语法不是文字YAML。这是错误试图告诉您的。

您要做的是在一个yq命令中处理两个输入:

代码语言:javascript
复制
yq ea "select(fi==0).spring.cloud.gateway.routes.[$j] = "`
     `"select(fi==1).routes.[$i] | select(fi==0)" spring.yml routes.yml

eaeval-all的缩写,您需要它同时处理多个输入文件。fifileIndex的缩写,用于选择适当的文件。将结果传递给| select(fi==0)确保只写入第一个(修改的)文件。为了提高可读性,我将长字符串拆分为多行using backticks

票数 0
EN

Stack Overflow用户

发布于 2022-02-04 02:51:22

最后,我从yq的创建者那里得到了一个解决方案。下面的解决方案是我所使用的:

代码语言:javascript
复制
yq ea '
  (select(fi==0) | .spring.cloud.gateway.routes.[].id) as $currentIds |
  (select(fi==1) | [.routes.[] | select( [$currentIds != .id] | all )] ) as $newRoutes |
  ( $newRoutes + .spring.cloud.gateway.routes + .routes) as $routesToMerge |

  (
    (($routesToMerge | .[] | {.id: .}) as $item ireduce ({}; . * $item )) as $uniqueMap
    | ( $uniqueMap  | to_entries | .[]) as $item ireduce([]; . + $item.value)
  ) as $mergedArray
  | select(fi == 0) | .spring.cloud.gateway.routes = $mergedArray  

' spring.yml routes.yml

这在id上是匹配的。如果有匹配,则使用routes.yml中的值。如果没有匹配,则将其添加到路由的顶部。

票数 0
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/70932362

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档