การใช้ curl POST กับตัวแปรที่กำหนดในฟังก์ชั่นสคริปต์ทุบตี


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 script ฉันได้รับข้อผิดพลาดนี้

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"

ฉันคิดว่ามีปัญหากับเครื่องหมายคำพูดของฉัน แต่ฉันเล่นกับพวกเขามากและฉันได้รับข้อผิดพลาดที่คล้ายกัน ตัวแปรทั้งหมดถูกกำหนดด้วยฟังก์ชั่นต่าง ๆ ในสคริปต์จริง

คำตอบ:


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 -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") บอกให้ทุบตีเพื่อให้สิ่งที่อยู่ภายในเป็นอาร์กิวเมนต์เดียว (แม้ว่าจะมีช่องว่าง)

เครื่องหมายคำพูดเดี่ยวใน--dataอาร์กิวเมนต์ (เหมือนใน--data 'foo bar') ทำสิ่งเดียวกันยกเว้นพวกเขาจะส่งข้อความคำต่อคำทั้งหมด (รวมถึงอักขระเครื่องหมายคำพูดคู่และเครื่องหมายดอลลาร์)

'foo bar'"$variable"'more foo'การแทรกตัวแปรในช่วงกลางของข้อความที่ยกมาเพียงครั้งเดียวที่คุณมีจะจบคำพูดเดียวแล้วเชื่อมกับตัวแปรยกคู่และเปิดใหม่อีกครั้งคำพูดเดียวเพื่อดำเนินการต่อข้อความ:


9
"'" $ <ชื่อตัวแปร> "'" แก้ไขปัญหาที่ฉันต้องการไม่ต้องใส่เครื่องหมายคำพูด ขอบคุณ
Usman

1
วิธีนี้ใช้งานได้ แต่ฉันคิดว่าคุณสามารถเปล่งเครื่องหมายคำพูดคู่พิเศษที่ล้อมรอบตัวแปร ดังนั้นแทนที่จะเป็นเช่นนี้: - ข้อมูล '{"บัญชี": {"อีเมล": "'" $ email "'"}}' คุณสามารถทำได้: - ข้อมูล '{"บัญชี": {"อีเมล": " '$ email' "}} '
twistedstream

3
ไม่ได้ทำงานเมื่อมีช่องว่างหลัง EOF EOF ที่สอง: หลังจากลบมันทุกอย่างเรียบร้อยดี
Klaas

2
@dbreaux ขึ้นอยู่กับตำแหน่งที่คุณรันคำสั่ง curl หากคำสั่งนั้นอยู่ในสคริปต์คุณเพียงแค่กำหนดฟังก์ชั่นที่ใดก็ตามที่อยู่เหนือมันในสคริปต์เดียวกันนั้น หากคุณกำลังเรียกใช้ curl โดยตรงจากบรรทัดคำสั่งคุณมีหลายตัวเลือกหนึ่งในนั้นคือการพิมพ์ฟังก์ชั่นในไฟล์ใหม่จากนั้นที่บรรทัดคำสั่งทำงานsource my_new_fileเพื่อกำหนดฟังก์ชั่นในสภาพแวดล้อมปัจจุบันของคุณ หลังจากนั้นคุณสามารถเรียกใช้คำสั่ง curl ตามที่ระบุไว้
เซอร์โทส

2
@slashdottir นั่นเป็นคุณสมบัติทุบตีที่เรียกว่า Here Documents คุณสามารถอ่านรายละเอียดเพิ่มเติมได้ที่ลิงค์นี้ - โดยเฉพาะลองดูตัวอย่างที่ 19-5 นอกจากนี้ยังมีคำถามแบบเต็มเกี่ยวกับที่นี่ใน SO
เซอร์โทส

103

โซลูชันทดสอบด้วยhttps://httpbin.org/และ inline bash script
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.สำหรับอินพุตที่มีช่องว่าง:
ตัดตัวแปรด้วยเพิ่มเติม"เช่น"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

ว้าวใช้งานได้ :)


1
ไม่ทำงานเมื่อเมื่อ$iมีที่ว่าง :(
Vasyl Boroviak

คุณสามารถโพสต์ตัวอย่างได้ไหม?
pbaranski

1
แน่ใจ i="a b"แทน for-loop
Vasyl Boroviak

5
/bin/shฉันพบว่าได้รับการยอมรับและครั้งที่สองได้รับการโหวตคำตอบไม่ทำงานใน อย่างไรก็ตามคำตอบนี้ได้หลอกลวง และมันง่ายกว่าคำตอบอื่น ๆ ขอบคุณมาก! ฉันได้แก้ไขคำตอบของคุณด้วยการจัดรูปแบบการตัดบรรทัดที่ดีกว่า ไม่อย่างนั้นมันยากที่จะมองเห็นความฉลาด เพื่อนคู่ใจ
Vasyl Boroviak

1
ขอบคุณมาก @pbaranski คุณประหยัดเวลาได้มาก
sudhir tataraju

32

Curl สามารถโพสต์ข้อมูลไบนารีจากไฟล์ดังนั้นฉันจึงใช้การทดแทนกระบวนการและใช้ประโยชน์จากตัวอธิบายไฟล์ทุกครั้งที่ฉันต้องการโพสต์สิ่งที่น่ารังเกียจด้วย curl และยังต้องการเข้าถึง vars ในเชลล์ปัจจุบัน สิ่งที่ต้องการ:

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  }

อย่างที่คุณเห็นคุณสามารถเรียก subshells และ whatnot รวมถึง vars อ้างอิงใน heredoc '"'"'""""'''""''หวังแฮ็คนี้มีความสุขจะช่วยให้มี


2
คำตอบอื่นไม่ได้ผลสำหรับฉันขณะที่ฉันพยายามเรียกใช้มันในการแจ้งเตือนจาก Zabbix อันนี้แก้ปัญหาได้อย่างสมบูรณ์และสะอาดมากขึ้น
0rkan

แต่ถ้าคุณใส่โค้ดในฟังก์ชั่นทุบตี: 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:*****"

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'

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
โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.