替换为转义的shell字符串?

问题描述 投票:0回答:2

我想将ruby变量替换为转义的shell字符串。

这是我的开始,它的工作原理:

<<~`SHELL`
  curl -s "#{CANVAS_URI}/api/v1/courses/#{COURSE_ID}/quizzes/#{quiz_id}/questions" \
    -X POST \
    -H "Content-Type: application/json" \
    -d '{ "question": { "question_type": "multiple_choice_question", "question_text": "<p>Is everything clear?</p>", "points_possible": 1, "answers": [ { "text": "I read and understood", "html": "", "weight": 100 }, { "text": "I have questions", "comments_html": "<p>Please post your questions to a discussion (in course navigation).</p>", "weight": 0 } ] } }' \
    -H "Authorization: Bearer #{CANVAS_TOKEN}"
SHELL

但是我希望discussion(在-d JSON中)成为一个链接。并且不能让它工作:

myJson = %Q|{ "question": { "question_type": "multiple_choice_question", "question_text": "<p>Is everything clear?</p>", "points_possible": 1, "answers": [ { "text": "I read and understood", "html": "", "weight": 100 }, { "text": "I have questions", "comments_html": "<p>Please post your questions to a <a href="#{CANVAS_URI}/courses/#{COURSE_ID}/discussion_topics">discussion</a>.</p>", "weight": 0 } ] } }|

<<~`SHELL`
  curl -s "#{CANVAS_URI}/api/v1/courses/#{COURSE_ID}/quizzes/#{quiz_id}/questions" \
    -X POST \
    -H "Content-Type: application/json" \
    -d '#{myJson}' \
    -H "Authorization: Bearer #{CANVAS_TOKEN}"
SHELL

<<~`SHELL`
  curl -s "#{CANVAS_URI}/api/v1/courses/#{COURSE_ID}/quizzes/#{quiz_id}/questions" \
    -X POST \
    -H "Content-Type: application/json" \
    -d "#{myJson}" \
    -H "Authorization: Bearer #{CANVAS_TOKEN}"
SHELL

我被困在逃离两个郎之间。

整个过程是在ruby中发布嵌套json的解决方法。平面jsons适用于大多数http宝石,但获得嵌套json是一种罕见的需求,我担心大多数宝石没有测试它(我记得尝试http.rb来做到这一点,但即使是json数组也是non trivial there

ruby bash
2个回答
3
投票

要解决你的问题,你必须小心逃避Shellwords.escape的一切,然后不引用它们。

<<~`SHELL`
  curl -s "#{CANVAS_URI}/api/v1/courses/#{COURSE_ID}/quizzes/#{quiz_id}/questions" \
    -X POST \
    -H "Content-Type: application/json" \
    -d #{Shellwords.escape(myJson)} \
    -H "Authorization: Bearer #{CANVAS_TOKEN}"
SHELL

但这很乏味且容易出错,而不是你的问题。

整个过程是在ruby中发布嵌套json的解决方法。平面jsons适用于大多数http宝石,但获得嵌套json是一种罕见的需求,我担心大多数宝石都没有测试它...

嵌套的JSON并不罕见,无论如何,http客户端应该没有理由关注JSON的内容。它只是传输一个字符串。

你的JSON格式不正确。具体在这里:

"comments_html": "<p>Please post your questions to a <a href="#{CANVAS_URI}/courses/#{COURSE_ID}/discussion_topics">discussion</a>.</p>"

你有一个未转义的报价。这可能是因为您手动将嵌套的JSON放在一起。像炮轰一样卷曲,这很容易出错。


相反,创建一个Ruby哈希并将其转换为JSON。然后,您将获得Ruby语法检查的所有好处。

payload = {
  question: {
    question_type: "multiple_choice_question",
    question_text: "<p>Is everything clear?</p>",
    points_possible: 1,
    answers: [
      {
        text: "I read and understood", 
        html: "", 
        weight: 100
      }, {
        text: "I have questions",
        comments_html: %Q[<p>Please post your questions to a <a href="#{CANVAS_URI}/courses/#{COURSE_ID}/discussion_topics">discussion</a>.</p>],
        weight: 0
      }
    ]
  }
}

require "json"
json_payload = JSON.generate(payload)

而不是调用curl,使用http库。由于您正在调用REST API,因此可以使用RestClient

require "rest-client"
response = RestClient.post(
  "#{CANVAS_URI}/api/v1/courses/#{COURSE_ID}/quizzes/#{quiz_id}/questions",
  json_payload,
  { content_type: :json, authorization: "Bearer #{CANVAS_TOKEN}" }
)

或者,更好的是,使用负责JSON转换的canvas-api gem,并可以利用分页等API功能。

canvas = Canvas::API.new(:host => CANVAS_URI, :token => CANVAS_TOKEN)
response = canvas.post(
    "/api/v1/courses/#{COURSE_ID}/quizzes/#{quiz_id}/questions",
    payload
)

3
投票

我认为你采取了错误的做法。混合字符串插值与反引号或Kernel#system的单个参数版本是混乱和危险的。你最好完全绕过shell及其引用问题并使用system的多参数形式:

system(
  'curl',
  '-s', "#{CANVAS_URI}/api/v1/courses/#{COURSE_ID}/quizzes/#{quiz_id}/questions",
  '-X', 'POST',
  '-H', "Content-Type: application/json",
  '-d', myJson,
  '-H', "Authorization: Bearer #{CANVAS_TOKEN}"
)

这将使用提供的参数直接执行curl,而根本不涉及shell。如果你需要保存curl的响应,请使用标准库中的Open3并再次避免shell及其引用问题。

© www.soinside.com 2019 - 2024. All rights reserved.