Usando curl POST com variáveis ​​definidas nas funções de script bash

176

Quando eco, recebo isso, que é executado quando o insiro no terminal

curl -i \
-H "Accept: application/json" \
-H "Content-Type:application/json" \
-X POST --data '{"account":{"email":"[email protected]","screenName":"akdgdtk","type":"NIKE","passwordSettings":{"password":"Starwars1","passwordConfirm":"Starwars1"}},"firstName":"Test","lastName":"User","middleName":"ObiWan","locale":"en_US","registrationSiteId":"520","receiveEmail":"false","dateOfBirth":"1984-12-25","mobileNumber":"9175555555","gender":"male","fuelActivationDate":"2010-10-22","postalCode":"10022","country":"US","city":"Beverton","state":"OR","bio":"This is a test user","jpFirstNameKana":"unsure","jpLastNameKana":"ofthis","height":"80","weight":"175","distanceUnit":"MILES","weightUnit":"POUNDS","heightUnit":"FT/INCHES"}' https://xxx:xxxxx@xxxx-www.xxxxx.com/xxxxx/xxxx/xxxx

Mas quando executado no arquivo de script bash, recebo este erro

curl: (6) Could not resolve host: application; nodename nor servname provided, or not known
curl: (6) Could not resolve host: is; nodename nor servname provided, or not known
curl: (6) Could not resolve host: a; nodename nor servname provided, or not known
curl: (6) Could not resolve host: test; nodename nor servname provided, or not known
curl: (3) [globbing] unmatched close brace/bracket at pos 158

este é o código no arquivo

curl -i \
-H '"'Accept: application/json'"' \
-H '"'Content-Type:application/json'"' \
-X POST --data "'"'{"account":{"email":"'$email'","screenName":"'$screenName'","type":"'$theType'","passwordSettings":{"password":"'$password'","passwordConfirm":"'$password'"}},"firstName":"'$firstName'","lastName":"'$lastName'","middleName":"'$middleName'","locale":"'$locale'","registrationSiteId":"'$registrationSiteId'","receiveEmail":"'$receiveEmail'","dateOfBirth":"'$dob'","mobileNumber":"'$mobileNumber'","gender":"'$gender'","fuelActivationDate":"'$fuelActivationDate'","postalCode":"'$postalCode'","country":"'$country'","city":"'$city'","state":"'$state'","bio":"'$bio'","jpFirstNameKana":"'$jpFirstNameKana'","jpLastNameKana":"'$jpLastNameKana'","height":"'$height'","weight":"'$weight'","distanceUnit":"MILES","weightUnit":"POUNDS","heightUnit":"FT/INCHES"}'"'" "https://xxx:[email protected]/xxxxx/xxxx/xxxx"

Suponho que exista um problema com minhas aspas, mas eu brinquei muito com elas e obtive erros semelhantes. Todas as variáveis ​​são definidas com diferentes funções no script real

AGleasonTU
fonte

Respostas:

274

Você não precisa passar as aspas entre os cabeçalhos personalizados para ondular. Além disso, suas variáveis ​​no meio do dataargumento devem ser citadas.

Primeiro, escreva uma função que gere os dados de postagem do seu script. Isso evita todos os tipos de dores de cabeça relacionadas à citação de shell e facilita a leitura e a manutenção do script, além de alimentar os dados de postagem na linha de chamada do curl, como na sua tentativa:

generate_post_data()
{
  cat <<EOF
{
  "account": {
    "email": "$email",
    "screenName": "$screenName",
    "type": "$theType",
    "passwordSettings": {
      "password": "$password",
      "passwordConfirm": "$password"
    }
  },
  "firstName": "$firstName",
  "lastName": "$lastName",
  "middleName": "$middleName",
  "locale": "$locale",
  "registrationSiteId": "$registrationSiteId",
  "receiveEmail": "$receiveEmail",
  "dateOfBirth": "$dob",
  "mobileNumber": "$mobileNumber",
  "gender": "$gender",
  "fuelActivationDate": "$fuelActivationDate",
  "postalCode": "$postalCode",
  "country": "$country",
  "city": "$city",
  "state": "$state",
  "bio": "$bio",
  "jpFirstNameKana": "$jpFirstNameKana",
  "jpLastNameKana": "$jpLastNameKana",
  "height": "$height",
  "weight": "$weight",
  "distanceUnit": "MILES",
  "weightUnit": "POUNDS",
  "heightUnit": "FT/INCHES"
}
EOF
}

