Cách kiểm tra xem một chuỗi có chứa một chuỗi con trong Bash không


2570

Tôi có một chuỗi trong Bash:

string="My string"

Làm thế nào tôi có thể kiểm tra nếu nó chứa một chuỗi khác?

if [ $string ?? 'foo' ]; then
  echo "It's there!"
fi

Trong trường hợp ??là nhà điều hành chưa được biết của tôi. Tôi có sử dụng echo và grepkhông?

if echo "$string" | grep 'foo'; then
  echo "It's there!"
fi

Điều đó có vẻ hơi vụng về.


4
Xin chào, nếu chuỗi rỗng là sai, tại sao bạn coi nó vụng về? Đó là cách duy nhất làm việc cho tôi, bất chấp các giải pháp được đề xuất.
ericson.cepeda

1
Bạn có thể sử dụng exprlệnh tại đây
cli__

4
Đây là một trong các shell posix: stackoverflow.com/questions/2829613/ từ
sehe

Câu trả lời:


3654

Bạn cũng có thể sử dụng câu trả lời của Marcus (* ký tự đại diện) bên ngoài câu lệnh tình huống, nếu bạn sử dụng dấu ngoặc kép:

string='My long string'
if [[ $string == *"My long"* ]]; then
  echo "It's there!"
fi

Lưu ý rằng khoảng trắng trong chuỗi kim cần được đặt giữa dấu ngoặc kép và *ký tự đại diện phải ở bên ngoài. Cũng lưu ý rằng một toán tử so sánh đơn giản được sử dụng (nghĩa là ==), không phải toán tử regex =~.


127
Cũng lưu ý rằng bạn có thể đảo ngược so sánh bằng cách chuyển sang! = Trong thử nghiệm. Cảm ơn câu trả lời!
Quinn Taylor

63
@Jonik: Bạn có thể thiếu shebang hoặc có nó như #!/bin/sh. Hãy thử #!/bin/bashthay thế.
Tạm dừng cho đến khi có thông báo mới.

10
Để lại một khoảng trống giữa dấu ngoặc và nội dung.
Paul Giá

17
Bạn không cần trích dẫn các biến trong [[]]. Điều này cũng sẽ hoạt động tốt: [[$ string == $ kim ]] && echo được tìm thấy
Orwellophile

13
@Hoạt động cẩn thận! Bạn chỉ có thể bỏ qua dấu ngoặc kép trong đối số đầu tiên [[. Xem ideone.com/ZSy1gZ
nyuszika7h

611

Nếu bạn thích cách tiếp cận regex:

string='My string';

if [[ $string =~ "My" ]]
then
   echo "It's there!"
fi

2
Phải thay thế một regex egrep trong tập lệnh bash, điều này đã hoạt động hoàn hảo!
blast_hardcheese

114
Các =~nhà điều hành đã tìm kiếm toàn bộ chuỗi cho một trận đấu; các .*'s đây là không liên quan. Ngoài ra, trích dẫn thường thích hợp hơn cho dấu gạch chéo ngược:[[ $string =~ "My s" ]]
bukzor

16
@bukzor Báo giá đã ngừng hoạt động ở đây kể từ Bash 3.2+: tiswww.case.edu/php/chet/bash/FAQ E14) . Có lẽ tốt nhất là gán cho một biến (sử dụng dấu ngoặc kép), sau đó so sánh. Như thế này:re="My s"; if [[ $string =~ $re ]]
seanf

36
Kiểm tra nếu nó KHÔNG chứa một chuỗi: if [[ ! "abc" =~ "d" ]]là đúng.
KrisWebDev

1
Lưu ý rằng thứ tự kiểm tra xảy ra vấn đề. Đầu ra của dòng mã sau sẽ được chuyển tiếp 2.number=2; if [[ "1, 2, 4, 5" = *${number}* ]]; then echo forward $number; fi; if [[ *${number}* = "1, 2, 4, 5" ]]; then echo backwards $number; fi;
Douwe van der Leest

356

Tôi không chắc chắn về việc sử dụng câu lệnh if, nhưng bạn có thể nhận được hiệu ứng tương tự với câu lệnh tình huống:

case "$string" in 
  *foo*)
    # Do stuff
    ;;
esac

76
Đây có lẽ là giải pháp tốt nhất vì nó có thể mang theo vỏ posix. (còn gọi là không có bashism)
technosaurus

