Cách so sánh các chuỗi trong Bash


Câu trả lời:


1375

Sử dụng biến trong câu lệnh if

if [ "$x" = "valid" ]; then
  echo "x has the value 'valid'"
fi

Nếu bạn muốn làm gì đó khi chúng không khớp, hãy thay thế =bằng !=. Bạn có thể đọc thêm về các hoạt động chuỗihoạt động số học trong tài liệu tương ứng của họ.

Tại sao chúng ta sử dụng dấu ngoặc kép xung quanh $x?

Bạn muốn các trích dẫn xung quanh $x, vì nếu nó trống, tập lệnh Bash của bạn gặp lỗi cú pháp như được thấy dưới đây:

if [ = "valid" ]; then

Sử dụng không đúng tiêu chuẩn của ==nhà điều hành

Lưu ý rằng Bash cho phép ==được sử dụng cho bình đẳng với [, nhưng điều này không phải là tiêu chuẩn .

Sử dụng trường hợp đầu tiên trong đó các trích dẫn xung quanh $xlà tùy chọn:

if [[ "$x" == "valid" ]]; then

hoặc sử dụng trường hợp thứ hai:

if [ "$x" = "valid" ]; then

12
Làm thế nào mà liên quan đến câu trả lời được chấp nhận được đưa ra trong lỗi toán tử không mong đợi ? Tôi đã nhận được cùng một lỗi khi sử dụng [ "$1" == "on" ]. Thay đổi điều này thành ["$ 1" = "on"] đã giải quyết vấn đề.
Piotr Dobrogost

78
Các không gian là cần thiết.
TAAPSogeking

6
@JohnFeminella Khi viết bằng bash script, nó nên có một =và không phải hai.
dùng13107

73
có thể đáng lưu ý rằng bạn không thể sử dụng [ $x -eq "valid" ]. -eqlà toán tử so sánh cho số nguyên, không phải chuỗi.
craq

2
@Alex, Trong trường hợp nào (nếu có) tôi cần sử dụng mẫu ["x$yes" == "xyes"], đó là tiền tố cả biến và chuỗi ký tự bằng một x? Đó có phải là một di tích của thời xưa hay nó thực sự cần thiết trong một số tình huống?
lanoxx

142

Hoặc, nếu bạn không cần mệnh đề khác:

[ "$x" == "valid" ] && echo "x has the value 'valid'"

71
Và nếu bạn cần một mệnh đề khác và muốn tạo một phần tử điên: ["$ x" == "hợp lệ"] && echo "hợp lệ" || tiếng vang "không hợp lệ"
Matt White

11
@MattWhite: đây thường là một ý tưởng tồi, vì echocó thể thất bại.
gniourf_gniourf

1
thậm chí tho gotchas có thể xuất hiện, những cách đẹp và thanh lịch từ cả marko && MattWhite
Deko

3
@gniourf_gniourf, không vấn đề gì, hãy sử dụng [ "$X" == "valid" ] || ( echo invalid && false ) && echo "valid" .
12431234123412341234123

4
@ 12431234123412341234123 { echo invalid && false; }hiệu quả hơn ( echo invalid && false ), vì nó tránh trả tiền cho một subshell không cần thiết.
Charles Duffy

84
a="abc"
b="def"

# Equality Comparison
if [ "$a" == "$b" ]; then
    echo "Strings match"
else
    echo "Strings don't match"
fi

# Lexicographic (greater than, less than) comparison.
if [ "$a" \< "$b" ]; then
    echo "$a is lexicographically smaller then $b"
elif [ "$a" \> "$b" ]; then
    echo "$b is lexicographically smaller than $a"
else
    echo "Strings are equal"
fi

Ghi chú:

  1. Khoảng trống giữa if[]rất quan trọng
  2. ><là các toán tử chuyển hướng để thoát nó với \>\<tương ứng cho các chuỗi.

6
Cảm ơn đã so sánh chuỗi theo thứ tự bảng chữ cái
shadi

Vấn đề của tôi là $athực sự đã " "bao quanh nó như là một phần của giá trị chuỗi ký tự, do đó tôi phải sử dụng ký tự thoát $bđể so sánh các giá trị. Tôi đã có thể tìm thấy điều này sau khi chạy bash -x ./script.sh, cờ -x cho phép bạn xem giá trị của mỗi lần thực hiện và giúp gỡ lỗi.
ShahNewazKhan

Lưu ý rằng so sánh thứ tự chữ cái không được chuẩn hóa POSIX, do đó, nó không được đảm bảo để hoạt động trên các nền tảng không phải là GNU / shell không bash. Chỉ các hoạt động tại pubs.opengroup.org/onlinepub/9699919799/utilities/test.html được đảm bảo có thể mang theo được.
Charles Duffy

62

Để so sánh chuỗi với ký tự đại diện, hãy sử dụng

if [[ "$stringA" == *$stringB* ]]; then
  # Do something here
else
  # Do Something here
fi

12
Điều quan trọng là các ký tự đại diện chỉ có thể được sử dụng ở phía bên phải! Cũng lưu ý thiếu "xung quanh các ký tự đại diện. (btw: +1 cho ký tự đại diện!)
Scz

6
Việc mở rộng $stringB phải được trích dẫn (và, tình cờ, phía bên trái không cần phải trích dẫn) : if [[ $stringA = *"$stringB"* ]]; then.
gniourf_gniourf

tôi đang cố gắng sử dụng logic ký tự đại diện tương tự cho tên tệp trong filepath. Nhưng nó không làm việc cho tôi. đã thử tất cả các chuỗi ký tự đại diện khác nhau được cung cấp ở đây. nhưng nó luôn luôn đi đến trường hợp khác. chuỗiA trong trường hợp của tôi là đường dẫn tệp / tmp / tệp và chuỗiB là "tệp".
mưa

35

Tôi phải không đồng ý một trong những ý kiến ​​trong một điểm:

[ "$x" == "valid" ] && echo "valid" || echo "invalid"

Không, đó không phải là một oneliner điên

Có vẻ như nó giống như một, hmm, người không quen biết ...

Nó sử dụng các mẫu phổ biến như một ngôn ngữ, theo một cách nào đó;

Và sau khi bạn học ngôn ngữ.

Thật ra, thật tuyệt khi đọc

Đó là một biểu thức logic đơn giản, với một phần đặc biệt: đánh giá lười biếng các toán tử logic.

[ "$x" == "valid" ] && echo "valid" || echo "invalid"

Mỗi phần là một biểu thức logic; cái đầu tiên có thể đúng hoặc sai, hai cái còn lại luôn đúng.

(
[ "$x" == "valid" ] 
&&
echo "valid"
)
||
echo "invalid"

Bây giờ, khi nó được đánh giá, đầu tiên được kiểm tra. Nếu nó sai, hơn toán hạng thứ hai của logic && sau nó không liên quan. Điều đầu tiên là không đúng, vì vậy dù sao nó cũng không thể là lần đầu tiên và lần thứ hai là đúng.
Bây giờ, trong trường hợp này là mặt đầu tiên của logic hoặc || sai, nhưng nó có thể đúng nếu mặt kia - phần thứ ba - là đúng.

Vì vậy, phần thứ ba sẽ được đánh giá - chủ yếu là viết thông điệp như một tác dụng phụ. (Nó có kết quả0 đúng, mà chúng tôi không sử dụng ở đây)

Các trường hợp khác tương tự, nhưng đơn giản hơn - và - tôi hứa! là - có thể - dễ đọc!
(Tôi không có ai, nhưng tôi nghĩ việc trở thành cựu chiến binh UNIX với bộ râu xám sẽ giúp ích rất nhiều cho việc này.)


17
Điều ... && ... || ...này thường cau mày (xin lỗi cựu chiến binh Unix, bạn đã sai trong suốt thời gian này), vì nó không tương đương về mặt ngữ nghĩa if ... then ... else .... Đừng lo lắng, đây là một cạm bẫy phổ biến .
gniourf_gniourf

6
@gniourf_gniourf OP không sai-- cũng không có khả năng họ không biết gì như bạn đề xuất. ... && ... || ...là một mẫu hoàn toàn hợp lệ và một thành ngữ bash phổ biến. Việc sử dụng nó quy định kiến ​​thức trước đó (có thể là điều tốt để ghi nhớ nếu có người mới bắt đầu), nhưng OP có mái tóc để chứng minh rằng họ biết cách tránh nắp hố ga mở.
ebpa

3
@ebpa Điều gì xảy ra nếu câu lệnh sau && trả về giá trị false, sẽ thực thi tiến hành câu lệnh tot he sau | | ? Nếu đó là sai và có lẽ đó là những gì gniourf đang đề xuất
TSG

4
Tôi nghĩ rằng echo chỉ là một ví dụ. Câu lệnh sau && vẫn có thể trả về giá trị khác không
TSG

2
@gniourf_gniourf +1 để đăng liên kết tới Bash Cạm bẫy! Rất hữu ích!
Jaguar

21

bạn cũng có thể sử dụng case / esac

case "$string" in
 "$pattern" ) echo "found";;
