代码之家  ›  专栏  ›  技术社区  ›  Adobe

替换为转义的shell字符串?

  •  0
  • Adobe  · 技术社区  · 6 年前

    我想用一个转义的shell字符串替换ruby变量。

    这是我的开始,它起作用:

    <<~`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 (在A中) -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的解决方案。平面json在大多数http gems中都可以工作,但是很少需要嵌套json,而且恐怕大多数gems都没有针对它进行测试(我记得曾经尝试过http.rb这样做,但是即使json数组也是 non trivial there .

    2 回复  |  直到 6 年前
        1
  •  3
  •   Schwern    6 年前

    要解决你的问题,你必须小心逃避一切 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的解决方案。平面json在大多数http gems中都可以工作,但是很少需要嵌套json,恐怕大多数gems都没有针对它进行测试……

    嵌套的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
    )
    
        2
  •  3
  •   mu is too short    6 年前

    我认为你走错了路。将字符串插值与反勾号或单参数版本的 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。如果你需要拯救 卷曲 的响应,使用 Open3 从标准库中再次避免shell及其引用问题。