วิธีตรวจสอบว่าสตริงมีสตริงย่อยใน Bash . หรือไม่

How Check If String Contains Substring Bash



คำถามคือจะตรวจสอบว่าสตริงมีสตริงย่อยใน Bash ได้อย่างไร คำตอบคือ: ใช้การจับคู่รูปแบบ ทำให้เกิดคำถามอีกข้อหนึ่ง นั่นคือ Pattern Matching คืออะไร? วลีในประโยคมีลักษณะบางอย่าง นั่นคือเหตุผลที่แตกต่างจากวลีอื่นๆ ในประโยคเดียวกันหรือในประโยคอื่นๆ ลักษณะสามารถเขียนโค้ดเป็นแพทเทิร์นได้ ด้วยวิธีนี้ สามารถระบุวลีเฉพาะในสตริงได้ บทความนี้อธิบายวิธีการระบุสตริงย่อยเฉพาะในสตริงที่ใหญ่กว่า แทนที่สตริงย่อยที่ตรงกับสตริงย่อยอื่น และค้นหาสตริงย่อยใดๆ ในสตริงที่ใหญ่กว่าตามดัชนี อย่างไรก็ตาม ก่อนดำดิ่งสู่คำอธิบาย เราต้องจำวิธีต่างๆ ที่สตริงถูกสร้างขึ้นใน Bash

สตริงโดยหลบหนี Spaces

สตริงสามารถสร้างได้โดยการแทนที่แต่ละช่องว่างด้วยลำดับการเว้นวรรค ' '; เช่นเดียวกับใน:







myVar=การท่องเที่ยวใน Egypt is one of the country 's ชั้นนำ เศรษฐกิจ อุตสาหกรรม
โยนออก $myVar

ผลลัพธ์คือ:



การท่องเที่ยวในอียิปต์เป็นหนึ่งในอุตสาหกรรมเศรษฐกิจชั้นนำของประเทศ



หมายเหตุ: อะพอสทรอฟียังใช้ลำดับการเว้นวรรคด้วย





สตริงโดยคำคมเดียว

โปรแกรมเมอร์มีเวลาที่จะหลบหนีช่องว่างทั้งหมดในสตริงหรือไม่? ไม่ ดังนั้น การใช้อัญประกาศเดี่ยวสองอันเพื่อคั่นสตริงจะดีกว่า เช่น:

myVar='การท่องเที่ยวในอียิปต์เป็นหนึ่งในประเทศ' ''อุตสาหกรรมเศรษฐกิจชั้นนำ.'

สตริงที่มีเครื่องหมายอัญประกาศเดี่ยวไม่อนุญาตให้มีการขยาย (แทนที่ด้วยเอฟเฟกต์) ของเอสเคปซีเควนซ์ใดๆ โชคดีที่หากมีการเข้ารหัสสองสตริงติดกัน จะถือเป็นสตริงเดียว สามารถแทรกลำดับการหลบหนีได้ระหว่างดังกล่าว ลำดับการหลบหนีจะขยายออก ดังนั้นผลลัพธ์จะกลายเป็น:



การท่องเที่ยวในอียิปต์เป็นหนึ่งในอุตสาหกรรมเศรษฐกิจชั้นนำของประเทศ

สตริงโดยคำคมคู่

ด้วยเครื่องหมายอัญประกาศคู่ ลำดับหลีกจะไม่ถูกขยายเช่นกัน แต่มีการขยายตัวแปร รหัสต่อไปนี้แสดงให้เห็นสิ่งนี้:

myVar=การท่องเที่ยวใน Egypt is one of the country 's ชั้นนำ เศรษฐกิจ อุตสาหกรรม
โยนออก $myVar

ผลลัพธ์คือ:

การท่องเที่ยวในอียิปต์เป็นหนึ่งในอุตสาหกรรมเศรษฐกิจชั้นนำของประเทศ

