Kiểm tra nếu một chuỗi chứa một chuỗi con


40

Tôi có mã

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

Tôi kiểm tra nếu filecó chứa "gen". Đầu ra là "Sai". Tốt đẹp!

Vấn đề là khi tôi thay thế "gen" bằng một biến testseq:

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

Bây giờ đầu ra là "Đúng". Lam thê nao điêu đo co thể? Làm thế nào để khắc phục vấn đề?


Câu trả lời:


25

Bạn cần nội suy $testseqbiến với một trong các cách sau:

  • $file == *_"$testseq"_*(ở đây $testseqđược coi là một chuỗi cố định)

  • $file == *_${testseq}_*(ở đây $testseqcoi như một mô hình).

Hoặc _ngay sau tên của biến sẽ được lấy làm một phần của tên biến (đó là ký tự hợp lệ trong tên biến).


Câu trả lời đúng khi áp dụng cho OP, nhưng không thể mang theo được. (Đây không phải là chỉ trích về câu trả lời được cung cấp, chỉ là một cảnh báo cho độc giả). ;-)
Cbhihe

28

Sử dụng =~toán tử để thực hiện các biểu thức tổng hợp thông thường:

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

Bằng cách này, nó sẽ so sánh nếu $file$testseqvề nội dung của nó.

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

Nếu tôi thay đổi testseq="Const":

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

Nhưng, hãy cẩn thận với những gì bạn nuôi $testseqbằng. Nếu chuỗi trên đó một số biểu thị một biểu thức chính quy ( [0-9]ví dụ như), có nhiều cơ hội để kích hoạt "khớp".

Tham khảo :


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

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

Sử dụng case ... esaclà một trong những cách đơn giản nhất để thực hiện khớp mẫu theo cách di động. Nó hoạt động như một "công tắc" tuyên bố trong các ngôn ngữ khác ( bash, zshksh93cũng cho phép bạn làm rơi qua theo những cách không tương thích khác nhau). Các mẫu được sử dụng là các mẫu Globing tên tệp tiêu chuẩn.

Vấn đề bạn gặp phải là do thực tế đó _là một ký tự hợp lệ trong một tên biến. Do đó, shell sẽ xem *_$testseq_*là " *_theo sau là giá trị của biến $testseq_*". Biến $testseq_không được xác định, vì vậy nó sẽ được mở rộng thành một chuỗi rỗng và bạn kết thúc bằng *_*, rõ ràng phù hợp với $filegiá trị mà bạn có. Bạn có thể mong đợi nhận được Truemiễn là tên tệp trong $filechứa ít nhất một dấu gạch dưới.

Để phân định chính xác tên của biến, sử dụng "..."xung quanh việc mở rộng : *_"$testseq"_*. Điều này sẽ sử dụng giá trị của biến như một chuỗi. Bạn có muốn sử dụng giá trị của biến làm mẫu , *_${testseq}_*thay vào đó hãy sử dụng .

Một cách khắc phục nhanh khác là bao gồm các dấu gạch dưới trong giá trị của $testseq:

testseq="_gen_"

và sau đó chỉ sử dụng *"$testseq"*làm mẫu (để so sánh chuỗi).


Vì vậy, shell sẽ tìm kiếm một biến $ testseq_ và không tìm thấy nó và thay thế nó bằng một chuỗi rỗng.
Viesturs

@Viesturs Đó là trọng tâm của vấn đề, vâng.
Kusalananda

1
Đối với tìm kiếm chuỗi con, nó phải là *"$testseq"*for for casefor [[...]](trừ zsh trừ khi bạn bật globsubst)
Stéphane Chazelas
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.