วิธีใช้ตัวแปรภายในเครื่องหมายคำพูดเดี่ยว


11

ฉันมีแอปพลิเคชันที่ใช้เป็นคุณลักษณะอินพุตในเครื่องหมายคำพูดคู่ฝังอยู่ในเครื่องหมายคำพูดเดี่ยว ยกตัวอย่างคำสั่งที่ถูกต้องนี้:

command -p 'cluster="cl1"'

เพื่อให้เป็นไปโดยอัตโนมัติฉันสร้างไฟล์ bash โดยใช้$CLUSTERเป็นตัวแปร ฉันควรสั่งการอย่างไร กล่าวอีกนัยหนึ่งฉันควรใส่อะไรแทน cl1

โปรดทราบว่าหากฉันแก้ไขคำสั่งข้างต้นคำสั่งนั้นจะไม่ได้รับการยอมรับ ตัวอย่างเช่น: command -p "cluster=cl1"ไม่ยอมรับ


2
CLUSTER='"cl1"'; command -p "cluster=$CLUSTER"
mikeserv

ความเป็นไปได้อีกอย่างหนึ่ง (ถ้าคุณต้องการเก็บcliโดยไม่มีเครื่องหมายอัญประกาศอยู่ข้างในCLUSTERตัวแปร):CLUSTER='cl1'; command -p 'cluster="'"$CLUSTER"'"'
jimmij

ในที่สุดฉันก็พบคำตอบที่ถูกต้อง ขอบคุณ @jimmij
Mohamad-Jaafar NEHME

คำตอบ:


8

ดูเหมือนว่าคำสั่งของคุณอาจตั้งค่าตัวแปรสภาพแวดล้อมตามอาร์กิวเมนต์ที่กำหนดไว้ในบรรทัดคำสั่ง อาจเป็นได้:

CLUSTER=cl1; cluster=$CLUSTER command

... และตั้งค่าสภาพแวดล้อมสำหรับการเรียกใช้

มิฉะนั้นคำพูดของเชลล์จะกำหนดขอบเขตอาร์กิวเมนต์หรือยกเว้นอักขระเชลล์พิเศษอื่น ๆ จากการตีความเชลล์ คุณสามารถมี(และดังนั้นการหลบหนี)ชนิดของอัญประกาศเชลล์ภายในชนิดอื่น ๆ ตามกฎต่าง ๆ :

  • "''''" - สตริงที่ยกมานุ่มสามารถมีจำนวนของคำพูดยาก
  • "\""- \เครื่องหมายแบ็กสแลชสามารถหนีเครื่องหมาย"คำพูด"นุ่มนวลภายในสตริงที่ยกมานุ่ม
    • ในบริบทนี้\\แบ็กสแลชจะหนีออกไปเอง\$โทเค็นการขยายและ\newlines ดังที่ระบุไว้ด้านล่าง
  • "${expand} and then some"- สตริงที่ยกมานุ่มสามารถมีการ$ขยายตัวเปลือกตีความ
  • '"\'- 'สตริงที่ยกมายากสามารถมีตัวละครอื่น ๆ นอกเหนือจาก'อ้างยาก
  • \- เครื่องหมายแบ็กสแลชที่ไม่ได้ใส่เครื่องหมายอัญประกาศจะหนีอักขระต่อไปนี้สำหรับการตีความตามตัวอักษร - แม้แต่เครื่องหมายแบ็กสแลชตัวอื่น - ยกเว้น\newline
    • ใน\\nกรณี ewline ทั้ง\แบ็กสแลชและ\newline จะถูกลบออกอย่างสมบูรณ์จากคำสั่งที่แปลผลลัพธ์
  • ${parameter+expand "$parameter"}- คำพูดที่เกิดจากการขยายตัวของเชลล์แทบจะไม่เคยทำหน้าที่เป็นตัวคั่นเครื่องหมายยกเว้นบางกรณีพิเศษ ฉันจะไม่กล้าอธิบายเพิ่มเติมที่นี่

ฉันคิดว่ามันแปลกที่แอปพลิเคชันใด ๆ จะตีความคำพูดใน args บรรทัดคำสั่ง การฝึกฝนเช่นนี้ไม่สมเหตุสมผลนัก - สำหรับกระสุนอย่างน้อย - วัตถุประสงค์หลักของการเสนอราคาโดยทั่วไปคือการกำหนดขอบเขตการโต้แย้ง อย่างไรก็ตามเมื่อมีการร้องขออาร์กิวเมนต์จะถูกคั่นด้วย\0NULอักขระอยู่เสมอดังนั้นการเสนอราคาจึงไม่สามารถให้บริการได้มากนัก

แม้แต่เชลล์ก็มักจะรำคาญที่จะตีความคำพูดในหนึ่งในข้อโต้แย้งการภาวนาเมื่อมันถูกเรียกว่ามี-cสวิตช์ - ซึ่งหมายถึงว่าตัวถูกดำเนินการครั้งแรกของมันคือเชลล์สคริปต์ที่จริงแล้วมันควรทำงานเมื่อมีการร้องขอ นี่เป็นกรณีของอินพุตที่ประเมินสองครั้ง

