วิธีการตรวจสอบว่าสตริงเป็นสตริงย่อยของอื่นในทุบตี?


49

ฉันต้องการดูว่าสตริงอยู่ในส่วนของสตริงอื่นหรือไม่
เช่น:

'ab' in 'abc' -> true
'ab' in 'bcd' -> false

ฉันจะทำสิ่งนี้ในเงื่อนไขของสคริปต์ทุบตีได้อย่างไร

คำตอบ:


27

คุณสามารถใช้แบบฟอร์ม${VAR/subs}ที่VARมีสตริงที่ใหญ่กว่าและ subsเป็นสตริงย่อยที่คุณพยายามค้นหา:

my_string=abc
substring=ab
if [ "${my_string/$substring}" = "$my_string" ] ; then
  echo "${substring} is not in ${my_string}"
else
  echo "${substring} was found in ${my_string}"
fi

วิธีนี้ใช้งานได้เพราะ${VAR/subs}มีค่าเท่ากับ$VARแต่เมื่อมีการsubsลบสตริงครั้งแรกโดยเฉพาะหาก$VARไม่มีคำที่subsไม่ได้แก้ไข


ฉันคิดว่าคุณควรเปลี่ยนลำดับของechoงบ เพราะฉันได้รับab is not in abc
Lucio

คุณพูดถูก! : P
edwin

อืมมม .. สคริปต์นั้นผิด เช่นเดียวกับที่ฉันได้รับab was found in abcแต่ถ้าฉันใช้substring=zฉันจะได้รับz was found in abc
Lucio

1
ตอนนี้ฉันได้รับab is not in abcแล้ว z was found in abcแต่ นี่เป็นเรื่องตลก: D
Lucio

1
ดุจ! เสียงสะท้อนดังขึ้นในตอนเริ่มต้น! XD
edwin

47

[[ "bcd" =~ "ab" ]]
[[ "abc" =~ "ab" ]]

=~วงเล็บมีการทดสอบและมันเป็นวงเล็บคู่ก็สามารถดังนั้นบางการทดสอบพิเศษเช่น

ดังนั้นคุณสามารถใช้รูปแบบนี้เช่น

var1="ab"
var2="bcd"
if [[ "$var2" =~ "$var1" ]]; then
    echo "pass"
else
    echo "fail"
fi

แก้ไข:แก้ไข "= ~" ได้พลิกแล้ว


1
ฉันจะได้รับfailกับพารามิเตอร์นี้:var2="abcd"
Lucio

3
@Lucio [[ $string =~ $substring ]]ถูกต้องคือ ฉันอัพเดตคำตอบแล้ว
Eric Carvalho


10

สองวิธีต่อไปนี้จะทำงานบนสภาพแวดล้อมที่เข้ากันได้กับ POSIX ไม่ใช่เฉพาะใน bash:

substr=ab
for s in abc bcd; do
    if case ${s} in *"${substr}"*) true;; *) false;; esac; then
        printf %s\\n "'${s}' contains '${substr}'"
    else
        printf %s\\n "'${s}' does not contain '${substr}'"
    fi
done
substr=ab
for s in abc bcd; do
    if printf %s\\n "${s}" | grep -qF "${substr}"; then
        printf %s\\n "'${s}' contains '${substr}'"
    else
        printf %s\\n "'${s}' does not contain '${substr}'"
    fi
done

ทั้งเอาต์พุตข้างต้น:

'abc' contains 'ab'
'bcd' does not contain 'ab'

อดีตมีข้อได้เปรียบของการไม่วางไข่grepกระบวนการแยกต่างหาก

โปรดทราบว่าฉันใช้printf %s\\n "${foo}"แทนecho "${foo}"เพราะechoอาจมีปัญหา${foo}ถ้ามันมีแบ็กสแลช


เวอร์ชันแรกทำงานได้อย่างสมบูรณ์แบบในการค้นหาซับสตริงของชื่อจอภาพในรายการชื่อxrandrจอภาพที่เก็บไว้ในตัวแปร +1 และยินดีต้อนรับสู่สโมสรตัวแทน 1K :)
WinEunuuchs2Unix

6

คำสั่งกรณีเชลล์

นี่เป็นโซลูชั่นแบบพกพาที่สุดแม้จะใช้กับ Bourne shell และ Korn shell ก็ตาม

#!/bin/bash
case "abcd" in
    *$1*) echo "It's a substring" ;;
    *) echo "Not a substring" ;;
esac

วิ่งตัวอย่าง:

$ ./case_substr.sh "ab"                                                                                           
It's a substring
$ ./case_substr.sh "whatever"                                                                                     
Not a substring

โปรดทราบว่าคุณไม่จำเป็นต้องใช้งานเป็นพิเศษechoคุณสามารถใช้exit 1และexit 0เพื่อบ่งบอกถึงความสำเร็จหรือความล้มเหลว

