Search code examples
bashapicurlenvironment-variablespushbullet

Bash: Command output as variable to curl error


I trying to get this bash script to run a speedtest (speedtest-cli) then pass the output as a variable to pushbullet via curl.

#!/bin/bash
speed=$(speedtest --simple)
curl --header 'Access-Token: <-ACCESS-TOKEN->' \
     --header 'Content-Type: application/json' \
     --data-binary {"body":"'"$speed"'","title":"SpeedTest","type":"note"}' \
     --request POST \
     https://api.pushbullet.com/v2/pushes

Other commands have worked well using this method (eg. whoami) but speedtest and ifconfig just get an error like this:

{"error":{"code":"invalid_request","type":"invalid_request","message":"Failed to decode JSON body.","cat":"(=^‥^=)"},"error_code":"invalid_request"}

Solution

  • Your quoting is wrong:

    speed=$(speedtest --simple)
    curl --header 'Access-Token: o.4q87SC5INy6nMQZqVHJeymwRsvMXW74j' \
         --header 'Content-Type: application/json' \
         --data-binary "{\"body\":\"$speed\",\"title\":\"SpeedTest\",\"type\":\"note\"}" \
         --request POST \
         https://api.pushbullet.com/v2/pushes
    

    Reading from a here document simplifies the quoting:

    speed=$(speedtest --simple)
    curl --header 'Access-Token: o.4q87SC5INy6nMQZqVHJeymwRsvMXW74j' \
         --header 'Content-Type: application/json' \
         --data-binary @- \
         --request POST \
         https://api.pushbullet.com/v2/pushes <<EOF
    { "body": "$speed",
      "title": "SpeedTest",
      "type": "note"
    }
    EOF
    

    However, in general you should not assume that the contents of the variable are a properly encoded JSON string, so use a tool like jq to generate the JSON for you.

    jq -n --arg data "$(speedtest --simple)" \
       '{body: $data, title: "SpeedTest", type: "note"}' | 
     curl --header 'Access-Token: o.4q87SC5INy6nMQZqVHJeymwRsvMXW74j' \
          --header 'Content-Type: application/json' \
          --data-binary @- \
          --request POST \
          https://api.pushbullet.com/v2/pushes
    

    This can be refactored easily:

    post_data () {
      url=$1
      token=$2
      data=$3
    
      jq -n --arg d "$data" \
       '{body: $d, title: "SpeedTest", type: "note"}' | 
       curl --header "Access-Token: $token" \
            --header 'Content-Type: application/json' \
            --data-binary @- \
            --request POST \
            "$url"
    }
    
    post_data "https://api.pushbullet.com/v2/pushes" \
              "o.4q87SC5INy6nMQZqVHJeymwRsvMXW74j" \
              "$(speedtest ---simple)"