Использование curl POST с переменными, определенными в функциях скрипта bash

176

Когда я получаю эхо, я получаю это, которое запускается, когда я вхожу в терминал

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

Но при запуске в файле сценария bash, я получаю эту ошибку

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

это код в файле

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"

Я предполагаю, что есть проблема с моими кавычками, но я много играл с ними и у меня были похожие ошибки. Все переменные определяются с помощью различных функций в реальном скрипте

AGleasonTU
источник

Ответы:

274

Вам не нужно передавать кавычки, содержащие пользовательские заголовки. Кроме того, ваши переменные в серединеdata аргумента должны быть в кавычках.

Сначала напишите функцию, которая генерирует данные поста вашего скрипта. Это избавит вас от всех видов головной боли, связанной с цитированием оболочки, и облегчит чтение сценария сопровождения, чем подача почтовых данных в строку вызова curl, как в вашей попытке:

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
}

Затем легко использовать эту функцию при вызове 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"

Тем не менее, вот несколько пояснений о правилах цитирования оболочки:

Двойные кавычки в -Hаргументах (как в -H "foo bar") говорят bash хранить то, что внутри, как один аргумент (даже если он содержит пробелы).

Одинарные кавычки в --dataаргументе (как в --data 'foo bar') делают то же самое, за исключением того, что они передают весь текст (включая символы двойных кавычек и знак доллара).

Чтобы вставить переменную в середине одного цитируемого текста, вы должны закончить апостроф, затем сцепить с цитируемого переменной двойной, и повторно открыть единственную цитату , чтобы продолжить текст: 'foo bar'"$variable"'more foo'.

Сэр афон
источник
9
"'" $ <имя переменной> "'" решило мою проблему, где я хотел, чтобы кавычки не были опущены. Спасибо.
Усман
1
Это решение работает, но я думаю, что вы можете выбросить дополнительные двойные кавычки, окружающие переменную. Поэтому вместо этого: --data '{"account": {"email": "'" $ email "'"}}' вы можете сделать это: --data '{"account": {"email": " '$ электронной почты' "}}»
twistedstream
3
Не работал , когда был пробел после второго EOF: EOF . После удаления все нормально.
Клаас
2
@dbreaux Это зависит от того, где вы запускаете команду curl. Если команда находится в сценарии, вы просто определяете функцию в любом месте над ней в том же сценарии. Если вы запускаете curl непосредственно из командной строки, у вас есть несколько опций, одна из которых состоит в том, чтобы напечатать функцию в новом файле, а затем в командной строке запустить, source my_new_fileчтобы определить функцию в вашей текущей среде. После этого вы можете запустить команду curl, как указано.
Сэр Афон
2
@slashdottir Это функция bash, которая называется Here Documents. Вы можете прочитать об этом более подробно по этой ссылке - в частности, посмотрите Пример 19-5. Здесь также уже есть полный вопрос об этом на SO.
сэр Афон
103

Решение протестировано с https://httpbin.org/ и встроенным сценарием bash
1. Для переменных без пробелов, то есть 1:
просто добавьте 'до и после $variableпри замене желаемой строки

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

2. Для ввода с пробелами:
переменная Wrap с дополнительным , "т.е. "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

Вау работает :)

pbaranski
источник
1
Не работает, когда, когда $iсодержит пробелы. :(
Василий
Можете ли вы опубликовать пример?
pbaranski
1
Конечно. i="a b"вместо цикла
Василий
5
Я обнаружил, что принятый и второй проголосовавший ответ не работает в /bin/sh. Тем не менее, этот ответ сделал свое дело. И это намного проще, чем другие ответы. Спасибо вам большое! Я отредактировал ваш ответ с более приятным форматированием переноса строк. В противном случае, трудно определить блеск. Ура, приятель
Василий
1
Большое спасибо @pbaranski, вы сэкономили много моего времени
Судхир Татараджу
32

Curl может публиковать двоичные данные из файла, поэтому я использую подстановку процессов и использую преимущества файловых дескрипторов всякий раз, когда мне нужно опубликовать что-то неприятное с помощью curl и все еще хотеть получить доступ к переменным в текущей оболочке. Что-то вроде:

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

Это выглядит как, --data @/dev/fd/<some number>который просто обрабатывается как обычный файл. В любом случае, если вы хотите, чтобы это работало локально, просто запустите nc -l 8080сначала и в другой оболочке запустите вышеуказанную команду. Вы увидите что-то вроде:

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  }

Как видите, в heredoc вы можете вызывать подоболочки и тому подобное, а также ссылочные переменные. Счастливого взлома надеюсь, что это помогает с '"'"'""""'''""''.

Че Руиси-Бесарес
источник
2
Другой ответ не сработал для меня, так как я пытался вызвать его в предупреждении от Zabbix. Этот решает это отлично и является более чистым.
0rkan
Но что, если вы поместите код в функцию bash: myFunction () {....}?
Hanynowsky
1
Стоит отметить, что этот рецепт работает только в том случае, если скрипт скопирован дословно (то есть без переформатирования EOF, фигурных скобок и т. д.)
Вейдер Б
9

Несколько лет спустя, но это может помочь кому-то, если вы используете замещение eval или backtick:

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

Использование sed для удаления цитат из начала и конца ответа

$(curl --silent -H "Content-Type: application/json" https://${target_host}/runs/get-work -d ${postDataJson} | sed -e 's/^"//' -e 's/"$//')
глиф
источник
4
  • информация от сэра Атоса сработала отлично !!

Вот как я должен был использовать это в моем скрипте curl для couchDB. Это действительно очень помогло. Спасибо!

bin/curl -X PUT "db_domain_name_:5984/_config/vhosts/$1.couchdb" -d '"/'"$1"'/"' --user "admin:*****"
thargenediad
источник
4

Вот что на самом деле сработало для меня, после указания здесь ответов:

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
источник
2

Существующие ответы указывают на то, что curl может отправлять данные из файла и использовать heredocs, чтобы избежать чрезмерного экранирования кавычек и четко разбить JSON на новые строки. Однако нет необходимости определять функцию или захватывать выходные данные из cat, потому что curl может публиковать данные из стандартного ввода. Я нахожу эту форму очень читабельной:

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
источник