สิ่งที่เราสามารถทำได้เช่นกันคือสร้างฟังก์ชั่น (ซึ่งสามารถใช้ในสคริปต์ขนาดใหญ่หากจำเป็น) ด้วยค่าส่งคืนเฉพาะ (0 เมื่อจับคู่, 1 โดยไม่มีการจับคู่):

$ ./substring_function.sh                                  
ab is substring

$ cat substring_function.sh                                
#!/bin/sh

is_substring(){
    case "$2" in
        *$1*) return 0;;
        *) return 1;;
    esac
}

main(){
   if is_substring "ab" "abcdefg"
   then
       echo "ab is substring"
   fi
}

main $@

grep

$ grep -q 'ab' <<< "abcd" && echo "it's a substring" || echo "not a substring"                                    
it's a substring

bashวิธีการนี้โดยเฉพาะอย่างยิ่งจะเป็นประโยชน์กับงบถ้า-อื่นใน ยังพกพาเป็นส่วนใหญ่

AWK

$ awk '$0~/ab/{print "it is a substring"}' <<< "abcd"                                                             
it is a substring

หลาม

$ python -c 'import sys;sys.stdout.write("it is a substring") if "ab" in sys.stdin.read() else exit(1)' <<< "abcd"
it is a substring

ทับทิม

$ ruby -e ' puts "is substring" if  ARGV[1].include? ARGV[0]'  "ab" "abcdef"                                             
is substring

+1 สำหรับการทำงานที่เหนือกว่าใคร ๆ ฉันสังเกตเห็นที่นี่และในไซต์แลกเปลี่ยนสแต็กอื่น ๆ ไม่มีคำตอบส่งคืนออฟเซ็ตย่อยของสตริงภายในสตริง ซึ่งเป็นภารกิจของคืนนี้ :)
WinEunuuchs2Unix

@ WinEunuuchs2Unix จะทำเช่นนั้นในทุบตี?
Sergiy Kolodyazhnyy

ใช่และไม่ฉันกำลังทำโครงการแฟรงเกนสไตน์ซึ่งไพ ธ อนได้รับเมตาดาต้าข้อความ gmail.com ทั้งหมดและทุบตีแยกวิเคราะห์และนำเสนอรายการ GUI พร้อมการเจาะลึก ฉันพบคำตอบแล้วที่นี่: stackoverflow.com/questions/5031764/…
WinEunuuchs2Unix

@ WinEunuuchs2Unix ตกลง ฟังดูน่าสนใจ. ฉันเองชอบแยกวิเคราะห์ทุกอย่างใน Python มันมีความสามารถในการประมวลผลข้อความมากกว่าทุบตีเพียงอย่างเดียว
Sergiy Kolodyazhnyy

ฉันรู้ว่าการตั้งค่าของคุณเป็นเวลาประมาณสองปีและฉันเคารพพวกเขา แต่ฉันแค่เรียนรู้ของ Python และทำให้พวกมันทำงานได้อย่างลำบาก ไม่พูดถึงการประมวลผลอาเรย์ทั้งหมดที่ฉันคุ้นเคยกับการทุบตี แต่อย่างน้อยฉันก็เขียนสคริปต์ไพ ธ อนตัวแรกของฉันเพื่อดูดทุกอย่างออกจาก gmail.com ของ google ลงในไฟล์ flat Linux ใช่ไหม :)
WinEunuuchs2Unix

5

คำนึงถึง[[และ":

[[ $a == z* ]]   # True if $a starts with an "z" (pattern matching).
[[ $a == "z*" ]] # True if $a is equal to z* (literal matching).

[ $a == z* ]     # File globbing and word splitting take place.
[ "$a" == "z*" ] # True if $a is equal to z* (literal matching).

ดังที่ @glenn_jackman พูด แต่โปรดทราบว่าหากคุณใส่คำที่สองทั้งหมดด้วยเครื่องหมายคำพูดคู่มันจะเปลี่ยนการทดสอบเป็นการจับคู่ตามตัวอักษร

ที่มา: http://tldp.org/LDP/abs/html/comparison-ops.html


4

คล้ายกับคำตอบของเอ็ดวิน แต่ด้วยความสะดวกในการพกพาที่ดีขึ้นสำหรับ posix & ksh และมีเสียงรบกวนน้อยกว่าของ Richard:

substring=ab

string=abc
if [ "$string" != "${string%$substring*}" ]; then
    echo "$substring IS in $string"
else
    echo "$substring is NOT in $string"
fi

string=bcd
if [ "$string" != "${string%$substring*}" ]; then
    echo "$string contains $substring"
else
    echo "$string does NOT contain $substring"
fi

เอาท์พุท:

abc contains ab
bcd does NOT contain ab
โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.