จากทั้งหมดที่กล่าวมาคุณสามารถทำสิ่งต่าง ๆ เพื่อส่งคำพูดตามตัวอักษรผ่านการขัดแย้งในบรรทัดคำสั่ง ตัวอย่างเช่น:

CLUSTER='"cl1"'; command -p "cluster=$CLUSTER"

ดังที่ฉันได้บันทึกไว้ในความคิดเห็นก่อนหน้านี้คุณสามารถใส่"เครื่องหมายคำพูดไว้ในส่วนขยายที่"เสนอราคาได้

CLUSTER=cl1; command -p "cluster=\"$CLUSTER\""

คุณสามารถหลบหนี"ด้วย\แบ็กสแลชภายใน"สตริงที่ยกมา

CLUSTER=cl1; command -p cluster='"'"$CLUSTER"'"'

คุณสามารถสลับและ concatenate quoting รูปแบบที่จะมาถึงผลลัพธ์ที่คุณต้องการเป็น @jimmij บันทึกดังกล่าวข้างต้น

CLUSTER=cl1; ( set -f; IFS=; command -p cluster=\"$CLUSTER\" )

คุณสามารถปิดการใช้งานทั้งการสร้างชื่อไฟล์และการ$IFSแยก - เพื่อหลีกเลี่ยงความจำเป็นที่จะต้องอ้างคำพูด$expansionทั้งหมด - และเพื่ออ้างคำพูดเท่านั้น นี่อาจจะเกินเลยไป

สุดท้ายมี shell-quote ประเภทอื่นที่อาจใช้ ดังที่ฉันได้กล่าวไว้ก่อนหน้านี้sh -c "$scriptlet"รูปแบบของการเรียกใช้เชลล์มักจะใช้เพื่อจัดเตรียมสคริปต์ของเชลล์ในบรรทัดคำสั่ง เมื่อ$scriptletได้รับความซับซ้อนแม้ว่า - เช่นเมื่อคำพูดต้องมีคำพูดอื่น ๆ - มันมักจะเป็นประโยชน์ในการใช้ที่นี่เอกสารและsh -sแทน - ที่เชลล์ได้รับคำสั่งโดยเฉพาะเพื่อกำหนดตัวถูกดำเนินการต่อไปนี้ทั้งหมดให้กับพารามิเตอร์ตำแหน่งตามที่มันจะทำใน-cกรณี stdinและยังจะยังใช้สคริปต์จาก

หากคำสั่งของคุณต้องตีความคำพูดด้วยวิธีนี้ฉันจะพิจารณาให้ดีกว่าถ้ามันสามารถทำได้ในอินพุตไฟล์ ตัวอย่างเช่น:

CLUSTER=cl1
command --stdin <<-SCRIPT
    cluster="$CLUSTER"
SCRIPT

หากคุณไม่ได้อ้างถึงตัวคั่นของเนื้อหา<<here-documentนั้นทั้งหมดจะได้รับการปฏิบัติเกือบจะเหมือนกัน"กับคำพูดแบบนุ่ม - ยกเว้นว่า"คำพูดสองครั้งจะไม่ได้รับการปฏิบัติเป็นพิเศษ ดังนั้นถ้าเราเรียกใช้ข้างต้นด้วยcatแทน:

CLUSTER=cl1
cat <<-SCRIPT
        cluster="$CLUSTER"
SCRIPT

... มันพิมพ์ ...

cluster="cl1"

1

Like mikeservเขียนว่า:

 CLUSTER='"cl1"'; command -p "cluster=$CLUSTER" 

"ดับเบิลอ้าง" ทุกตัวอักษรที่มีช่องว่าง / metacharacters และทุกการขยายตัว: "$var", "$(command "$var")", ,"${array[@]}" "a & b"ใช้'single quotes'สำหรับรหัสหรือตัวอักษร$'s: 'Costs $5 US', ssh host 'echo "$HOSTNAME"'. ดู
http://mywiki.wooledge.org/Quotes
http://mywiki.wooledge.org/Arguments
http://wiki.bash-hackers.org/syntax/words


คุณพูดถูกขอบคุณ แต่แล้วระบบอัตโนมัติล่ะ สมมติว่าฉันต้องการอ่าน CLUSTER ฉันจะติดอีกครั้งด้วยปัญหาเดียวกัน: ตัวแปรในคำพูดเดียว
Mohamad-Jaafar NEHME

@Moi - ระบบอัตโนมัติไม่ได้เป็นเรื่องใหญ่ แต่คุณจะต้องทำความสะอาดตัวแปรของ"ตัวละครให้ดี - ตัวแรกและตัวสุดท้ายควรจะเพียงพอ ปัญหาจริงที่นี่คือแอพของคุณตีความคำพูดในหาเรื่อง การตีความคำพูดในการโต้แย้งนั้นแทบจะไม่เป็นความคิดที่ดีเลยเพราะคำพูดนั้นควรจะหมายถึงการ จำกัด การโต้แย้ง - และในการเรียกร้องที่การจัดการการคั่นนั้นถูกจัดการโดย\0NULs ในทุกกรณี อาจเป็นวิธีที่ดีกว่าในการส่งผ่านข้อมูลที่คุณต้องการไปยังแอป ชอบcommand --'script=/path/to/some/file'หรืออะไร?
mikeserv
โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.