หมายเหตุ: อะพอสทรอฟียังใช้ลำดับการเว้นวรรคด้วย

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

พื้นฐานนิพจน์ทั่วไป

Regex

พิจารณาสตริงนี้:

โลกนี้ไม่ใช่บ้านของเราจริงๆ

ให้โลกเป็นสตริงย่อยที่น่าสนใจ จากนั้นสตริงขนาดใหญ่ (ทั้งสตริง) เรียกว่าสตริงเป้าหมายหรือเรียกง่ายๆว่าเป้าหมาย 'โลก' ในเครื่องหมายคำพูดเรียกว่านิพจน์ทั่วไปหรือเรียกง่ายๆว่า regex ในกรณีนี้ เนื้อหา โลก เป็นแบบแผน

จับคู่ง่าย

ในโค้ดต่อไปนี้ หากพบคำว่า 'โลก' ในเป้าหมาย เราจะบอกว่าคำนั้นตรงกัน

NS='โลกนี้ไม่ใช่บ้านของเราจริงๆ'
ทะเบียน='โลก'
ถ้า [[ $ str= ~$reg ]];แล้ว
โยนออกพบ
อื่น
โยนออกไม่พบ
เป็น

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

พบ

ตามแบบฉบับ โลก อยู่ในเป้าหมาย โปรดทราบว่าพื้นที่คั่นหลัง [[ และก่อน ]] ได้รับการคงไว้

ลวดลาย

ในโค้ดด้านบน 'world' ในเครื่องหมายคำพูดคือ regex ในขณะที่ world เป็นรูปแบบ นี่เป็นรูปแบบตรงไปตรงมา อย่างไรก็ตาม รูปแบบส่วนใหญ่ไม่ง่ายอย่างนั้น รูปแบบคือลักษณะของสตริงย่อยที่จะพบ ดังนั้น รูปแบบ Bash จึงใช้อักขระเมตาบางตัว อักขระเมตาคืออักขระเกี่ยวกับอักขระอื่น ตัวอย่างเช่น Bash Pattern ใช้ metacharacters ต่อไปนี้:

^ $ . * +? () [] {} |

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

คลาสตัวละคร

วงเล็บเหลี่ยม

พบผลลัพธ์ของรหัสต่อไปนี้ หมายความว่ามีการจับคู่เกิดขึ้น:

NS='แมวเข้ามาในห้อง'
ถ้า [[ $ str= ~[cbr]ที่]];แล้ว
โยนออกพบ
เป็น

รูปแบบ [cbr]at มีการจับคู่ cat ซึ่งขึ้นต้นด้วย 'c' และดำเนินต่อไปและลงท้ายด้วย at [cbr]at หมายถึง จับคู่ 'c' หรือ 'b' หรือ 'r' ตามด้วย at

พบผลลัพธ์ของรหัสต่อไปนี้ หมายความว่ามีการจับคู่เกิดขึ้น:

NS='ค้างคาวเข้ามาในห้อง'
ถ้า [[ $ str= ~[cbr]ที่]];แล้ว
โยนออกพบ
เป็น

รูปแบบ [cbr]at ตรงกับ bat ซึ่งขึ้นต้นด้วย 'b' และดำเนินต่อไปและลงท้ายด้วย at [cbr]at หมายถึง จับคู่ 'c' หรือ 'b' หรือ 'r' ตามด้วย at

พบผลลัพธ์ของรหัสต่อไปนี้ หมายความว่ามีการจับคู่เกิดขึ้น:

NS='หนูเข้ามาในห้อง'
ถ้า [[ $ str= ~[cbr]ที่]];แล้ว
โยนออกพบ
เป็น

รูปแบบ [cbr]at ตรงกับ rat ซึ่งขึ้นต้นด้วย 'r' และต่อด้วย at

