Làm thế nào để xác định nếu một chuỗi là một chuỗi con của một chuỗi khác trong bash?


49

Tôi muốn xem nếu một chuỗi nằm trong một phần của chuỗi khác.
ví dụ:

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

Làm thế nào tôi có thể làm điều này trong một điều kiện của một tập lệnh bash?

Câu trả lời:


27

Bạn có thể sử dụng các hình thức ${VAR/subs}nơi VARchứa chuỗi lớn hơn và subslà substring bạn đang cố gắng tìm:

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

Điều này hoạt động vì ${VAR/subs}bằng $VARnhưng với lần xuất hiện đầu tiên của chuỗi subsbị loại bỏ, đặc biệt nếu $VARkhông chứa từ substhì nó sẽ không được sửa đổi.


Tôi nghĩ rằng bạn nên thay đổi trình tự của các echotuyên bố. Bởi vì tôi nhận đượcab is not in abc
Lucio

Bạn đúng rồi! : P
edwin

Mmm .. Không, kịch bản sai. Giống như tôi nhận được ab was found in abc, nhưng nếu tôi sử dụng thì substring=ztôi nhận đượcz was found in abc
Lucio

1
Bây giờ tôi nhận được ab is not in abc. Nhưng z was found in abc. Điều này thật buồn cười: D
Lucio

1
Tât nhiên! Tiếng vang đã đúng khi bắt đầu điều này! XD
edwin

47

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

dấu ngoặc là dành cho thử nghiệm và vì nó là dấu ngoặc kép, nên có thể một số thử nghiệm bổ sung như thế =~.

Vì vậy, bạn có thể sử dụng hình thức này một cái gì đó như

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

Chỉnh sửa: đã sửa "= ~", đã lật.


1
Tôi nhận được failvới các thông số này:var2="abcd"
Lucio

3
@Lucio Đúng là [[ $string =~ $substring ]]. Tôi cập nhật câu trả lời.
Eric Carvalho

12

Sử dụng các mẫu tên tệp bash (còn gọi là mẫu "toàn cầu")

substr=ab
[[ abc == *"$substr"* ]] && echo yes || echo no    # yes
[[ bcd == *"$substr"* ]] && echo yes || echo no    # no

if [["$ JAVA_OPTS"! = "-XX: + UseCompressionOops" ]]; sau đó xuất JAVA_OPTS = "$ JAVA_OPTS -XX: + UseCompressionOops"; fi
Mike Slinn

10

Hai cách tiếp cận sau đây sẽ hoạt động trên mọi môi trường tương thích POSIX, không chỉ trong 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

Cả hai đầu ra trên:

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

Cái trước có lợi thế là không sinh ra một grepquá trình riêng biệt .

Lưu ý rằng tôi sử dụng printf %s\\n "${foo}"thay echo "${foo}"vì vì echocó thể mangle ${foo}nếu nó chứa dấu gạch chéo ngược.


Phiên bản đầu tiên hoạt động hoàn hảo để tìm chuỗi con của tên màn hình trong danh sách xrandrtên màn hình được lưu trong biến. +1 và chào mừng bạn đến câu lạc bộ đại diện 1K :)
WinEunuuchs2Unix

6

báo cáo vỏ

Đây là giải pháp di động nhất, sẽ hoạt động ngay cả trên vỏ Bourne cũ và vỏ Korn

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

Chạy mẫu:

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

Lưu ý rằng bạn không phải sử dụng cụ thể echobạn có thể sử dụng exit 1exit 0để biểu thị thành công hay thất bại.

Những gì chúng ta có thể làm là tốt, là tạo một hàm (có thể được sử dụng trong các tập lệnh lớn nếu cần thiết) với các giá trị trả về cụ thể (0 trên khớp, 1 không khớp):

$ ./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

Cách tiếp cận cụ thể này rất hữu ích với các câu lệnh if-other trong bash. Cũng chủ yếu là xách tay

AWK

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

Con trăn

$ 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

Hồng ngọc

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

+1 để vượt lên trên và vượt xa mọi người khác. Tôi nhận thấy ở đây và trên các trang web trao đổi ngăn xếp khác, không có câu trả lời nào trả về phần bù của chuỗi con trong chuỗi. Nhiệm vụ tối nay là gì :)
WinEunuuchs2Unix 17/11/18

@ WinEunuuchs2Unix Bạn sẽ làm điều đó trong bash?
Sergiy Kolodyazhnyy

Có và không. Tôi đang thực hiện một dự án Frankenstein trong đó python nhận được tất cả các siêu dữ liệu tin nhắn gmail và bash phân tích nó và trình bày một danh sách GUI với chi tiết. Tôi đã tìm thấy câu trả lời mặc dù ở đây: stackoverflow.com/questions/5031764/,
WinEunuuchs2Unix 17/11/18

@ WinEunuuchs2Unix OK. Nghe có vẻ thú vị. Cá nhân tôi thích phân tích mọi thứ trong Python. Nó có nhiều khả năng xử lý văn bản hơn là bash một mình.
Sergiy Kolodyazhnyy

Tôi biết sở thích của bạn trong khoảng hai năm và tôi tôn trọng họ. Nhưng tôi chỉ học Python và làm cho nó hoạt động trong đó có vẻ cồng kềnh đối với tôi. Chưa kể tất cả các xử lý mảng mà tôi đã thoải mái với bash. Nhưng ít nhất tôi đã viết kịch bản python đầu tiên của mình để hút mọi thứ ra khỏi gmail của google vào tệp phẳng Linux phải không? :)
WinEunuuchs2Unix 17/11/18

5

Tâm trí [[":

[[ $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).

Vì vậy, như @glenn_jackman đã nói, nhưng hãy nhớ rằng nếu bạn gói toàn bộ thuật ngữ thứ hai trong dấu ngoặc kép, nó sẽ chuyển bài kiểm tra sang kết hợp theo nghĩa đen .

Nguồn: http://tldp.org/LDP/abs/html/comparison-ops.html


4

Tương tự như câu trả lời của edwin, nhưng với tính di động được cải thiện cho posix & ksh, và một liên lạc ít ồn ào hơn 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

Đầu ra:

abc contains ab
bcd does NOT contain ab
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.