esac

Đây là tương đương hoặc có chứa?
ytpillai

@ytpillai, nó là tương đương. Hãy nhớ rằng bạn có thể có các mẫu được phân tách bằng |, trước ). Các intuyên bố là tương đương với thentrong ifbáo cáo. Bạn có thể lập luận rằng nó hoạt động trên một danh sách các mẫu, trong đó mỗi danh sách có tuyên bố riêng về những việc cần làm, nếu bạn đến từ Python. Không thích substring in string, nhưng đúng hơn for item in list. Sử dụng *như là tuyên bố cuối cùng của bạn nếu bạn muốn một elseđiều kiện. Nó trở lại trong lần gặp đầu tiên.
mazunki

18

Kịch bản sau đây đọc từ một tệp có tên "testonthis" theo từng dòng và sau đó so sánh mỗi dòng với một chuỗi đơn giản, một chuỗi với các ký tự đặc biệt và một biểu thức chính quy. Nếu nó không khớp, thì tập lệnh sẽ in dòng, nếu không thì không.

Không gian trong Bash rất quan trọng. Vì vậy, sau đây sẽ làm việc:

[ "$LINE" != "table_name" ] 

Nhưng sau đây sẽ không:

["$LINE" != "table_name"] 

Vì vậy, vui lòng sử dụng như là:

cat testonthis | while read LINE
do
if [ "$LINE" != "table_name" ] && [ "$LINE" != "--------------------------------" ] && [[ "$LINE" =~ [^[:space:]] ]] && [[ "$LINE" != SQL* ]]; then
echo $LINE
fi
done

Sử dụng phương pháp này để đi qua một tập tin. Đó là, loại bỏ UUoC trong số những thứ khác.
fedorqui 'SO ngừng làm hại'

Nó không quan trọng vì bashnhưng [thực ra là một nhị phân bên ngoài (như which [mang lại kết quả tương tự /usr/bin/[)
Patrick Bergner

11

Tôi có thể sẽ sử dụng kết hợp regex nếu đầu vào chỉ có một vài mục hợp lệ. Ví dụ: chỉ "bắt đầu" và "dừng" là hành động hợp lệ.

if [[ "${ACTION,,}" =~ ^(start|stop)$ ]]; then
  echo "valid action"
fi

Lưu ý rằng tôi viết thường biến $ACTIONbằng cách sử dụng dấu phẩy kép. Cũng lưu ý rằng điều này sẽ không hoạt động trên các phiên bản bash quá cũ ngoài kia.


9

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ụ trong 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

Thưởng thức.


đối với tôi (mac GNU bash phiên bản 4.4.12 (1) -release x86_64-apple-darwin17.0.0), tôi phải sử dụng if [ "$a"="$b" ]hoặc nó không hoạt động ... không thể có khoảng trắng xung quanh bằng
phổ

1

Tôi đã làm nó theo cách tương thích với Bash và Dash (sh):

testOutput="my test"
pattern="my"

case $testOutput in (*"$pattern"*)
    echo "if there is a match"
    exit 1
    ;;
(*)
   ! echo there is no coincidence!
;;esac

sự khác biệt giữa việc sử dụng trước (và không sử dụng nó là gì?
mazunki
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.