ในตัวอย่างโค้ดข้างต้น โปรแกรมเมอร์ไม่ทราบว่า cat หรือ bat หรือ rat มีอยู่ในสตริงเป้าหมายหรือไม่ แต่เขารู้ว่าสตริงย่อยเริ่มต้นด้วย 'c' หรือ 'b' หรือ 'r' จากนั้นดำเนินการต่อและลงท้ายด้วย at วงเล็บเหลี่ยมในรูปแบบช่วยให้อักขระต่างๆ ที่เป็นไปได้สามารถจับคู่อักขระหนึ่งตัวในตำแหน่งที่สัมพันธ์กับอักขระอื่นๆ ในเป้าหมายได้ ดังนั้น วงเล็บเหลี่ยมมีชุดอักขระ ซึ่งตรงกับชุดอักขระย่อย ในที่สุดก็เป็นสตริงย่อยที่สมบูรณ์ที่ตรงกัน

ช่วงของตัวละคร

ในรหัสด้านบน [cbr] เป็นคลาส แม้ว่า 'c' หรือ 'b' หรือ 'r' จะสอดคล้องกับอักขระตัวเดียว หากตามหลังไม่ตรงกัน รูปแบบจะไม่ตรงกับสิ่งใด

มีบางช่วงที่จะสร้างคลาส ตัวอย่างเช่น 0 ถึง 9 หลักในรูปแบบคลาส [0-9] โดยรวม 0 และ 9 ตัวพิมพ์เล็ก 'a' ถึง 'z' สร้างคลาส [a-z] โดยรวม 'a' และ 'z' ตัวพิมพ์ใหญ่ 'A' ถึง 'Z' สร้างคลาส [A-Z] โดยรวม 'A' และ 'Z' จากคลาส เป็นอักขระตัวหนึ่งที่จะจับคู่อักขระหนึ่งตัวในสตริง

รหัสต่อไปนี้สร้างการจับคู่:

ถ้า [[ 'ID8id'= ~[0-9] ]];แล้ว
โยนออกพบ
เป็น

คราวนี้เป้าหมายเป็นสตริงตามตัวอักษรในเงื่อนไข 8 ซึ่งเป็นหนึ่งในตัวเลขที่เป็นไปได้ภายในช่วง [0-9] ตรงกับ 8 ในสตริง 'ID8id' รหัสข้างต้นเทียบเท่ากับ:

ถ้า [[ 'ID8id'= ~[0123456789] ]];แล้ว
โยนออกพบ
เป็น

ในที่นี้ ตัวเลขที่เป็นไปได้ทั้งหมดถูกเขียนในรูปแบบ ดังนั้นจึงไม่มียัติภังค์

ในรหัสต่อไปนี้จะได้รับการจับคู่:

ถ้า [[ 'ID8iD'= ~[a-z] ]];แล้ว
โยนออกพบ
เป็น

การจับคู่อยู่ระหว่าง 'i' ตัวพิมพ์เล็กของช่วง [a-z] และตัวพิมพ์เล็ก 'i' ของสตริงเป้าหมาย 'ID8iD'

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

ถ้า [[ 'ID8id เป็นตัวระบุ'=~ ID[0-9]NS ]];แล้ว
โยนออกพบ
เป็น

ผลลัพธ์คือ: พบ 'ID8id' จากรูปแบบตรงกับ 'ID8id' ในสตริงเป้าหมาย

การปฏิเสธ

การจับคู่ไม่ได้มาจากรหัสต่อไปนี้:

ถ้า [[ '0123456789101112'= ~[^0-9] ]];แล้ว
โยนออกพบ
อื่น
โยนออกไม่พบ
เป็น

ผลลัพธ์คือ:

ไม่พบ

ถ้าไม่มี ^ ข้างหน้าช่วง ภายในวงเล็บเหลี่ยม ศูนย์ของช่วงจะตรงกับศูนย์แรกของสตริงเป้าหมาย ดังนั้น ^ ที่ด้านหน้าของช่วง (หรืออักขระเสริม) จะลบล้างคลาส

