251 votes

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

Lorsque j'écho, j'obtiens ceci, qui s'exécute lorsque je le saisis dans le terminal

curl -i \
-H "Accept: application/json" \
-H "Content-Type:application/json" \
-X POST --data '{"account":{"email":"akdgdtk@test.com","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 lorsque le script bash est exécuté, 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

Voici 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:xxxxx@xxxx-www.xxxxx.com/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 obtenu des erreurs similaires. Toutes les variables sont définies avec différentes fonctions dans le script réel

370voto

Sir Athos Points 1936

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

Tout d'abord, écrivez une fonction qui génère les données de publication de votre script. Cela vous évitera toutes sortes de problèmes concernant l'espacement des coquilles et rendra plus facile la lecture et la maintenance du script que de fournir les données de publication sur la ligne d'invocation de curl comme dans votre tentative :

generate_post_data()
{
  cat <

``

Il est alors facile d'utiliser cette fonction dans l'invocation de curl :

curl -i \
-H "Accept: application/json" \
-H "Content-Type:application/json" \
-X POST --data "$(generate_post_data)" "https://xxx:xxxxx@xxxx-www.xxxxx.com/xxxxx/xxxx/xxxx"

Ceci dit, voici quelques clarifications sur les règles de mise entre guillemets des coquilles :

Les guillemets doubles dans les arguments de -H (comme dans -H "foo bar") disent à bash de conserver ce qui se trouve à l'intérieur comme un seul argument (même s'il contient des espaces).

Les guillemets simples dans l'argument --data (comme dans --data 'foo bar') font la même chose, sauf qu'ils passent tout le texte littéralement (y compris les caractères de guillemets doubles et le signe dollar).

Pour insérer une variable au milieu d'un texte entre guillemets simples, vous devez terminer les guillemets simples, puis concaténer avec la variable entre guillemets doubles, et rouvrir les guillemets simples pour continuer le texte : 'foo bar'"$variable"'more foo'.

``

17 votes

"'"$"'" a résolu mon problème où j'avais besoin que les guillemets ne soient pas omis. Merci.

3 votes

Cette solution fonctionne mais je pense que vous pouvez supprimer les guillemets supplémentaires entourant la variable. Donc au lieu de cela: --data '{"account": {"email": "'"$email"'"} }' vous pouvez faire ceci: --data '{"account": {"email": "'$email'"} }'

0 votes

@twistedstream pour les adresses e-mail correctement formatées, oui. Si votre variable contient quelque chose de malveillant (par exemple des espaces), le fait d'omettre les guillemets supplémentaires cassera votre script.

189voto

abrasadera Points 1216

Solution testée avec https://httpbin.org/ et script bash en ligne
1. Pour les variables sans espaces c'est-à-dire 1:
Il suffit d'ajouter ' avant et après $variable lors 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 les entrées avec des espaces:
Enveloppez la variable avec des " supplémentaires c'est-à-dire "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

Ça marche :)

2 votes

