Używanie curl POST ze zmiennymi zdefiniowanymi w funkcjach skryptu bash

176

Kiedy powtarzam echo, otrzymuję to, które działa, gdy wprowadzam go do terminala

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

Ale po uruchomieniu w pliku skryptu bash otrzymuję ten błąd

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

to jest kod w pliku

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"

Zakładam, że wystąpił problem z moimi cudzysłowami, ale często się z nimi bawiłem i otrzymałem podobne błędy. Wszystkie zmienne mają zdefiniowane różne funkcje w rzeczywistym skrypcie

AGleasonTU
źródło

Odpowiedzi:

274

Nie musisz przekazywać cudzysłowów otaczających niestandardowe nagłówki do curl. Również twoje zmienne w środku dataargumentu powinny być cytowane.

Najpierw napisz funkcję, która generuje dane postu twojego skryptu. Pozwala to uniknąć wszelkiego rodzaju problemów związanych z cytowaniem w powłoce i ułatwia czytanie i konserwację skryptu niż podawanie danych postu w linii wywołania curl, jak w przypadku próby:

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
}

Dzięki temu łatwo jest użyć tej funkcji w wywołaniu 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"

To powiedziawszy, oto kilka wyjaśnień na temat reguł cytowania powłoki:

Podwójne cudzysłowy w -Hargumentach (tak jak w -H "foo bar") mówią bashowi, aby zachował zawartość jako pojedynczy argument (nawet jeśli zawiera spacje).

Pojedyncze cudzysłowy w --dataargumencie (jak w --data 'foo bar') robią to samo, z wyjątkiem tego, że przekazują cały tekst dosłownie (w tym znaki podwójnego cudzysłowu i znak dolara).

Aby wstawić zmienną w środku jednym cytowany tekst, trzeba zakończyć jeden cytat, następnie złączyć ze zmiennej podwójnej cytowanym i ponownie otworzyć apostrof kontynuować tekst: 'foo bar'"$variable"'more foo'.

Sir Athos
źródło
9
"'" $ <nazwa zmiennej> "'" rozwiązało mój problem, w którym potrzebowałem cudzysłowów, aby nie były pominięte. Dzięki.
Usman
1
To rozwiązanie działa, ale myślę, że możesz emitować dodatkowe podwójne cudzysłowy otaczające zmienną. Więc zamiast tego: --data '{"account": {"email": "'" $ email "'"}}' możesz to zrobić: --data '{"account": {"email": " '$ email' "}} '
twistedstream
3
Nie działa, gdy nie było miejsca po drugiej EOF: EOF . Po wyjęciu wszystko jest w porządku.
Klaas,
2
@dbreaux To zależy od tego, gdzie uruchomisz polecenie curl. Jeśli polecenie znajduje się w skrypcie, wystarczy zdefiniować funkcję w dowolnym miejscu nad nim w tym samym skrypcie. Jeśli uruchamiasz curl bezpośrednio z wiersza poleceń, masz kilka opcji, z których jedna polega na wpisaniu funkcji w nowym pliku, a następnie w wierszu poleceń, source my_new_fileaby zdefiniować funkcję w bieżącym środowisku. Następnie możesz uruchomić polecenie curl, jak wskazano.
Sir Athos
2
@slashdottir To funkcja bash o nazwie Here Documents. Możesz przeczytać o tym bardziej szczegółowo pod tym linkiem - w szczególności sprawdź przykład 19-5. Jest już na ten temat również pełne pytanie na ten temat.
Sir Athos
103

Rozwiązanie przetestowane za pomocą https://httpbin.org/ i wbudowanego skryptu bash
1. Dla zmiennych bez spacji, tj . 1:
Po prostu dodaj 'przed i po $variablepodczas zastępowania żądanego ciągu

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

2. Dla wprowadzenia ze spacjami:
Zawiń zmienną dodatkowymi "np . "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 działa :)

pbaranski
źródło
1
Nie działa, gdy $izawiera spacje. :(
Vasyl Boroviak
Czy możesz zamieścić przykład?
pbaranski
1
Pewnie. i="a b"zamiast pętli for
Vasyl Boroviak
5
Okazało się, że zaakceptowana i druga głosowana odpowiedź nie działa /bin/sh. Jednak ta odpowiedź załatwiła sprawę. Jest to znacznie prostsze niż inne odpowiedzi. Dziękuję bardzo! Zredagowałem twoją odpowiedź z ładniejszym formatowaniem zawijania linii. W przeciwnym razie trudno dostrzec blask. Cheers mate
Vasyl Boroviak
1
Wielkie dzięki @pbaranski zaoszczędziłeś dużo mojego czasu
sudhir tataraju
32

Curl może wysyłać dane binarne z pliku, więc korzystałem z podstawiania procesów i deskryptorów plików, gdy chcę opublikować coś paskudnego z curl i nadal chcę mieć dostęp do zmiennych w bieżącej powłoce. Coś jak:

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

Kończy się to wyglądem, --data @/dev/fd/<some number>który jest przetwarzany jak normalny plik. W każdym razie, jeśli chcesz zobaczyć, jak działa lokalnie, po prostu uruchom nc -l 8080najpierw i w innej powłoce odpal powyższe polecenie. Zobaczysz coś takiego:

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  }

Jak widać, w heredoc można wywoływać podpowłoki i tak dalej, jak również zmienne odniesienia. Miłego hakowania, mam nadzieję, że to pomoże w rozwiązaniu '"'"'""""'''""''.

Che Ruisi-Besares
źródło
2
Druga odpowiedź nie zadziałała dla mnie, ponieważ próbowałem wywołać ją w alercie Zabbix. Ten rozwiązuje to doskonale i jest bardziej czysty.
0rkan
Ale co, jeśli umieścisz kod w funkcji bash: myFunction () {....}?
Hanynowsky
1
warto zauważyć, że ten przepis działa tylko wtedy, gdy skrypt jest skopiowany dosłownie (tj. bez ponownego formatowania EOF, nawiasów klamrowych itp.)
Vader B
9

Kilka lat później, ale może to pomóc komuś, jeśli używasz zamiany eval lub backtick:

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

Używanie seda do usuwania cytatów z początku i końca odpowiedzi

$(curl --silent -H "Content-Type: application/json" https://${target_host}/runs/get-work -d ${postDataJson} | sed -e 's/^"//' -e 's/"$//')
glif
źródło
4
  • informacje od Sir Athosa działały idealnie !!

Oto, jak musiałem go użyć w moim skrypcie curl dla couchDB. To naprawdę bardzo pomogło. Dzięki!

bin/curl -X PUT "db_domain_name_:5984/_config/vhosts/$1.couchdb" -d '"/'"$1"'/"' --user "admin:*****"
thargenediad
źródło
4

Oto, co faktycznie zadziałało dla mnie, po wskazówkach z odpowiedzi tutaj:

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
źródło
2

Istniejące odpowiedzi wskazują, że curl może publikować dane z pliku i wykorzystywać heredoc, aby uniknąć nadmiernego ucieczki cytatów i wyraźnie podzielić JSON na nowe linie. Jednak nie ma potrzeby definiowania funkcji ani przechwytywania danych wyjściowych z cat, ponieważ curl może wysyłać dane ze standardowego wejścia. Uważam, że ten formularz jest bardzo czytelny:

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
źródło