É fácil usar essa função na chamada de curl:

curl -i \
-H "Accept: application/json" \
-H "Content-Type:application/json" \
-X POST --data "$(generate_post_data)" "https://xxx:[email protected]/xxxxx/xxxx/xxxx"

Dito isto, aqui estão alguns esclarecimentos sobre as regras de citação de shell:

As aspas duplas nos -Hargumentos (como em -H "foo bar") dizem ao bash para manter o que está dentro como um único argumento (mesmo que contenha espaços).

As aspas simples no --dataargumento (como em --data 'foo bar') fazem o mesmo, exceto que passam todo o texto literalmente (incluindo caracteres de aspas duplas e o cifrão).

Para inserir uma variável no meio de um único texto citado, você tem que acabar com o apóstrofo, então concatenar com a variável entre aspas duplas, e re-abrir o apóstrofo para continuar o texto: 'foo bar'"$variable"'more foo'.

Sir Athos
fonte
9
"'" $ <nome da variável> "'" resolveu meu problema, onde eu precisava que aspas não fossem omitidas. Obrigado.
Usman 5/05
1
Esta solução funciona, mas acho que você pode emitir aspas duplas extras ao redor da variável. Então, em vez disso: --data '{"account": {"email": "'" $ email "'"}}' você pode fazer isso: --data '{"account": {"email": " '$ email' "}} '
twistedstream
3
Não funcionou quando havia um espaço após o segundo EOF: EOF . Depois de removê-lo, está tudo bem.
Klaas
2
@ dbreaux Isso depende de onde você executa o comando curl. Se o comando estiver em um script, basta definir a função em qualquer lugar acima dele no mesmo script. Se você estiver executando curl diretamente da linha de comando, você terá várias opções, uma das quais é digitar a função em um novo arquivo e, em seguida, na linha de comando, source my_new_filepara definir a função no seu ambiente atual. Depois disso, você pode executar o comando curl como indicado.
Sir Athos
2
@slashdottir Esse é um recurso do bash chamado Here Documents. Você pode ler sobre isso com mais detalhes neste link - em particular, consulte o Exemplo 19-5. Também já existe uma pergunta completa sobre isso aqui no SO.
Sir Athos
103

Solução testada com https://httpbin.org/ e script embutido do bash
1. Para variáveis ​​sem espaços, isto é 1:
basta adicionar 'antes e depois $variableao substituir a sequência desejada

for i in {1..3}; do \
  curl -X POST -H "Content-Type: application/json" -d \
    '{"number":"'$i'"}' "https://httpbin.org/post"; \
done

2. Para entrada com espaços:
Quebra variável com adicional "ou seja "el a":

declare -a arr=("el a" "el b" "el c"); for i in "${arr[@]}"; do \
  curl -X POST -H "Content-Type: application/json" -d \
    '{"elem":"'"$i"'"}' "https://httpbin.org/post"; \
done

Uau funciona :)