รหัสต่อไปนี้สร้างการจับคู่เนื่องจากเงื่อนไขอ่าน: จับคู่อักขระที่ไม่ใช่ตัวเลขที่ใดก็ได้ในเป้าหมาย:

ถ้า [[ 'ABCDEFGHIJ'= ~[^0-9] ]];แล้ว
โยนออกพบ
อื่น
โยนออกไม่พบ
เป็น

ดังนั้นผลลัพธ์คือ: found

[^0-9] หมายถึงไม่ใช่ตัวเลข ดังนั้น [^0-9] จึงเป็นค่าลบของ [0-9]

[^a-z] หมายถึงตัวอักษรที่ไม่ใช่ตัวพิมพ์เล็ก ดังนั้น [^a-z] จึงเป็นค่าลบของ [a-z]

[^A-Z] หมายถึงตัวอักษรที่ไม่ใช่ตัวพิมพ์ใหญ่ ดังนั้น [^A-Z] จึงเป็นค่าลบของ [A-Z]

มีการปฏิเสธอื่น ๆ

ช่วงเวลา (.) ในรูปแบบ

จุด (.) ในรูปแบบตรงกับอักขระใดๆ รวมทั้งตัวมันเอง พิจารณารหัสต่อไปนี้:

ถ้า [[ '6759WXY.A3'= ~ 7.9W.Y.A]];แล้ว
โยนออกพบ
เป็น

พบผลลัพธ์ของรหัสเนื่องจากอักขระอื่นตรงกัน หนึ่งจุดตรงกับ '5'; จุดอื่นตรงกับ 'X'; และจุดสุดท้ายตรงกับจุด

การจับคู่สลับ

พิจารณาประโยคนี้สำหรับสตริงเป้าหมาย:

กรงมีนกหลายชนิด

บางคนอาจต้องการทราบว่าเป้าหมายนี้มีนกพิราบหรือนกยูงหรือนกอินทรีหรือไม่ สามารถใช้รหัสต่อไปนี้:

NS='กรงมีนกยูงหลายชนิด'
ถ้า [[ $ str=~ นกพิราบ|นกยูง|อินทรี]];แล้ว
โยนออกพบ
อื่น
โยนออกไม่พบ
เป็น

ผลลัพธ์คือพบ การเปลี่ยน metacharacter | ได้รับการว่าจ้าง อาจมีทางเลือกสอง สาม สี่ และอื่นๆ สิ่งที่ตรงกันในรหัสนี้คือ 'นกยูง'

การจัดกลุ่ม

ในรูปแบบต่อไปนี้ วงเล็บถูกใช้เพื่อจัดกลุ่มอักขระ:

เวที (นักเต้น)

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

(นักเต้นยอดเยี่ยมมาก)

ที่นี่กลุ่มย่อยหรือสตริงย่อยคือนักเต้นที่ยอดเยี่ยม

สตริงย่อยที่มีส่วนร่วม

ผู้มีส่วนได้ส่วนเสียคือบุคคลที่มีความสนใจในธุรกิจ ลองนึกภาพธุรกิจที่มีเว็บไซต์ stake.com ลองนึกภาพว่าหนึ่งในสตริงเป้าหมายต่อไปนี้อยู่ในคอมพิวเตอร์:

เว็บไซต์ Stake.com มีไว้สำหรับธุรกิจ

มีผู้มีส่วนได้ส่วนเสีย.;

ผู้มีส่วนได้ส่วนเสียทำงานให้กับ stake.com.;

ให้สตริงใด ๆ เหล่านี้เป็นเป้าหมาย โปรแกรมเมอร์อาจต้องการทราบว่า stake.com หรือผู้มีส่วนได้ส่วนเสียอยู่ในสตริงเป้าหมายหรือไม่ รูปแบบของเขาจะเป็น:

Stake.com|ผู้มีส่วนได้ส่วนเสีย

