ฉันจะคัดค้านการทดสอบด้วยการแสดงออกปกติในสคริปต์ทุบตีได้อย่างไร


173

การใช้ GNU bash (รุ่น 4.0.35 (1) - ปล่อย (x86_64-suse-linux-gnu) ฉันต้องการที่จะปฏิเสธการทดสอบด้วยนิพจน์ทั่วไปตัวอย่างเช่นฉันต้องการเพิ่มเส้นทางไปยังตัวแปร PATH อย่างมีเงื่อนไข หากเส้นทางยังไม่ได้มีเช่นใน:

TEMP=/mnt/silo/bin
if [[ ${PATH} =~ ${TEMP} ]] ; then PATH=$PATH; else PATH=$PATH:$TEMP; fi
TEMP=/mnt/silo/Scripts:
if [[ ${PATH} =~ ${TEMP} ]] ; then PATH=$PATH; else PATH=$PATH:$TEMP; fi
TEMP=/mnt/silo/local/bin
if [[ ${PATH} =~ ${TEMP} ]] ; then PATH=$PATH; else PATH=$PATH:$TEMP; fi
export PATH

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

TEMP=/mnt/silo/bin
if ![[ ${PATH} =~ ${TEMP} ]] ; then PATH=$PATH:$TEMP; fi
TEMP=/mnt/silo/Scripts:
if ![[ ${PATH} =~ ${TEMP} ]] ; then PATH=$PATH:$TEMP; fi
TEMP=/mnt/silo/local/bin
if ![[ ${PATH} =~ ${TEMP} ]] ; then PATH=$PATH:$TEMP; fi
export PATH

คำตอบ:


193

คุณทำได้ถูกต้องเพียงแค่ใส่ช่องว่างระหว่าง!และ[[ชอบif ! [[


14
Oy vey! เมื่อฉันก้าวเท้าเลี่ยงความบ้าคลั่งของตัวละครพิเศษของ perlactic อย่างปลอดภัยฉันพบว่าตัวเองหลงทางในพื้นที่ทุบตี (ตำแหน่ง)! (ฉันรู้สึกกลัวที่จะบีบไส้ของฉันเหมือนงูใหญ่) ขอบคุณ!
David Rogers

126

คุณยังสามารถใส่เครื่องหมายอัศเจรีย์ไว้ในวงเล็บ:

if [[ ! $PATH =~ $temp ]]

แต่คุณควรยึดรูปแบบของคุณเพื่อลดผลบวกปลอม:

temp=/mnt/silo/bin
pattern="(^|:)${temp}(:|$)"
if [[ ! "${PATH}" =~ ${pattern} ]]

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


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

4
@anyoneis เชื่อใจเราในสิ่งนี้ ควรหลีกเลี่ยงการใช้ตัวแปรตัวพิมพ์ใหญ่ที่ผู้ใช้กำหนด ตัวแปรทั้งหมดใน bash จะถูกขยายด้วย$ดังนั้นจึงไม่มีเหตุผลที่จะพิมพ์ใหญ่เพื่อให้โดดเด่น
SiegeX

ฉันพบว่าif [[ ! $foo =~ bar ]]ปลอดภัยกว่าif ! [[ $foo =~ bar ]]เพราะทำให้ง่ายต่อการแนะนำเงื่อนไขเพิ่มเติมให้กับif
CTodea


9

ใช่คุณสามารถปฏิเสธการทดสอบได้เนื่องจากSiegeXได้ชี้ให้เห็นแล้ว

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

[[ ":$PATH:" != *":$1:"* ]]

(ที่มา)


1
อีกเหตุผลที่ใช้รูปแบบนี้คือจะไม่จับคู่กับวัสดุพิมพ์โดยไม่ตั้งใจ (เช่นไม่สามารถเพิ่ม "/ bin" ในพา ธ เนื่องจาก "/ usr / bin" มีอยู่แล้ว)
Gordon Davisson

ฉันใช้เวลาพอสมควรที่จะเข้าใจว่าลำไส้ใหญ่ด้านซ้ายให้การยึดที่ฉันต้องการได้อย่างไร แนวคิดในการลดรูปแบบโดยการเพิ่มเนื้อหาลงในสตริงที่จะค้นหานั้นคุ้มค่าที่จะจดจำ ฉันไม่เข้าใจว่าทำไมอักขระพิเศษในพา ธ จะรบกวนการแก้ปัญหา regex แต่ไม่ใช่รูปแบบการทุบตี คุณยกตัวอย่างให้ฉันได้ไหม
David Rogers

ฉันไม่คิดว่ามันจะทำงานได้อย่างน่าเชื่อถือในทุกกรณี การจับคู่ Regex กับ IMHO ชั้นยอด
เฟลิเป้อัลวาเรซ

5

ฉันต้องการลดความซับซ้อนของรหัสโดยไม่ต้องใช้ตัวดำเนินการตามเงื่อนไขในกรณีเช่นนี้:

TEMP=/mnt/silo/bin
[[ ${PATH} =~ ${TEMP} ]] || PATH=$PATH:$TEMP
โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.