Ne fonctionne pas pour quand $i contient des espaces. :(

0 votes

Pouvez-vous poster un exemple?

1 votes

Bien sûr. i="a b" au lieu de la boucle for

53voto

Che Ruisi-Besares Points 561

Curl peut poster des données binaires à partir d'un fichier, j'ai donc utilisé la substitution de processus et tiré parti des descripteurs de fichiers chaque fois que j'ai besoin de poster quelque chose de méchant avec curl et je veux toujours accéder aux variables dans l'environnement actuel. Quelque chose comme :

curl "http://localhost:8080" \
-H "Accept: application/json" \
-H "Content-Type:application/json" \
--data @<(cat <

``

Cela finit par ressembler à --data @/dev/fd/ qui est simplement traité comme un fichier normal. Quoi qu'il en soit, si vous voulez le voir fonctionner localement, lancez d'abord nc -l 8080 et dans un shell différent, 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": "utilisateur",  "something": 1465057519  }

Comme vous pouvez le voir, vous pouvez appeler des sous-processus et autres choses ainsi que faire référence à des variables dans le here document. Bon hack, j'espère que cela vous aidera avec les '"'"'""""'''""''.

``

2 votes

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.

0 votes

Mais que se passe-t-il si vous mettez le code dans une fonction bash : myFunction () { .... } ?

1 votes

Il est bon de noter que cette recette fonctionne uniquement si le script est copié intégralement (c'est-à-dire sans reformater EOF, accolades, etc.)

34voto

Shakiba Moshiri Points 6556

Nous pouvons attribuer une variable pour curl en utilisant une simple citation ' et envelopper d'autres variables dedans

  • une simple citation => ' $variable '
  • une citation double-simple => "' $variable '"
  • une citation simple+double+simple => '"' $variable '"'

Testons chaque cas, mais attention à ce détail : si nous utilisons une simple citation ' pour l'assignation d'une variable, cette variable n'est pas évaluée.

attention

Veuillez noter que l'assignation se fait par une simple citation CURL_DATA='contenu'

cmd='ls'

CURL_DATA='{
    "cmd": "$cmd",    <===== notre variable
    "args": [ "-la" , "/tmp" ],
    "options": {
        "cwd": "/tmp"
    },
   "type": "sync"
}';

echo "$CURL_DATA";

Nous obtiendrons

{
    "cmd": "$cmd",    <===== nous avons besoin de ls pas de $cmd
    "args": [ "-la" , "/tmp" ],
    "options": {
        "cwd": "/tmp"
    },
   "type": "sync"
}

une simple citation ' $variable '

  • La valeur d'une variable est évaluée
  • ni une simple citation ' ni une double "

    cmd='ls'

    CURL_DATA='{ "cmd": '$cmd', <===== notre variable "args": [ "-la" , "/tmp" ], "options": { "cwd": "/tmp" }, "type": "sync" }';

    echo "$CURL_DATA";

Nous obtiendrons :

{
    "cmd": ls,    <===== ni 'ls' ni "ls", juste ls
    "args": [ "-la" , "/tmp" ],
    "options": {
        "cwd": "/tmp"
    },
   "type": "sync"
}

une citation double-simple "' $variable '"

  • Variable évaluée
  • Sera entouré d'une double citation "

    cmd='ls'

    CURL_DATA='{ "cmd": "'$cmd'", <===== notre variable "args": [ "-la" , "/tmp" ], "options": { "cwd": "/tmp" }, "type": "sync" }';

    echo "$CURL_DATA";

Nous obtiendrons

{
    "cmd": "ls",    <===== nous avons double quote " variable "
    "args": [ "-la" , "/tmp" ],
    "options": {
        "cwd": "/tmp"
    },
   "type": "sync"
}

une simple+double+simple citation => '"' $variable '"'

  • Variable évaluée
  • Sera entouré d'une simple citation '

    cmd='ls'

    CURL_DATA='{ "cmd": '"'$cmd'"', "args": [ "-la" , "/tmp" ], "options": { "cwd": "/tmp" }, "type": "sync" }';

    echo "$CURL_DATA";

Nous obtiendrons

{
    "cmd": 'ls',    <===== nous avons une simple citation ' variable '
    "args": [ "-la" , "/tmp" ],
    "options": {
        "cwd": "/tmp"
    },
   "type": "sync"
}

résumé

# pas de citation du tout
$cmd => $cmd

# une double citation (" $variable ")
"$cmd" => "$cmd"

# une simple citation (' $variable ')
'$cmd' => ls

# une simple citation + une double citation ("' $variable '")
"'$cmd'" => "ls"

# une simple-double-simple citation ('"' $variable '"')
'"'$cmd'"' => 'ls'

lequel devrions-nous utiliser?

Comme JSON nécessite une double citation " pour sa clé ou sa valeur, nous pouvons utiliser :

  • une double simple citation "' $variable '"

curl

cmd='ls'

CURL_DATA='{
    "cmd": "'$cmd'",
    "args": [ "-la" , "/tmp" ],
    "options": {
        "cwd": "/tmp"
    },
   "type": "sync"
}';

echo "$CURL_DATA" | jq '.'

curl --data "$CURL_DATA" -X POST localhost:3232/cmd | jq '.'

REMARQUE:
L'équivalent de ' pour une évaluation de variable est '", ce qui signifie qu'au lieu d'utiliser '$cmd', nous pouvons utiliser '"$cmd"' et cela nous donne ls ni avec une simple citation ni avec une double citation, mais cela devient plus déroutant si nous devons l'appliquer à curl car nous avons besoin d'un double résultat cité "ls" et devrions l'envelopper dans une autre double citation => "'"

Ce code fonctionne bien, mais ce qui précède est plus lisible

cmd='ls'

CURL_DATA='{
    "cmd": "'"$cmd"'",     <===== notre variable
    "args": [ "-la" , "/tmp" ],
    "options": {
        "cwd": "/tmp"
    },
   "type": "sync"
}';

echo "$CURL_DATA" | jq '.'

curl --data "$CURL_DATA" -X POST localhost:3232/cmd | jq '.'

Nous obtiendrons :

{
    "cmd": "ls",    <===== résultat
    "args": [ "-la" , "/tmp" ],
    "options": {
        "cwd": "/tmp"
    },
   "type": "sync"
}

enfin

Nous pouvons utiliser l'un ou l'autre de :

    "cmd": "'$cmd'",    <===== sera: "ls"

ou

    "cmd": "'"$cmd"'",    <===== sera: "ls" 

et "$CURL_DATA" comme une variable normale

curl --data "$CURL_DATA" -X POST localhost:3232/cmd

0 votes

Pour une raison quelconque, le script shell échappait les guillemets, la bonne combinaison de guillemets pour les espaces réservés a marché pour moi. some_body='{"query":"/v1/'$some_id'","body":""}' curl --data "$some_body" 'https://some.url'

13voto

glyph Points 438

Quelques années en retard mais cela pourrait aider quelqu'un si vous utilisez l'évaluation ou la substitution de backtick :

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

Utilisation de sed pour supprimer les guillemets 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/"$//')

0 votes

Solution simple, a beaucoup aidé, merci!

Prograide.com

Prograide est une communauté de développeurs qui cherche à élargir la connaissance de la programmation au-delà de l'anglais.
Pour cela nous avons les plus grands doutes résolus en français et vous pouvez aussi poser vos propres questions ou résoudre celles des autres.

Powered by:

X