โดยใช้การสลับ

เดิมพันถูกพิมพ์สองครั้งในสองคำ สามารถหลีกเลี่ยงได้โดยการพิมพ์รูปแบบดังนี้:

เดิมพัน(.com|ผู้ถือ)

.com|holder คือกลุ่มย่อยในกรณีนี้

หมายเหตุ: การใช้อักขระสลับในกรณีนี้ Stake.com หรือผู้มีส่วนได้ส่วนเสียจะยังคงถูกค้นหา พบผลลัพธ์ของรหัสต่อไปนี้:

NS='เว็บไซต์ stake.com มีไว้เพื่อธุรกิจ'
ถ้า [[ $ str=~ เดิมพัน(.กับ|ที่ยึด) ]];แล้ว
โยนออกพบ
เป็น

สตริงย่อยที่ตรงกันคือ Stake.com

อาร์เรย์ที่กำหนดไว้ล่วงหน้า BASH_REMATCH

BASH_REMATCH เป็นอาร์เรย์ที่กำหนดไว้ล่วงหน้า สมมติว่ารูปแบบมีกลุ่ม ทั้งกลุ่มที่ตรงกัน จะเข้าสู่เซลล์เพื่อหาดัชนี 0 ของอาร์เรย์นี้ กลุ่มย่อยแรกที่ตรงกันจะเข้าสู่เซลล์สำหรับดัชนี 1; กลุ่มย่อยที่สองตรงกัน เข้าไปในเซลล์สำหรับดัชนี 2 และอื่นๆ รหัสต่อไปนี้แสดงวิธีใช้อาร์เรย์นี้:

NS='นักเต้นบนเวทีมาแล้ว'
ถ้า [[ $ str=~ เวที(นักเต้น) ]];แล้ว
โยนออกพบ
เป็น

สำหรับผมใน ${!BASH_REMATCH[@]};ทำ
printf '${BASH_REMATCH[i]}, '
เสร็จแล้ว
โยนออก

ผลลัพธ์คือ:

พบ
นักเต้นบนเวที, นักเต้น,

ทั้งกลุ่มเป็นนักเต้นบนเวที มีกลุ่มย่อยเพียงกลุ่มเดียวคือนักเต้น

หมายเหตุ: เว้นวรรคในลวดลายแล้ว

การจับคู่ความเป็นอิสระของตัวพิมพ์ใหญ่ / ล่าง

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

ร้านค้า -NSnocasematch

NS='เราชอบเพลงดีๆ'
ถ้า [[ $ str=~ ดี]];แล้ว
โยนออกพบ
เป็น

ร้านค้า -ยูnocasematch

ผลลัพธ์คือ: พบ รูปแบบคือ GoodOd สตริงย่อยที่ตรงกันคือ 'ดี' โปรดทราบว่ามีการเปิดใช้ตัวเลือก nocasematch ที่จุดเริ่มต้นของส่วนโค้ดและปิดใช้งานเมื่อสิ้นสุดส่วนของโค้ด

ความยาวของสตริง

ไวยากรณ์ที่จะได้รับความยาวของสตริงคือ:

