Utilisation de curl POST avec des variables définies dans les fonctions de script bash

176

Quand je fais écho, j'obtiens ceci, qui s'exécute quand je le rentre dans le 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

Mais une fois exécuté dans le fichier de script bash, j'obtiens cette erreur

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

c'est le code dans le fichier

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"

Je suppose qu'il y a un problème avec mes guillemets, mais j'ai beaucoup joué avec eux et j'ai eu des erreurs similaires. Toutes les variables sont définies avec différentes fonctions dans le script réel

AGleasonTU
la source

Réponses:

274

Vous n'avez pas besoin de transmettre les guillemets entourant les en-têtes personnalisés à curl. De plus, vos variables au milieu de l' dataargument doivent être entre guillemets.

Tout d'abord, écrivez une fonction qui génère les données de publication de votre script. Cela vous évite toutes sortes de maux de tête concernant les citations de shell et facilite la lecture et la maintenance du script que de nourrir les données de publication sur la ligne d'appel de curl comme dans votre tentative:

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
}

Il est alors facile d'utiliser cette fonction lors de l'invocation 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"

Cela dit, voici quelques clarifications sur les règles de citation du shell:

Les guillemets doubles dans les -Harguments (comme dans -H "foo bar") indiquent à bash de garder ce qu'il y a à l'intérieur comme argument unique (même s'il contient des espaces).

Les guillemets simples dans l' --dataargument (comme dans --data 'foo bar') font de même, sauf qu'ils transmettent tout le texte textuellement (y compris les guillemets doubles et le signe dollar).

Pour insérer une variable au milieu d'un seul texte cité, vous devez mettre fin à la seule citation, puis concaténer à la variable entre guillemets doubles et rouvrez la citation unique pour continuer le texte: 'foo bar'"$variable"'more foo'.

Sir Athos
la source
9
"'" $ <nom de la variable> "'" a résolu mon problème où j'avais besoin de guillemets pour ne pas être omis. Merci.
Usman
1
Cette solution fonctionne mais je pense que vous pouvez émettre les guillemets doubles supplémentaires entourant la variable. Donc au lieu de ceci: --data '{"account": {"email": "'" $ email "'"}}' vous pouvez faire ceci: --data '{"account": {"email": " '$ email' "}} '
twistedstream
3
Ne fonctionne pas quand il y avait un espace après la deuxième EOF: EOF . Après l'avoir retiré, tout va bien.
Klaas le
2
@dbreaux Cela dépend de l'endroit où vous exécutez la commande curl. Si la commande est dans un script, vous définissez simplement la fonction n'importe où au-dessus d'elle dans ce même script. Si vous exécutez curl directement à partir de la ligne de commande, vous avez plusieurs options, dont l'une consiste à taper la fonction dans un nouveau fichier, puis à exécuter la ligne de commande source my_new_filepour définir la fonction dans votre environnement actuel. Après cela, vous pouvez exécuter la commande curl comme indiqué.
Sir Athos
2
@slashdottir C'est une fonctionnalité bash appelée Here Documents. Vous pouvez en savoir plus à ce sujet sur ce lien - en particulier, consultez l'exemple 19-5. Il y a aussi déjà une question complète à ce sujet ici sur SO.
Sir Athos
103

Solution testée avec https://httpbin.org/ et script bash en ligne
1. Pour les variables sans espaces, c'est-à-dire 1:
ajoutez simplement 'avant et après $variablelors du remplacement de la chaîne souhaitée

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

2. Pour une entrée avec des espaces:
Wrap variable avec additionnel "ie "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

Wow fonctionne :)

Pbaranski
la source
1
Ne fonctionne pas lorsque $icontient des espaces. :(
Vasyl Boroviak
Pouvez-vous poster un exemple?
pbaranski
1
Sûr. i="a b"au lieu de for-loop
Vasyl Boroviak
5
J'ai trouvé que la réponse acceptée et la deuxième réponse votée ne fonctionnaient pas /bin/sh. Cependant, cette réponse a fait l'affaire. Et c'est beaucoup plus simple que les autres réponses. Merci beaucoup! J'ai modifié votre réponse avec une mise en forme de ligne plus agréable. Sinon, il est difficile de repérer la brillance. Cheers mate
Vasyl Boroviak
1
Merci beaucoup @pbaranski vous m'avez sauvé beaucoup de temps
sudhir tataraju
32

Curl peut publier des données binaires à partir d'un fichier.J'ai donc utilisé la substitution de processus et profité des descripteurs de fichier chaque fois que j'ai besoin de publier quelque chose de méchant avec curl et que je veux toujours accéder aux variables dans le shell actuel. Quelque chose comme:

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

Cela finit par ressembler à celui --data @/dev/fd/<some number>qui est simplement traité comme un fichier normal. Quoi qu'il en soit, si vous voulez le voir fonctionner localement, lancez-le d' nc -l 8080abord et dans un autre shell, lancez la commande ci-dessus. Vous verrez quelque chose comme:

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  }

Comme vous pouvez le voir, vous pouvez appeler des sous-shell et autres ainsi que des variables de référence dans heredoc. Happy hacking espère que cela aidera avec le '"'"'""""'''""''.

Che Ruisi-Besares
la source
2
L'autre réponse n'a pas fonctionné pour moi car j'essayais de l'invoquer dans une alerte de Zabbix. Celui-ci le résout parfaitement et est plus propre.
0rkan
Mais que faire si vous mettez le code dans une fonction bash: myFunction () {....}?
Hanynowsky
1
il convient de noter que cette recette ne fonctionne que si le script est copié textuellement (c'est-à-dire pas de reformatage EOF, accolades, etc.)
Vader B
9

Quelques années de retard, mais cela pourrait aider quelqu'un si vous utilisez une substitution eval ou backtick:

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

Utilisation de sed pour supprimer les citations du début et de la fin de la réponse

$(curl --silent -H "Content-Type: application/json" https://${target_host}/runs/get-work -d ${postDataJson} | sed -e 's/^"//' -e 's/"$//')
glyphe
la source
4
  • les informations de Sir Athos fonctionnaient parfaitement !!

Voici comment j'ai dû l'utiliser dans mon script curl pour couchDB. Cela a vraiment beaucoup aidé. Merci!

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

Voici ce qui a réellement fonctionné pour moi, après les conseils des réponses ici:

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
la source
2

Les réponses existantes soulignent que curl peut publier des données à partir d'un fichier et utiliser heredocs pour éviter les échappements excessifs des citations et séparer clairement le JSON sur de nouvelles lignes. Cependant, il n'est pas nécessaire de définir une fonction ou de capturer la sortie de cat, car curl peut publier des données à partir d'une entrée standard. Je trouve ce formulaire très lisible:

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
la source