25
@technosaurus Tôi thấy khá kỳ quặc khi chỉ trích "bashism" trong một câu hỏi chỉ có thẻ bash :)
PP

39
@PP Đó không phải là một lời chỉ trích nhiều như là ưu tiên của một giải pháp phổ quát hơn so với một giải pháp hạn chế hơn. Vui lòng xem xét rằng, nhiều năm sau, mọi người (như tôi) sẽ dừng lại để tìm câu trả lời này và có thể hài lòng khi tìm thấy câu trả lời hữu ích trong phạm vi rộng hơn câu hỏi ban đầu. Như họ nói trong thế giới Nguồn mở: "sự lựa chọn là tốt!"
Carl Smotricz

2
@technosaurus, FWIW [[ $string == *foo* ]]cũng hoạt động trong một số phiên bản sh tuân thủ POSIX (ví dụ /usr/xpg4/bin/shtrên Solaris 10) và ksh (> = 88)
maxschlepzig

3
Busybox ash không xử lý các dấu sao trong [[... trường hợp chuyển đổi đã hoạt động!
Ray Foss

232

stringContain các biến thể (tương thích hoặc trường hợp độc lập)

Vì các câu trả lời Stack Overflow này chủ yếu nói về Bash , tôi đã đăng một hàm Bash độc lập trường hợp ở cuối bài này ...

Dù sao, có của tôi

Câu trả lời tương thích

Vì đã có rất nhiều câu trả lời sử dụng các tính năng dành riêng cho Bash, nên có một cách làm việc dưới các trình bao kém hơn, như BusyBox :

[ -z "${string##*$reqsubstr*}" ]

Trong thực tế, điều này có thể cung cấp cho:

string='echo "My string"'
for reqsubstr in 'o "M' 'alt' 'str';do
  if [ -z "${string##*$reqsubstr*}" ] ;then
      echo "String '$string' contain substring: '$reqsubstr'."
    else
      echo "String '$string' don't contain substring: '$reqsubstr'."
    fi
  done

Điều này đã được thử nghiệm dưới Bash, Dash , KornShell ( ksh) và tro (BusyBox) và kết quả luôn là:

String 'echo "My string"' contain substring: 'o "M'.
String 'echo "My string"' don't contain substring: 'alt'.
String 'echo "My string"' contain substring: 'str'.

Vào một chức năng

Theo yêu cầu của @EeroAaltonen, đây là một phiên bản của cùng một bản demo, được thử nghiệm dưới cùng một vỏ:

myfunc() {
    reqsubstr="$1"
    shift
    string="$@"
    if [ -z "${string##*$reqsubstr*}" ] ;then
        echo "String '$string' contain substring: '$reqsubstr'.";
      else
        echo "String '$string' don't contain substring: '$reqsubstr'."
    fi
}

Sau đó:

$ myfunc 'o "M' 'echo "My String"'
String 'echo "My String"' contain substring 'o "M'.

$ myfunc 'alt' 'echo "My String"'
String 'echo "My String"' don't contain substring 'alt'.

Lưu ý: bạn phải thoát hoặc nhân đôi dấu ngoặc kép và / hoặc dấu ngoặc kép:

$ myfunc 'o "M' echo "My String"
String 'echo My String' don't contain substring: 'o "M'.

$ myfunc 'o "M' echo \"My String\"
String 'echo "My String"' contain substring: 'o "M'.

Chức năng đơn giản

Điều này đã được thử nghiệm dưới BusyBox, Dash và dĩ nhiên là Bash:

stringContain() { [ -z "${2##*$1*}" ]; }

Ngay sau đó:

$ if stringContain 'o "M3' 'echo "My String"';then echo yes;else echo no;fi
no
$ if stringContain 'o "M' 'echo "My String"';then echo yes;else echo no;fi
yes

... Hoặc nếu chuỗi đã gửi có thể trống, như được chỉ ra bởi @Sjlver, hàm sẽ trở thành:

stringContain() { [ -z "${2##*$1*}" ] && [ -z "$1" -o -n "$2" ]; }

hoặc như được đề xuất bởi nhận xét của Adrian Günter , tránh các -ocông tắc:

stringContain() { [ -z "${2##*$1*}" ] && { [ -z "$1" ] || [ -n "$2" ];};}

Hàm cuối cùng (đơn giản):

Và đảo ngược các bài kiểm tra để làm cho chúng có khả năng nhanh hơn:

stringContain() { [ -z "$1" ] || { [ -z "${2##*$1*}" ] && [ -n "$2" ];};}

Với các chuỗi trống:

$ if stringContain '' ''; then echo yes; else echo no; fi
yes
$ if stringContain 'o "M' ''; then echo yes; else echo no; fi
no

Trường hợp độc lập (chỉ Bash!)

Để kiểm tra các chuỗi mà không cần quan tâm đến trường hợp, chỉ cần chuyển đổi từng chuỗi thành chữ thường:

stringContain() {
    local _lc=${2,,}
    [ -z "$1" ] || { [ -z "${_lc##*${1,,}*}" ] && [ -n "$2" ] ;} ;}

Kiểm tra:

stringContain 'o "M3' 'echo "my string"' && echo yes || echo no
no
stringContain 'o "My' 'echo "my string"' && echo yes || echo no
yes
if stringContain '' ''; then echo yes; else echo no; fi
yes
if stringContain 'o "M' ''; then echo yes; else echo no; fi
no

1
Điều này sẽ còn tốt hơn nữa, nếu bạn có thể tìm ra một cách nào đó để đưa nó vào một chức năng.
Eero Aaltonen

2
@EeroAaltonen Làm thế nào để bạn tìm thấy chức năng (mới được thêm vào) của tôi?
F. Hauri

2
Tôi biết! tìm thấy . -tên "*" | xargs grep "myfunc" 2> / dev / null
đánh trứng

6
Điều này thật tuyệt vời vì nó rất tương thích. Tuy nhiên, có một lỗi: Nó không hoạt động nếu chuỗi haystack trống. Phiên bản chính xác sẽ là string_contains() { [ -z "${2##*$1*}" ] && [ -n "$2" -o -z "$1" ]; } suy nghĩ cuối cùng: chuỗi trống có chứa chuỗi trống không? Các phiên bản trên những điều có (vì -o -z "$1"một phần).
Sjlver

3
+1. Rất tốt! Đối với tôi, tôi đã thay đổi thứ tự chuỗiContain () {[-z "$ {1 ## * $ 2 *}"] && [-z "$ 2" -o -n "$ 1"]; }; "Tìm kiếm ở đâu" "Tìm gì". Làm việc trong busybox. Câu trả lời được chấp nhận ở trên không hoạt động trong busybox.
dùng3439968

149

Bạn nên nhớ rằng shell scripting ít ngôn ngữ hơn và tập hợp nhiều lệnh hơn. Theo bản năng, bạn nghĩ rằng "ngôn ngữ" này đòi hỏi bạn phải tuân theo ifmột [hoặc a [[. Cả hai chỉ là các lệnh trả về trạng thái thoát cho biết thành công hay thất bại (giống như mọi lệnh khác). Vì lý do đó tôi sẽ sử dụng grep, và không phải [lệnh.

Cứ làm đi:

if grep -q foo <<<"$string"; then
    echo "It's there"
fi

Bây giờ bạn đang nghĩ đến việc ifkiểm tra trạng thái thoát của lệnh theo sau nó (hoàn thành với dấu chấm phẩy), tại sao không xem xét lại nguồn của chuỗi bạn đang kiểm tra?

## Instead of this
filetype="$(file -b "$1")"
if grep -q "tar archive" <<<"$filetype"; then
#...

## Simply do this
if file -b "$1" | grep -q "tar archive"; then
#...

Các -q tùy chọn làm cho grep bất cứ điều gì không đầu ra, vì chúng tôi chỉ muốn mã trở lại. <<<làm cho shell mở rộng từ tiếp theo và sử dụng nó làm đầu vào cho lệnh, một phiên bản một dòng của <<tài liệu ở đây (tôi không chắc đây là tiêu chuẩn hay Bashism).


7
chúng được gọi là chuỗi ở đây (3.6.7) Tôi tin rằng đó là bashism
alex.pilon

10
người ta cũng có thể sử dụng Thay thế quy trình if grep -q foo <(echo somefoothing); then
larsr

Lưu ý rằng không thể truy cập echođược, nếu bạn chuyển một biến, hãy sử dụng printf '%s' "$stringthay thế.
nyuszika7h

5
Chi phí của việc này rất tốn kém: thực hiện grep -q foo <<<"$mystring"1 ngã ba và là bashismecho $mystring | grep -q fooimplie 2 dĩa (một cho đường ống và thứ hai để chạy /path/to/grep)
F. Hauri

1
@BrunoBronosky echokhông có cờ vẫn có thể gặp sự cố về tính di động không mong muốn nếu chuỗi đối số chứa chuỗi dấu gạch chéo ngược. echo "nope\c"được mong đợi trên một số nền tảng để hoạt động như echo -e "nope"trên một số nền tảng khác. printf '%s' "nope"vsprintf '%s\n' 'nope\c'
tripleee

92

Câu trả lời được chấp nhận là tốt nhất, nhưng vì có nhiều cách để làm điều đó, đây là một giải pháp khác:

if [ "$string" != "${string/foo/}" ]; then
    echo "It's there!"
fi

${var/search/replace}$varvới phiên bản đầu tiên được searchthay thế bởi replace, nếu nó được tìm thấy (nó không thay đổi $var). Nếu bạn cố gắng thay thế foobằng không có gì, và chuỗi đã thay đổi, thì rõ ràng foođã được tìm thấy.


5
Giải pháp của ephemient ở trên:> `if [" $ string "! =" $ {string / foo /} "]; rồi vang lên "Nó đây rồi!" fi` rất hữu ích khi sử dụng tro vỏ của BusyBox . Giải pháp được chấp nhận không hoạt động với BusyBox vì một số biểu thức thông thường của bash không được triển khai.
TPoschel

1
sự bất bình đẳng của sự khác biệt. Suy nghĩ khá kỳ lạ! Tôi thích nó
nitinr708

1
trừ khi chuỗi của bạn là 'foo' mặc dù
venimus

Tôi đã tự viết cùng một giải pháp này (vì thông dịch viên của tôi sẽ không đưa ra câu trả lời hàng đầu) sau đó đã tìm kiếm một giải pháp tốt hơn, nhưng đã tìm thấy giải pháp này!
BuvinJ

56

Vì vậy, có rất nhiều giải pháp hữu ích cho câu hỏi - nhưng nhanh nhất / sử dụng ít tài nguyên nhất?

Các thử nghiệm lặp lại sử dụng khung này:

/usr/bin/time bash -c 'a=two;b=onetwothree; x=100000; while [ $x -gt 0 ]; do TEST ; x=$(($x-1)); done'

Thay thế KIỂM TRA mỗi lần:

[[ $b =~ $a ]]           2.92 user 0.06 system 0:02.99 elapsed 99% CPU

[ "${b/$a//}" = "$b" ]   3.16 user 0.07 system 0:03.25 elapsed 99% CPU

[[ $b == *$a* ]]         1.85 user 0.04 system 0:01.90 elapsed 99% CPU

case $b in *$a):;;esac   1.80 user 0.02 system 0:01.83 elapsed 99% CPU

doContain $a $b          4.27 user 0.11 system 0:04.41 elapsed 99%CPU

(doContain đã ở trong câu trả lời của F. Houri)

Và để cười khúc khích:

echo $b|grep -q $a       12.68 user 30.86 system 3:42.40 elapsed 19% CPU !ouch!

Vì vậy, tùy chọn thay thế đơn giản có thể dự đoán chiến thắng cho dù trong một thử nghiệm mở rộng hoặc một trường hợp. Các trường hợp là xách tay.

Đường ống ra tới 100000 greps được dự đoán là đau đớn! Các quy tắc cũ về việc sử dụng các tiện ích bên ngoài mà không cần phải đúng.


4
Điểm chuẩn gọn gàng. Thuyết phục tôi sử dụng [[ $b == *$a* ]].
Nhà vật lý điên

2
Nếu tôi đọc chính xác, casechiến thắng với mức tiêu thụ thời gian nhỏ nhất. Bạn đang thiếu một dấu sao sau đó $b in *$a. Tôi nhận được kết quả nhanh hơn một chút [[ $b == *$a* ]]so casevới sửa lỗi, nhưng nó cũng có thể phụ thuộc vào các yếu tố khác.
tripleee

1
ideone.com/5roEVt đã thử nghiệm một số lỗi bổ sung và kiểm tra một kịch bản khác (trong đó chuỗi thực sự không có trong chuỗi dài hơn). Kết quả phần lớn tương tự nhau; [[ $b == *$a* ]]nhanh chóng và casegần như nhanh chóng (và tương thích với POSIX).
tripleee

28

Điều này cũng hoạt động:

if printf -- '%s' "$haystack" | egrep -q -- "$needle"
then
  printf "Found needle in haystack"
fi

Và bài kiểm tra tiêu cực là:

if ! printf -- '%s' "$haystack" | egrep -q -- "$needle"
then
  echo "Did not find needle in haystack"
fi

Tôi cho rằng phong cách này cổ điển hơn một chút - ít phụ thuộc vào các tính năng của vỏ Bash.

Đối --số là hoang tưởng POSIX thuần túy, được sử dụng để bảo vệ chống lại các chuỗi đầu vào tương tự như các tùy chọn, chẳng hạn như --abchoặc -a.

Lưu ý: Trong một vòng lặp chặt chẽ mã này sẽ được nhiều chậm hơn so với sử dụng các tính năng Bash shell nội bộ, như một (hoặc hai) quy trình riêng biệt sẽ được tạo và kết nối thông qua đường ống.


5
... nhưng OP không cho biết phiên bản bash nào; ví dụ, các bash cũ hơn (như solaris thường có) có thể không bao gồm các tính năng bash mới hơn này. (Tôi đã gặp phải vấn đề chính xác này (không phù hợp với mô hình bash) trên solaris w / bash 2.0)
michael

2
echolà không thể truy cập, bạn nên sử dụng printf '%s' "$haystackthay thế.
nyuszika7h

2
Không, chỉ cần tránh echohoàn toàn cho bất cứ điều gì ngoại trừ văn bản bằng chữ mà không thoát mà không bắt đầu bằng a -. Nó có thể làm việc cho bạn, nhưng nó không phải là di động. Ngay cả bash cũng echosẽ hoạt động khác nhau tùy thuộc vào việc xpg_echotùy chọn được đặt. PS: Tôi đã quên đóng trích dẫn kép trong bình luận trước đây của tôi.
nyuszika7h

1
@kevinarpe Tôi không chắc chắn, --không được liệt kê trong thông số POSIXprintf , nhưng printf '%s' "$anything"dù sao bạn cũng nên sử dụng , để tránh các vấn đề nếu $anythingcó chứa một %ký tự.
nyuszika7h

1
@kevinarpe Dựa vào đó, có lẽ là vậy.
nyuszika7h

21

Bash 4+ ví dụ. Lưu ý: không sử dụng dấu ngoặc kép sẽ gây ra vấn đề khi các từ có dấu cách, v.v. Luôn luôn trích dẫn trong Bash, IMO.

Dưới đây là một số ví dụ Bash 4+:

Ví dụ 1, kiểm tra 'có' trong chuỗi (không phân biệt chữ hoa chữ thường):

    if [[ "${str,,}" == *"yes"* ]] ;then

Ví dụ 2, kiểm tra 'có' trong chuỗi (không phân biệt chữ hoa chữ thường):

    if [[ "$(echo "$str" | tr '[:upper:]' '[:lower:]')" == *"yes"* ]] ;then

Ví dụ 3, kiểm tra 'có' trong chuỗi (phân biệt chữ hoa chữ thường):

     if [[ "${str}" == *"yes"* ]] ;then

Ví dụ 4, kiểm tra 'có' trong chuỗi (phân biệt chữ hoa chữ thường):

     if [[ "${str}" =~ "yes" ]] ;then

Ví dụ 5, khớp chính xác (phân biệt chữ hoa chữ thường):

     if [[ "${str}" == "yes" ]] ;then

Ví dụ 6, khớp chính xác (không phân biệt chữ hoa chữ thường):

     if [[ "${str,,}" == "yes" ]] ;then

Ví dụ 7, khớp chính xác:

     if [ "$a" = "$b" ] ;then

Ví dụ 8, khớp ký tự đại diện .ext (không phân biệt chữ hoa chữ thường):

     if echo "$a" | egrep -iq "\.(mp[3-4]|txt|css|jpg|png)" ; then

Thưởng thức.


17

Còn cái này thì sao:

text="   <tag>bmnmn</tag>  "
if [[ "$text" =~ "<tag>" ]]; then
   echo "matched"
else
   echo "not matched"
fi

2
= ~ là để khớp regex, do đó quá mạnh cho mục đích của OP.

16

Như Paul đã đề cập trong so sánh hiệu suất của mình:

if echo "abcdefg" | grep -q "bcdef"; then
    echo "String contains is true."
else
    echo "String contains is not true."
fi

Đây là tuân thủ POSIX như 'trường hợp "$ chuỗi" trong' câu trả lời do Marcus cung cấp , nhưng nó dễ đọc hơn một chút so với câu trả lời của trường hợp. Cũng lưu ý rằng điều này sẽ chậm hơn nhiều so với sử dụng một tuyên bố trường hợp. Như Paul đã chỉ ra, đừng sử dụng nó trong một vòng lặp.



9
[[ $string == *foo* ]] && echo "It's there" || echo "Couldn't find"

Tôi sẽ thêm rằng echo "Couldn't findcâu lệnh ở cuối là một mẹo hay để trả về 0 trạng thái thoát cho các lệnh khớp này.
nicodjimenez

@nicodjimenez bạn không thể nhắm mục tiêu trạng thái thoát nữa với giải pháp này. Trạng thái thoát bị nuốt chửng bởi các thông báo trạng thái ...
Jahid

1
Đó chính xác là những gì tôi muốn nói ... Nếu bạn không có || echo "Couldn't find"thì bạn sẽ trả về trạng thái thoát lỗi nếu không có kết quả khớp, điều mà bạn có thể không muốn nếu bạn đang chạy một đường ống CI, ví dụ như bạn muốn tất cả các lệnh quay trở lại trạng thái thoát không lỗi
nicodjimenez

9

Một là:

[ $(expr $mystring : ".*${search}.*") -ne 0 ] && echo 'yes' ||  echo 'no'

2
exprlà một trong những tiện ích dao-quân-dao thường có thể làm bất cứ điều gì bạn cần làm, một khi bạn tìm ra cách thực hiện, nhưng một khi đã thực hiện, bạn không bao giờ có thể nhớ tại sao hoặc làm thế nào nó đang làm, vì vậy bạn không bao giờ chạm vào nó một lần nữa và hy vọng rằng nó sẽ không bao giờ ngừng làm những gì nó đang làm.
michael

@AloisMahdal Tôi không bao giờ bỏ phiếu, tôi chỉ nêu lý do tại sao downvote được đưa ra. Một bình luận cảnh báo. Tôi thường sử dụng expr, trong trường hợp hiếm khi, tính di động ngăn chặn sử dụng bash (ví dụ: hành vi không nhất quán trên các phiên bản cũ hơn), tr (không nhất quán ở mọi nơi) hoặc sed (đôi khi quá chậm). Nhưng từ kinh nghiệm cá nhân, bất cứ khi nào đọc lại những exprchủ nghĩa này , tôi phải quay lại trang người đàn ông. Vì vậy, tôi chỉ nhận xét rằng mọi cách sử dụng đều exprđược bình luận ...
michael

1
Đã có lúc tất cả những gì bạn có là vỏ Bourne ban đầu. Nó thiếu một số tính năng thường được yêu cầu, vì vậy các công cụ như exprtestđược triển khai để thực hiện chúng. Trong thời đại ngày nay, thường có những công cụ tốt hơn, nhiều trong số chúng được tích hợp vào bất kỳ lớp vỏ hiện đại nào. Tôi đoán testvẫn còn treo ở đó, nhưng dường như không ai bị mất tích expr.
tripleee

6

Tôi thích sed.

substr="foo"
nonsub="$(echo "$string" | sed "s/$substr//")"
hassub=0 ; [ "$string" != "$nonsub" ] && hassub=1

Chỉnh sửa, Logic:

  • Sử dụng sed để loại bỏ thể hiện của chuỗi con khỏi chuỗi

  • Nếu chuỗi mới khác với chuỗi cũ, chuỗi con tồn tại


2
Vui lòng thêm một số lời giải thích. Truyền đạt logic cơ bản quan trọng hơn là chỉ đưa ra mã, bởi vì nó giúp OP và các độc giả khác tự khắc phục vấn đề này và các vấn đề tương tự
Zulan

5

grep -q là hữu ích cho mục đích này.

Cùng sử dụng awk:

string="unix-bash 2389"
character="@"
printf '%s' "$string" | awk -vc="$character" '{ if (gsub(c, "")) { print "Found" } else { print "Not Found" } }'

Đầu ra:

Không tìm thấy

string="unix-bash 2389"
character="-"
printf '%s' "$string" | awk -vc="$character" '{ if (gsub(c, "")) { print "Found" } else { print "Not Found" } }'

Đầu ra:

Tìm

Nguồn gốc: http://unstableme.blogspot.com/2008/06/bash-search-letter-in-opes-awk.html


3
echolà không thể truy cập, bạn nên sử dụng printf '%s' "$string"thay thế. Tôi đang chỉnh sửa câu trả lời vì người dùng dường như không còn tồn tại nữa.
nyuszika7h

Theo cách nào echokhông phải là di động, @ nyuszika7h?
starbeamrainbowlabs

5

Tôi thấy cần chức năng này khá thường xuyên, vì vậy tôi đang sử dụng chức năng vỏ tự làm trong nhà .bashrcnhư thế này cho phép tôi sử dụng lại nó thường xuyên như tôi cần, với một tên dễ nhớ:

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

Để kiểm tra xem $string1(ví dụ, abc ) có trong $string2(giả sử 123abcABC ) tôi chỉ cần chạy stringinstring "$string1" "$string2"và kiểm tra giá trị trả về, ví dụ

stringinstring "$str1" "$str2"  &&  echo YES  ||  echo NO

[["$ str" == $ đế ]] && echo CÓ | | echo NO
elyase

Tôi khá chắc chắn rằng xhack chỉ được yêu cầu cho các shell rất cũ.
nyuszika7h

5

Tệp .bash_profile của tôi và cách tôi sử dụng grep:

Nếu biến môi trường PATH bao gồm hai binthư mục của tôi , đừng nối chúng,

# .bash_profile
# Get the aliases and functions
if [ -f ~/.bashrc ]; then
    . ~/.bashrc
fi

U=~/.local.bin:~/bin

if ! echo "$PATH" | grep -q "home"; then
    export PATH=$PATH:${U}
fi

1
Đây có phải là một câu trả lời?
tiền mã hóa

nâng cao. Tại sao phải học cách Bash làm điều đó khi grep, mạnh hơn nhiều, nhiều khả năng sẽ có sẵn. cũng mở rộng thêm một chút bằng cách khớp với danh sách các mẫu : grep -q -E 'pattern1|...|patternN'.
Mohamed Bana

4

Phần mở rộng của câu hỏi được trả lời ở đây Làm thế nào để bạn biết nếu một chuỗi có chứa một chuỗi khác trong POSIX sh? :

Giải pháp này hoạt động với các ký tự đặc biệt:

# contains(string, substring)
#
# Returns 0 if the specified string contains the specified substring,
# otherwise returns 1.
contains() {
    string="$1"
    substring="$2"

    if echo "$string" | $(type -p ggrep grep | head -1) -F -- "$substring" >/dev/null; then
        return 0    # $substring is in $string
    else
        return 1    # $substring is not in $string
    fi
}

contains "abcd" "e" || echo "abcd does not contain e"
contains "abcd" "ab" && echo "abcd contains ab"
contains "abcd" "bc" && echo "abcd contains bc"
contains "abcd" "cd" && echo "abcd contains cd"
contains "abcd" "abcd" && echo "abcd contains abcd"
contains "" "" && echo "empty string contains empty string"
contains "a" "" && echo "a contains empty string"
contains "" "a" || echo "empty string does not contain a"
contains "abcd efgh" "cd ef" && echo "abcd efgh contains cd ef"
contains "abcd efgh" " " && echo "abcd efgh contains a space"

contains "abcd [efg] hij" "[efg]" && echo "abcd [efg] hij contains [efg]"
contains "abcd [efg] hij" "[effg]" || echo "abcd [efg] hij does not contain [effg]"

contains "abcd *efg* hij" "*efg*" && echo "abcd *efg* hij contains *efg*"
contains "abcd *efg* hij" "d *efg* h" && echo "abcd *efg* hij contains d *efg* h"
contains "abcd *efg* hij" "*effg*" || echo "abcd *efg* hij does not contain *effg*"

Bài kiểm tra contains "-n" "n"không hoạt động ở đây, vì echo -nsẽ nuốt -ntùy chọn! Một sửa chữa phổ biến cho điều đó là sử dụng printf "%s\n" "$string"thay thế.
joeytwiddle

hoàn hảo, giải quyết chuỗi chứa khoảng trắng
dengApro

4

Vì câu hỏi POSIX / BusyBox đã bị đóng mà không cung cấp câu trả lời đúng (IMHO), tôi sẽ đăng câu trả lời tại đây.

Câu trả lời ngắn nhất có thể là:

[ ${_string_##*$_substring_*} ] || echo Substring found!

hoặc là

[ "${_string_##*$_substring_*}" ] || echo 'Substring found!'

Lưu ý rằng hàm băm képbắt buộc với một số shell ( ash). Ở trên sẽ đánh giá [ stringvalue ]khi không tìm thấy chuỗi con. Nó trả về không có lỗi. Khi chuỗi con được tìm thấy, kết quả là trống và nó đánh giá [ ]. Điều này sẽ ném mã lỗi 1 do chuỗi được thay thế hoàn toàn (do* ).

Cú pháp phổ biến ngắn nhất:

[ -z "${_string_##*$_substring_*}" ] && echo 'Substring found!'

hoặc là

[ -n "${_string_##*$_substring_*}" ] || echo 'Substring found!'

Một số khác:

[ "${_string_##$_substring_}" != "$_string_" ] && echo 'Substring found!'

hoặc là

[ "${_string_##$_substring_}" = "$_string_" ] || echo 'Substring found!'

Lưu ý các dấu bằng đơn !


3

Kết hợp từ chính xác:

string='My long string'
exactSearch='long'

if grep -E -q "\b${exactSearch}\b" <<<${string} >/dev/null 2>&1
  then
    echo "It's there"
  fi

3

Hãy thử oobash.

Nó là một thư viện chuỗi kiểu OO cho Bash 4. Nó có hỗ trợ cho âm sắc tiếng Đức. Nó được viết bằng Bash.

Nhiều chức năng có sẵn: -base64Decode, -base64Encode, -capitalize, -center, -charAt, -concat, -contains, -count, -endsWith, -equals, -equalsIgnoreCase, -reverse, -hashCode, -indexOf, -isAlnum, -isAlpha, -isAscii, -isDigit, -isEmpty, -isHexDigit, -isLowerCase, -isSpace, -isPrintable, -isUpperCase, -isVisible, -lastIndexOf, -length, -matches, -replaceAll, -replaceFirst, -startsWith, -substring, -swapCase, -toLowerCase, -toString, -toUpperCase, -trim, và -zfill.

Nhìn vào ví dụ chứa :

[Desktop]$ String a testXccc
[Desktop]$ a.contains tX
true
[Desktop]$ a.contains XtX
false

oobash có sẵn tại Sourceforge.net .


2

Tôi sử dụng chức năng này (không bao gồm một phụ thuộc nhưng rõ ràng). Nó vượt qua các bài kiểm tra dưới đây. Nếu hàm trả về giá trị> 0 thì chuỗi đã được tìm thấy. Thay vào đó, bạn có thể dễ dàng trả về 1 hoặc 0.

function str_instr {
   # Return position of ```str``` within ```string```.
   # >>> str_instr "str" "string"
   # str: String to search for.
   # string: String to search.
   typeset str string x
   # Behavior here is not the same in bash vs ksh unless we escape special characters.
   str="$(str_escape_special_characters "${1}")"
   string="${2}"
   x="${string%%$str*}"
   if [[ "${x}" != "${string}" ]]; then
      echo "${#x} + 1" | bc -l
   else
      echo 0
   fi
}

function test_str_instr {
   str_instr "(" "'foo@host (dev,web)'" | assert_eq 11
   str_instr ")" "'foo@host (dev,web)'" | assert_eq 19
   str_instr "[" "'foo@host [dev,web]'" | assert_eq 11
   str_instr "]" "'foo@host [dev,web]'" | assert_eq 19
   str_instr "a" "abc" | assert_eq 1
   str_instr "z" "abc" | assert_eq 0
   str_instr "Eggs" "Green Eggs And Ham" | assert_eq 7
   str_instr "a" "" | assert_eq 0
   str_instr "" "" | assert_eq 0
   str_instr " " "Green Eggs" | assert_eq 6
   str_instr " " " Green "  | assert_eq 1
}

Hồi hộp! Có gì phụ thuộc?
Peter Mortensen

Hàm "str_escape_special_char character". Nó nằm trong tệp GitHub arcshell_str.sh. arcshell.io sẽ giúp bạn có.
Ethan Post


0
msg="message"

function check {
    echo $msg | egrep [abc] 1> /dev/null

    if [ $? -ne 1 ];
    then 
        echo "found" 
    else 
        echo "not found" 
    fi
}

check

Điều này sẽ tìm thấy bất kỳ sự xuất hiện của a hoặc b hoặc c


0

Ví dụ haystack kim chung là sau với các biến

#!/bin/bash

needle="a_needle"
haystack="a_needle another_needle a_third_needle"
if [[ $haystack == *"$needle"* ]]; then
    echo "needle found"
else
    echo "needle NOT found"
fi
Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.