ทดสอบว่าสตริงมีสตริงย่อยหรือไม่


40

ฉันมีรหัส

file="JetConst_reco_allconst_4j2t.png"
if [[ $file == *_gen_* ]];
then
    echo "True"
else
    echo "False"
fi

ฉันทดสอบว่าfileมี "gen" หรือไม่ ผลลัพธ์คือ "เท็จ" ดี!

ปัญหาคือเมื่อฉันแทนที่ "gen" ด้วยตัวแปรtestseq:

file="JetConst_reco_allconst_4j2t.png"
testseq="gen"
if [[ $file == *_$testseq_* ]];
then
    echo "True"
else
    echo "False"
fi

ตอนนี้เอาต์พุตคือ "True" มันจะเป็นอย่างไร จะแก้ไขปัญหาได้อย่างไร


ซ้ำซ้อนที่เป็นไปได้ของการทดสอบ Shell เพื่อหารูปแบบในสตริง

คำตอบ:


25

คุณต้องสอดแทรก$testseqตัวแปรด้วยวิธีใดวิธีหนึ่งต่อไปนี้:

  • $file == *_"$testseq"_*(นี่$testseqถือว่าเป็นสตริงคงที่)

  • $file == *_${testseq}_*(นี่$testseqถือว่าเป็นรูปแบบ)

หรือ_ทันทีหลังจากชื่อตัวแปรจะถูกนำมาเป็นส่วนหนึ่งของชื่อตัวแปร (มันเป็นตัวละครที่ถูกต้องในชื่อตัวแปร)


คำตอบที่ถูกต้องตามที่ใช้กับ OP แต่ไม่มีการพกพา (นี่คือคำวิจารณ์ของคำตอบที่ให้ไว้ไม่เพียงเตือนให้ผู้อ่าน) ;-)
Cbhihe

28

ใช้=~โอเปอเรเตอร์เพื่อสร้างนิพจน์ทั่วไป:

#!/bin/bash
file="JetConst_reco_allconst_4j2t.png"
testseq="gen"
if [[ $file =~ $testseq ]];
then
    echo "True"
else
    echo "False"
fi

วิธีนี้จะเป็นการเปรียบเทียบว่า$fileมี$testseqเนื้อหาหรือไม่

user@host:~$ ./string.sh
False

ถ้าฉันเปลี่ยนtestseq="Const":

user@host:~$ ./string.sh
True

แต่ระวังสิ่งที่คุณเลี้ยง$testseqด้วย หากสตริงที่มันแสดงให้เห็นว่าบางคน regex (เช่น[0-9]ตัวอย่าง) มีโอกาสมากขึ้นที่จะเรียก "การแข่งขัน"

เอกสารอ้างอิง :


20
file="JetConst_reco_allconst_4j2t.png"
testseq="gen"

case "$file" in
    *_"$testseq"_*) echo 'True'  ;;
    *)              echo 'False'
esac

การใช้case ... esacเป็นหนึ่งในวิธีที่ง่ายที่สุดในการจับคู่รูปแบบในแบบพกพา การทำงานเป็น "เปลี่ยน" คำสั่งในภาษาอื่น ๆ ( bash, zshและksh93ยังช่วยให้คุณทำในฤดูใบไม้ร่วงผ่านในรูปแบบที่เข้ากันไม่ได้ต่างๆ) รูปแบบที่ใช้เป็นรูปแบบชื่อไฟล์มาตรฐานการวนรอบ

ปัญหาที่คุณพบนั้นเกิดจากความจริงที่ว่า_เป็นอักขระที่ถูกต้องในชื่อตัวแปร เชลล์จะมอง*_$testseq_*ว่า " *_ตามด้วยค่าของตัวแปร$testseq_และ*" ตัวแปร$testseq_ไม่ได้ถูกกำหนดดังนั้นมันจะถูกขยายเป็นสตริงว่างเปล่าและคุณก็จบลงด้วย*_*ซึ่งตรงกับ$fileค่าที่คุณมี คุณอาจคาดหวังว่าจะได้รับTrueตราบใดที่ชื่อไฟล์$fileมีเครื่องหมายขีดล่างอย่างน้อยหนึ่งรายการ

ที่จะต้องคั่นชื่อของตัวแปรที่ใช้รอบการขยายตัว:"..." *_"$testseq"_*สิ่งนี้จะใช้ค่าของตัวแปรเป็นสตริง คุณต้องการใช้ค่าของตัวแปรเป็นรูปแบบหรือไม่ใช้*_${testseq}_*แทน

อีกหนึ่งการแก้ไขด่วนคือการรวมขีดล่างในค่าของ$testseq:

testseq="_gen_"

จากนั้นใช้*"$testseq"*เป็นรูปแบบ (สำหรับการเปรียบเทียบสตริง)


ดังนั้นเชลล์จะค้นหาตัวแปร $ testseq_ และไม่พบมันและแทนที่ด้วยสตริงว่าง
Viesturs

@Viesturs นั่นคือหัวใจของปัญหาใช่
Kusalananda

1
สำหรับสตริงย่อยค้นหามันควรจะเป็น*"$testseq"*สำหรับcaseเหมือน[[...]](ยกเว้น zsh เว้นแต่คุณจะใช้ globsubst)
Stéphane Chazelas
โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.