การต่อสตริงสตริง Bash ใช้เพื่อสร้างรายการพารามิเตอร์


12

รับชิ้นส่วนทุบตีนี้:

PARMS='-rvu'
PARMS+=" --delete --exclude='.git'"
echo $PARMS
rsync ${PARMS} . ${TARGET}

echo แสดงสตริง PARMS ตามที่คาดไว้จะไม่มีข้อผิดพลาดปรากฏขึ้น แต่ rsync จะทำหน้าที่อย่างเงียบ ๆ ราวกับไม่มีตัวเลือกที่เพิ่มโดย + = อยู่ อย่างไรก็ตามทำงานได้ตามที่คาดไว้:

PARMS='-rvu'
rsync ${PARMS} --delete --exclude='.git' . ${TARGET}

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


1
echo "$PARMS"และrsync "${PARMS}"...
jasonwryan

สิ่งนี้ใช้ได้กับฉันในbashเวอร์ชัน 4.2.25 โดยไม่มีการเปลี่ยนแปลงใด ๆ
Anthon

คำตอบ:


17

มีความแตกต่างระหว่าง:

PARMS+="... --exclude='.git'"

และ

... --exclude='.git'

ในครั้งแรกคำพูดเดียวอยู่ภายในเครื่องหมายคำพูดด้วยตนเองดังนั้นจึงมีอยู่ในข้อความที่ถูกแทนที่ที่กำหนดให้rsyncเป็นอาร์กิวเมนต์ ได้รับการโต้แย้งค่าซึ่งเป็นrsync --exclude='.git'ในครั้งที่สองราคาเดียวจะถูกตีความโดยเปลือกในขณะที่พวกเขากำลังเขียนเพราะพวกเขาไม่ได้อยู่ในเครื่องหมายตัวเองและได้รับการเห็นrsync--exclude=.git

ในกรณีนี้คุณไม่จำเป็นต้องใช้เครื่องหมายคำพูดใด ๆ เลย - .gitเป็นคำของเชลล์ที่ถูกต้องสมบูรณ์แบบด้วยตัวเองโดยไม่มีอักขระพิเศษดังนั้นคุณสามารถใช้มันได้อย่างแท้จริงในคำสั่ง

ดีกว่าสำหรับสิ่งนี้แม้ว่าเป็นอาร์เรย์ :

PARMS=(-rvu)
PARMS+=(--delete --exclude='.git')
rsync "${PARMS[@]}"

สิ่งนี้จะสร้างคำสั่งของคุณเป็นคำที่แยกกันไม่ว่าคุณต้องการตีความอะไรในเวลาที่คุณเขียนอาเรย์ "${PARMS[@]}"ขยายไปยังแต่ละรายการในอาเรย์เป็นอาร์กิวเมนต์แยกต่างหากแม้ว่าอาร์กิวเมนต์นั้นจะมีอักขระพิเศษหรือช่องว่างอยู่ดังนั้นให้rsyncดูสิ่งที่คุณเขียนตามที่คุณต้องการ


bashดำเนินการแยกคำหลังจาก${PARMS}ถูกขยาย ดังนั้นคำพูดเดียวก็ถูกตีความโดยเชลล์
cuonglm

2
ลองมัน! ฉันทำ. คำพูดยังคงอยู่และหากมีช่องว่างในระหว่างพวกเขาเป็นจุดแยกต่อไป
Michael Homer

@Gnouc: จากหน้าคนทุบตี "อ้างกำจัด: หลังจากที่ก่อนหน้านี้ขยายทั้งหมดเกิดขึ้น unquoted ของตัวละคร\ , 'และ". ที่ไม่ได้เป็นผลมาจากหนึ่งในการขยายดังกล่าวข้างต้นจะถูกลบออก" "การขยายตัวดังกล่าวข้างต้น" ${PARMS}รวมถึงการขยายตัวพารามิเตอร์ซึ่งดำเนินการขยายตัวของ
camh

ขอบคุณ ดังนั้นฉันจึงเข้าใจว่าในกรณีนั้นการไม่ใส่เครื่องหมายคำพูดเดี่ยวภายในเครื่องหมายคำพูดคู่นั้นจะได้ผล แต่เพื่อความสมบูรณ์ - จะเกิดอะไรขึ้นถ้าฉันต้องพูดอักขระพิเศษบางตัวและไม่ต้องการใช้วิธีหลังของคุณ?
neuviemeporte

หากตัวละครพิเศษของคุณไม่ได้เป็นส่วนหนึ่งของIFS(โดยทั่วไปช่องว่าง) คุณไม่จำเป็นต้องพูด หากพวกเขาเป็นคุณจะโชคไม่ดีถ้าคุณไม่ได้แฮ็คบางอย่างร่วมกันeval- นี่เป็นความผิดปกติเล็กน้อยและอาร์เรย์คือวิธีที่เหมาะสมในการจัดการกับมัน
Michael Homer

2

นอกจากคำตอบ @Michael Homerคุณสามารถใช้bash ฟังก์ชัน eval :

PARMS='-rvu'
PARMS+=" --delete --exclude='.git'"
echo "$PARMS"
eval "rsync ${PARMS} . "'"${TARGET}"'

2
คุณทำได้ แต่ไม่ควรทำ อาร์เรย์ที่ถูกเพิ่มเข้ามาโดยเฉพาะevalเพื่อหลีกเลี่ยงการใช้นี้
chepner
โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.