O envio de uma solicitação POST via curl apresenta problemas com aspas duplas

O envio de uma solicitação POST via curl apresenta problemas com aspas duplas

Então, para enviar uma solicitação POST para gists (github), você pode fazer algo assim como visto emhttps://gist.github.com/caspyi...

curl --user "user" -X POST --data '{"description":"Created via API","public":"true","files":{"file1.txt":{"content":"Demo"}}' https://api.github.com/gists

Mas, no exemplo acima, o nome do arquivo e o conteúdo do arquivo são codificados, o que é a parte .. file1.txt":{"content":"Demo"}..

Estou substituindo a parte acima pela minha variável, $file":{"content":"$content"}mas inicializo a variável, a solicitação json deve ser colocada entre aspas duplas, o que fiz como

curl --user "user" -X POST --data "{\"description\":\"Created via API\",\"public\":\"true\",\"files\":{\"$file\":{\"content\":\"$content\"}}' https://api.github.com/gists

Mas isso não funciona, recebo um erro json.

{
  "message": "Problems parsing JSON",
  "documentation_url": "https://developer.github.com/v3/gists/#create-a-gist"
}

Mesmo se eu substituísse todas as aspas duplas escapadas por \'aspas simples.

Alguém sabe como incluir uma variável dentro desta solicitação json? aliás: usei todos os cabeçalhos, como

 -H "Content-Type: application/json; charset=UTF-8" 

e muitas combinações para validar a solicitação, mas sem sucesso

ATUALIZAR.

É assim que todo o conteúdo se parece.

function gist_controller(){
    content=$(cat $1)
    DIR="$( cd "$( dirname "${BASH_SOURCE[0]}" )" && pwd )"
    read -p "enter your password - " pass 
    public="false"
    gist_content=$(cat $1)
    curl --user "samserayo"  -H "Content-Type: application/json; charset=UTF-8" -X POST -d  "{ 'description': 'Created via API', 'public': 'true', 'files':{ ' '$1 ':{ 'content': '$gist_content'}}" https://api.github.com/gists
}
ATUALIZAÇÃO 2

O arquivo que causa a falha do script (o arquivo que estou tentando enviar é)

<?php echo 'hello world' ?>

Responder1

Você não mostra qual valor definiu para $file ou $content. Para onde esses dois se expandem? É provável que um, ou outro, ou ambos, contenham caracteres que o analisador JSON não gosta. Muito provavelmente, algo dentro do valor de expansão da variável precisa ser escapado ou codificado antes do envio ao analisador JSON por meio de curl.

Você EXPORTOU as variáveis ​​de ambiente?

Tentar:

echo "$ arquivo $ conteúdo";

para ter certeza de que ambos estão configurados como você espera que estejam.

Responder2

Você não especificou qual shell está usando, mas qualquer coisa entre aspas duplas está sujeita à expansão do nome de arquivo do shell. Em particular, {} tem significado para a maioria dos shells. Essa é a razão pela qual o exemplo que você citou usou aspas simples para encerrar tudo.

As fugas de shell são complicadas e às vezes parece impossível conseguir o que deseja. Honestamente, em casos como esse eu escreveria um script Python para chamar curl, onde sei que o shell não está me "ajudando".

Responder3

Como isso foi revisado, aqui está outra resposta.

Escape das partes separadamente (feche o primeiro escape e depois escape sua variável):

curl --user "user" -X POST --data '{"description":"Created via API","public":"true","files":{"'"${file}"'":{"content":"'"${content}"'"}}}' https://api.github.com/gists

ou dividido para facilitar a leitura:

'{"description":"Created via API","public":"true","files":{"'
"${file}"
'":{"content":"'
"${content}"
'"}}}' 

Você pode ou não precisar alterar o separador de campo interno, para que o shell não interprete nenhum espaço em branco em suas variáveis.

MWE:cat /tmp/myfile | ./thisscript.sh "myfilename.txt"

#!/bin/sh

FILENAME="${1}"
#CONTENT="$(cat)"
CONTENT="$(sed -e 's/"/\\"/g')" # escape stuff

OFS="${IFS}"
IFS=''

PERSONAL_ACCESS_TOKEN="e5fa44f2b31c1fb553b6021e7360d07d5d91ff5e"

curl --user "username:${PERSONAL_ACCESS_TOKEN}" -X POST --data '{"description":"Created via API","public":"true","files":{"'"${FILENAME}"'":{"content":"'"${CONTENT}"'"}}}' https://api.github.com/gists
IFS="${OFS}"

Para que isso funcione corretamente, é claro que você ainda precisará escapar de todos os caracteres que quebrariam o JSON, no conteúdo do arquivo, como "caracteres de controle (retorno de carro do DOS), etc.
É ... lamentável que eles tenham decidido usar estruturas de dados JSON paraconteúdo do arquivouploads.


Se eu puder sugerir uma maneira diferente de criar Gists, use a curlchamada de API apenas para criar um único arquivo, digamos, READMEcom algum conteúdo padrão (não pode estar vazio).
Em seguida, execute grep na estrutura json retornada paragit_push_urleclonea essência do repositório git. Depois disso, você pode simplesmente git commitir git pushdireto ao ponto principal, sem se preocupar com dados binários ou problemas de escape.

Responder4

Aqui está uma solução, mas pressupõe duas coisas.

Que fileé um nome de arquivo fornecido ao script como primeiro argumento. E contenté o conteúdo do arquivo como text.

Observe também um URL POST diferente do seu (veja a explicação abaixo).

#!/bin/bash

file=$1
content=$(cat $1)

curl -H "Content-Type: application/json; charset=UTF-8" -X POST -d  "{ 'description': 'Created via API', 'public': 'true', 'files':{ ' '${file}':{ 'content': '${content}'}}" https://postman-echo.com/post

O arquivo content.txt contém:

This is content of the content file.

Exemplo de execução:

./curl.sh content.txt

Exemplo de saída:

{
  "args": {},
  "data": "{ 'description': 'Created via API', 'public': 'true', 'files':{ ' 'content.txt ':{ 'content': 'This is content of the content file.'}}",
  "files": {},
  "form": {},
  "headers": {
    "x-forwarded-proto": "https",
    "host": "postman-echo.com",
    "content-length": "134",
    "accept": "*/*",
    "content-type": "application/json; charset=UTF-8",
    "user-agent": "curl/7.65.3",
    "x-forwarded-port": "443"
  },
  "json": null,
  "url": "https://postman-echo.com/post"
}

NOTAS:

Estou usando aqui o https://postman-echo.com/postsite que ecoa tudo o que você publica como JSON.

Se o conteúdo do arquivo content.txt for mais complicado, esta solução poderá falhar, pois ainda precisará ser escapada adequadamente. O conteúdo está sendo colocado no campo "conteúdo" para que todas as regras de escape para json se apliquem aqui.

Para ver a resposta lindamente exibida (como json acima), adicione no final do curl | jq .(pode ser necessário instalá-lo primeiro):

https://postman-echo.com/post | jq . 

É possível usar jqpara citar automaticamente todo o arquivo de conteúdo (se necessário para uso mais avançado):

$ jq -Rs '.' content.txt
"This is just a text.\n"

$ jq -Rs '.' content.cpp
"#include <iostream>\nusing namespace std;\nint main() \n{\n    cout << \"Hello, World!\";\n    return 0;\n}\n"

Você terá que modificar ligeiramente o script curl.shpara que funcione:

content=$(jq -Rs '.' $1)

informação relacionada