${#PARAMETER}

ตัวอย่าง:

NS='เราชอบเพลงดีๆ'
โยนออก $ {# str}

ผลลัพธ์คือ: 19

ลดสตริง

ไวยากรณ์สำหรับการลดสตริงคือ:

${พารามิเตอร์:ออฟเซ็ต}
${PARAMETER:OFFSET:LENGTH}

โดยที่การนับ OFFSET เริ่มจากศูนย์

ตัวอย่างต่อไปนี้แสดงวิธีการลบอักขระ 11 ตัวแรกของสตริง:

NS='ฉันมักจะเต้นไปกับเพลงที่ดี'
โยนออก $ {str: 10}

ผลลัพธ์คือ:

เพลงที่ดี

นับ LENGTH เริ่มจากตัวถัดไป รหัสต่อไปนี้แสดงวิธีที่อนุญาตให้ใช้ส่วนภายในสตริง:

NS='ฉันมักจะเต้นไปกับเพลงที่ดี'
โยนออก $ {str: 10: 6}

ผลลัพธ์คือ:

ance t

อักขระ 11 ตัวแรกถูกลบ; อนุญาตให้ใช้อักขระ 6 ตัวถัดไป และอักขระที่เหลือจะถูกลบออกโดยอัตโนมัติ

ค้นหาและแทนที่

เมื่อพบสตริงย่อย จะสามารถแทนที่ด้วยสตริงย่อยอื่นได้ ไวยากรณ์สำหรับสิ่งนี้คือ:

ที่ไหน=${พารามิเตอร์/รูปแบบ/การเปลี่ยน}
ที่ไหน=${พารามิเตอร์//PATTERN/REPLACEMENT}
ที่ไหน=${พารามิเตอร์/รูปแบบ}
ที่ไหน=${พารามิเตอร์//รูปแบบ}

สำหรับไวยากรณ์แรกที่มีเครื่องหมายทับเดี่ยว เฉพาะการจับคู่ครั้งแรกเท่านั้นที่จะถูกแทนที่ ตัวอย่าง:

NS='มีหนู ค้างคาว และแมว อยู่ในห้อง'
ขวา=${str/[cbr]at/วัวใหญ่}
โยนออก $ str
โยนออก $ ret

ผลลัพธ์คือ:

มีหนู ค้างคาว และแมว อยู่ในห้อง
มีวัวตัวใหญ่ ค้างคาว และแมว อยู่ในห้อง

สำหรับไวยากรณ์ที่สองที่มีเครื่องหมายทับคู่ การแข่งขันทั้งหมดจะถูกแทนที่ ตัวอย่าง:

NS='มีหนู ค้างคาว และแมว อยู่ในห้อง'
ขวา=${str//[cbr]at/big cow}
โยนออก $ str
โยนออก $ ret

ผลลัพธ์คือ:

มีหนู ค้างคาว และแมว อยู่ในห้อง
มีวัวตัวใหญ่ วัวตัวใหญ่ และวัวตัวใหญ่อยู่ในห้อง

สำหรับไวยากรณ์ที่สามที่มีเครื่องหมายทับเดี่ยว จะไม่มีการแทนที่สำหรับการจับคู่ครั้งแรกและครั้งเดียว

นอกจากนี้ สตริงย่อยแรกที่พบจะถูกลบออก ตัวอย่าง:

NS='มีหนู ค้างคาว และแมว อยู่ในห้อง'
ขวา=${str/[cbr]ที่}
โยนออก $ str
โยนออก $ ret

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

NS='มีหนู ค้างคาว และแมว อยู่ในห้อง'
ขวา=${str//[cbr]ที่}
โยนออก $ str
โยนออก $ ret

ผลลัพธ์คือ:

มีหนู ค้างคาว และแมว อยู่ในห้อง
มี a , a และ a , ในห้องเพาะเลี้ยง

บทสรุป

ในการตรวจสอบว่าสตริงมีสตริงย่อยใน Bash หรือไม่ ต้องใช้การจับคู่รูปแบบ การจับคู่รูปแบบไม่ได้เกิดขึ้นเฉพาะในวงเล็บคู่เงื่อนไข [[ . . . ]]. นอกจากนี้ยังสามารถเกิดขึ้นได้ในการขยายพารามิเตอร์ด้วย ${ . .}. ด้วยการขยายพารามิเตอร์ สามารถรับสตริงย่อยตามดัชนีได้

สิ่งที่นำเสนอในบทความนี้คือประเด็นที่สำคัญที่สุดในการจับคู่รูปแบบ มีมากขึ้น! อย่างไรก็ตาม สิ่งที่ผู้อ่านควรศึกษาต่อไปคือการขยายชื่อไฟล์