【问题标题】:Substitute to an escaped shell string?替代转义的外壳字符串?
【发布时间】:2018-06-01 02:05:06
【问题描述】:

我想将 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

我被困在两个 langs 的逃脱之间。

整个事情是在 ruby​​ 中发布嵌套 json 的解决方法。 Flat jsons 适用于大多数 http gem,但是很少需要嵌套 json,恐怕大多数 gem 都没有针对它进行测试(我记得尝试过 http.rb 这样做,但即使是 json 数组也是non trivial there .

【问题讨论】:

    标签: ruby bash


    【解决方案1】:

    要解决您的问题,您必须小心使用 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 的解决方法。 flat jsons 在大多数 http gem 中都可以使用,但是获取嵌套 json 是一种罕见的需求,恐怕大多数 gem 都没有针对它进行测试...

    嵌套 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}" }
    )
    

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

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

    【讨论】:

    • 我喜欢 RestClient 和 Canvas 方法,反引号(和 system(command_string))以“无用使用猫”排名靠前(除了猫也很生气并挥舞着剃须刀)。
    【解决方案2】:

    我认为你采取了错误的方法。将字符串插值与反引号或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 及其引用问题。

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 2019-05-19
      • 1970-01-01
      • 1970-01-01
      • 2016-10-26
      • 1970-01-01
      • 2015-01-17
      • 2017-08-31
      • 1970-01-01
      相关资源
      最近更新 更多