pbaranski
fonte
1
Não funciona para quando quando $icontém espaços. :(
Vasyl Boroviak
Você pode postar um exemplo?
Pbaranski 03/04
1
Certo. i="a b"em vez de para-ciclo
Vasyl Boroviak
5
Descobri que a resposta aceita e a segunda resposta votada não funcionam /bin/sh. No entanto, esta resposta fez o truque. E é muito mais simples que as outras respostas. Muito obrigado! Editei sua resposta com uma formatação mais agradável de quebra de linha. Caso contrário, é difícil identificar o brilho. Cheers mate
Vasyl Boroviak
1
Muito obrigado @pbaranski você salvou muito do meu tempo #
sudhir tataraju 17/17/19
32

O Curl pode postar dados binários de um arquivo, então eu tenho usado a substituição de processos e aproveitado os descritores de arquivos sempre que preciso postar algo desagradável com o curl e ainda assim quero acessar os vars no shell atual. Algo como:

curl "http://localhost:8080" \
-H "Accept: application/json" \
-H "Content-Type:application/json" \
--data @<(cat <<EOF
{
  "me": "$USER",
  "something": $(date +%s)
  }
EOF
)

Isso acaba parecendo o --data @/dev/fd/<some number>que é processado como um arquivo normal. De qualquer forma, se você quiser vê-lo funcionar localmente, basta executar nc -l 8080primeiro e em um shell diferente disparar o comando acima. Você verá algo como:

POST / HTTP/1.1
Host: localhost:8080
User-Agent: curl/7.43.0
Accept: application/json
Content-Type:application/json
Content-Length: 43

{  "me": "username",  "something": 1465057519  }

Como você pode ver, você pode chamar subshells e outros enfeites, além de vars de referência no heredoc. Feliz hacking espero que isso ajude com o '"'"'""""'''""''.

Che Ruisi-Besares
fonte
2
A outra resposta não funcionou para mim, pois eu estava tentando invocá-la em um alerta do Zabbix. Este resolve-o perfeitamente e é mais limpo.
0rkan
Mas e se você colocar o código em uma função bash: myFunction () {....}?
Hanynowsky
1
Vale a pena notar que esta receita funciona apenas se o script é copiado na íntegra (ou seja, sem EOF reformatação, chaves etc.)
Vader B
9

Alguns anos atrasado, mas isso pode ajudar alguém se você estiver usando a substituição de avaliação ou backtick:

postDataJson="{\"guid\":\"$guid\",\"auth_token\":\"$token\"}"

Usando sed para retirar aspas do início e do fim da resposta

$(curl --silent -H "Content-Type: application/json" https://${target_host}/runs/get-work -d ${postDataJson} | sed -e 's/^"//' -e 's/"$//')
glifo
fonte
4
  • as informações de Sir Athos funcionaram perfeitamente !!

Aqui está como eu tive que usá-lo no meu script curl para couchDB. Isso realmente ajudou muito. Obrigado!

bin/curl -X PUT "db_domain_name_:5984/_config/vhosts/$1.couchdb" -d '"/'"$1"'/"' --user "admin:*****"
thargenediad
fonte
4

Aqui está o que realmente funcionou para mim, após a orientação das respostas aqui:

export BASH_VARIABLE="[1,2,3]"
curl http://localhost:8080/path -d "$(cat <<EOF
{
  "name": $BASH_VARIABLE,
  "something": [
    "value1",
    "value2",
    "value3"
  ]
}
EOF
)" -H 'Content-Type: application/json'
xgMz
fonte
2

As respostas existentes apontam que o curl pode postar dados de um arquivo e empregar heredocs para evitar o escape excessivo de cotações e dividir claramente o JSON em novas linhas. No entanto, não há necessidade de definir uma função ou capturar a saída do gato, porque o curl pode postar dados da entrada padrão. Acho este formulário muito legível:

curl -X POST -H 'Content-Type:application/json' --data '$@-' ${API_URL} << EOF
{
  "account": {
    "email": "$email",
    "screenName": "$screenName",
    "type": "$theType",
    "passwordSettings": {
      "password": "$password",
      "passwordConfirm": "$password"
    }
  },
  "firstName": "$firstName",
  "lastName": "$lastName",
  "middleName": "$middleName",
  "locale": "$locale",
  "registrationSiteId": "$registrationSiteId",
  "receiveEmail": "$receiveEmail",
  "dateOfBirth": "$dob",
  "mobileNumber": "$mobileNumber",
  "gender": "$gender",
  "fuelActivationDate": "$fuelActivationDate",
  "postalCode": "$postalCode",
  "country": "$country",
  "city": "$city",
  "state": "$state",
  "bio": "$bio",
  "jpFirstNameKana": "$jpFirstNameKana",
  "jpLastNameKana": "$jpLastNameKana",
  "height": "$height",
  "weight": "$weight",
  "distanceUnit": "MILES",
  "weightUnit": "POUNDS",
  "heightUnit": "FT/INCHES"
}
EOF
abyrd
fonte