Usar curl POST con variables definidas en funciones de script bash

176

Cuando hago eco obtengo esto, que se ejecuta cuando lo ingreso en la 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

Pero cuando se ejecuta en el archivo de script bash, aparece este error

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 es el código en el archivo

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"

Supongo que hay un problema con mis comillas, pero he jugado mucho con ellas y he tenido errores similares. Todas las variables se definen con diferentes funciones en el script real.

AGleasonTU
fuente

Respuestas:

274

No necesita pasar las comillas que encierran los encabezados personalizados para curvar. Además, sus variables en el medio del dataargumento deben ser citadas.

Primero, escriba una función que genere los datos de publicación de su script. Esto le ahorra todo tipo de dolores de cabeza con respecto a las citas de shell y hace que sea más fácil leer y mantener el script que alimentar los datos de publicación en la línea de invocación de curl como en su intento:

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
}

Entonces es fácil usar esa función en la invocación 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"

Dicho esto, aquí hay algunas aclaraciones sobre las reglas de cotización de shell:

Las comillas dobles en los -Hargumentos (como en -H "foo bar") le dicen a bash que mantenga lo que hay dentro como un argumento único (incluso si contiene espacios).

Las comillas simples en el --dataargumento (como en --data 'foo bar') hacen lo mismo, excepto que pasan todo el texto literalmente (incluidos los caracteres de comillas dobles y el signo de dólar).

Para insertar una variable en el medio de un único texto citado, hay que poner fin a la comilla simple, entonces concatenar con la variable entre comillas dobles, y volver a abrir la comilla simple de seguir el texto: 'foo bar'"$variable"'more foo'.

Sir Athos
fuente
9
"'" $ <nombre de variable> "'" resolvió mi problema donde necesitaba que no se omitieran las comillas. Gracias.
Usman
1
Esta solución funciona, pero creo que puede emitir las comillas dobles adicionales que rodean la variable. Entonces, en lugar de esto: --data '{"cuenta": {"correo electrónico": "'" $ correo electrónico "'"}}' puede hacer esto: --data '{"cuenta": {"correo electrónico": " '$ email' "}} '
twistedstream
3
No funcionó cuando había un espacio después de la segunda EOF: EOF . Después de quitarlo todo está bien.
Klaas
2
@dbreaux Eso depende de dónde ejecutas el comando curl. Si el comando está en un script, simplemente defina la función en cualquier lugar sobre él en ese mismo script. Si está ejecutando curl directamente desde la línea de comando, tiene varias opciones, una de las cuales es escribir la función en un archivo nuevo y luego ejecutar en la línea de comando source my_new_filepara definir la función en su entorno actual. Después de eso, puede ejecutar el comando curl como se indica.
Sir Athos
2
@slashdottir Esa es una característica de bash llamada Here Documents. Puede leer sobre esto con más detalle en este enlace , en particular, consulte el Ejemplo 19-5. También hay una pregunta completa al respecto aquí en SO.
Sir Athos
103

Solución probada con https://httpbin.org/ y script en línea bash
1. Para variables sin espacios, es decir 1:
simplemente agregue 'antes y después $variableal reemplazar la cadena deseada

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 con espacios:
Ajustar variable con adicional, "es decir "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 funciona :)

pbaranski
fuente
1
No funciona cuando cuando $icontiene espacios. :(
Vasyl Boroviak
Puede publicar un ejemplo?
pbaranski
1
Por supuesto. i="a b"en lugar de for-loop
Vasyl Boroviak
55
Encontré que la respuesta aceptada y la segunda votada no funciona /bin/sh. Sin embargo, esta respuesta hizo el truco. Y es mucho más simple que las otras respuestas. Muchas gracias! He editado tu respuesta con un formato de ajuste de línea más agradable. De lo contrario, es difícil detectar el brillo. Saludos compañero
Vasyl Boroviak
1
Muchas gracias @pbaranski me ahorraste mucho tiempo
sudhir tataraju
32

Curl puede publicar datos binarios de un archivo, por lo que he estado usando la sustitución de procesos y aprovechándome de los descriptores de archivos cada vez que necesito publicar algo desagradable con curl y todavía quiero acceder a los vars en el shell actual. Algo como:

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

Esto termina pareciendo --data @/dev/fd/<some number>que simplemente se procesa como un archivo normal. De todos modos, si quieres verlo funcionar localmente, solo ejecuta nc -l 8080primero y en un shell diferente dispara el comando anterior. Verás 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 puede ver, puede llamar subcapas y demás, así como variables de referencia en el heredoc. Feliz piratería espero que esto ayude con el '"'"'""""'''""''.

Che Ruisi-Besares
fuente
2
La otra respuesta no funcionó para mí, ya que estaba tratando de invocarla en una alerta de Zabbix. Este lo resuelve perfectamente y está más limpio.
0rkan
Pero, ¿qué pasa si pones el código en una función bash: myFunction () {....}?
Hanynowsky
1
vale la pena señalar que esta receta solo funciona si el script se copia textualmente (es decir, sin formatear EOF, llaves, etc.)
Vader B
9

Unos años de retraso, pero esto podría ayudar a alguien si está utilizando evaluación o sustitución de retroceso:

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

Uso de sed para eliminar comillas desde el principio y el final de la respuesta

$(curl --silent -H "Content-Type: application/json" https://${target_host}/runs/get-work -d ${postDataJson} | sed -e 's/^"//' -e 's/"$//')
glifo
fuente
4
  • ¡La información de Sir Athos funcionó perfectamente!

Así es como tuve que usarlo en mi script curl para couchDB. Realmente ayudó mucho. ¡Gracias!

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

Esto es lo que realmente funcionó para mí, después de la orientación de las respuestas aquí:

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
fuente
2

Las respuestas existentes señalan que curl puede publicar datos de un archivo, y emplea heredocs para evitar el escape excesivo de comillas y claramente separar el JSON en nuevas líneas. Sin embargo, no es necesario definir una función o capturar la salida de cat, porque curl puede publicar datos desde la entrada estándar. Este formulario me parece muy legible:

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
fuente