Trường hợp so sánh không nhạy cảm của chuỗi trong shell script


129

Các ==nhà điều hành được sử dụng để so sánh hai chuỗi trong shell script. Tuy nhiên, tôi muốn so sánh hai chuỗi bỏ qua trường hợp, làm thế nào nó có thể được thực hiện? Có bất kỳ lệnh tiêu chuẩn cho điều này?

Câu trả lời:


72

nếu bạn có bash

str1="MATCH"
str2="match"
shopt -s nocasematch
case "$str1" in
 $str2 ) echo "match";;
 *) echo "no match";;
esac

nếu không, bạn nên cho chúng tôi biết bạn đang sử dụng loại vỏ nào.

thay thế, sử dụng awk

str1="MATCH"
str2="match"
awk -vs1="$str1" -vs2="$str2" 'BEGIN {
  if ( tolower(s1) == tolower(s2) ){
    print "match"
  }
}'

32
Đối với bất kỳ ai so sánh các chuỗi bằng cách sử dụng các ifcâu lệnh, shoptcách tiếp cận yêu cầu bạn sử dụng dạng hai khung [[ ]]có điều kiện thay vì dạng dấu ngoặc [ ]đơn. Xem thêm: gnu.org/software/bash/manual/html_node/The-Shopt-Builtin.html
C.nhân

3
Câu hỏi chỉ ra rằng ==được sử dụng để so sánh hai chuỗi, nhưng câu trả lời thể hiện so sánh không phân biệt chữ hoa chữ thường bằng cách sử dụng một casecâu lệnh. Trấn an, các shoptgiải pháp cũng cho phép sử dụng case-insensitive của ==, =~và các nhà khai thác chuỗi so sánh khác.
taranaki

7
Có lẽ là khôn ngoan để thực hiện shopt -u nocasematchsau khi so sánh được thực hiện để trở lại mặc định của bash.
Ohad Schneider

6
Tốt nhất để lưu và khôi phục nocasematchcài đặt. Lấy nó SHELLNOCASEMATCH=`shopt -p nocasematch`sau đó thay đổi nó shopt -s nocasematchvà sau khi thực hiện xong, khôi phục nó bằng$SHELLNOCASEMATCH
Urhixidur

2
Vẫn tốt hơn : SHELLNOCASEMATCH=$(shopt -p nocasematch; true), vì shopt -psẽ thoát với mã 1 nếu tùy chọn không được đặt và điều này có thể khiến tập lệnh hủy bỏ nếu set -ecó hiệu lực.
Chúng tôi là tất cả Monica

158

Trong Bash, bạn có thể sử dụng mở rộng tham số để sửa đổi một chuỗi thành tất cả chữ thường / chữ hoa:

var1=TesT
var2=tEst

echo ${var1,,} ${var2,,}
echo ${var1^^} ${var2^^}

14
Ít nhất là một câu trả lời không ngụ ý tùy chọn shopt. Vì vậy, bạn có thể so sánh hai trường hợp bỏ qua chuỗi và trong cùng một bài kiểm tra, so sánh hai trường hợp khác với trường hợp. Cảm ơn
jehon

37
Đây có phải là mới trong Bash 4? Ít nhất là trong Bash 3.2.51 (được sử dụng trong OS X 10.9), nó không hoạt động - echocâu lệnh đầu tiên dẫn đến:-bash: ${var1,,}: bad substitution
Felix Rabe

1
Việc triển khai so sánh không phân biệt chữ hoa như vậy dễ xảy ra các vấn đề nội địa hóa (như vấn đề I của Thổ Nhĩ Kỳ). Tôi không biết cách shopt -s nocasematchtriển khai nhưng thông thường các giải pháp "cấp độ ngôn ngữ" đó xử lý chính xác.
Ohad Schneider

5
@Ohad Schneider, hãy để người Thổ Nhĩ Kỳ lo lắng về các vấn đề nội địa hóa của Thổ Nhĩ Kỳ, tôi chỉ cần một cách nhanh chóng và hiệu quả để kết hợp chuỗi và điều này sẽ lấy bánh bằng lề huuuuuge
niken

1
Người dùng macOS, nâng cấp phiên bản Bash của bạn. Đến thời điểm này, bạn đã hơn một thập kỷ. itnext.io/upgrad-bash-on-macos-7138bd1066ba
Jason Carter

114

Tất cả những câu trả lời này đều bỏ qua cách dễ nhất và nhanh nhất để làm điều này (miễn là bạn có Bash 4):

if [ "${var1,,}" = "${var2,,}" ]; then
  echo ":)"
fi

Tất cả những gì bạn đang làm ở đó là chuyển đổi cả hai chuỗi thành chữ thường và so sánh kết quả.


6
Điều này chỉ khả dụng trong Bash 4 hoặc mới hơn (ví dụ: không có trên Mac OS X 10.11)
d4Rk

8
@ d4Rk đó là lý do tại sao câu đầu tiên trong câu trả lời của tôi nói "miễn là bạn có Bash 4". Phải nói rằng, Bash 4 đã ra mắt được hơn bảy năm tại thời điểm viết bình luận này và bản cài đặt OS X của riêng tôi đã có nó trong gần như vậy.
Bạo loạn

@Riot xin lỗi, đã không nhận thấy rằng ở nơi đầu tiên. Tôi biết bạn có thể cài đặt bất cứ thứ gì bạn muốn trên OS X, nhưng mặc định là 3.2 và vì tập lệnh của tôi cũng phải chạy trên các máy Mac khác nhau, đây thực sự không phải là một lựa chọn cho tôi.
d4Rk

2
@ d4Rk điều đó có thể hiểu được - nếu bạn thực sự cần đảm bảo tính di động, tôi sẽ khuyên bạn nên tuân thủ tiêu chuẩn vỏ POSIX, vì trong một số trường hợp, bạn không được đảm bảo tìm thấy bất kỳ phiên bản bash nào.
Bạo loạn

1
Điều này thật đúng với gì mà tôi đã tìm kiếm. Nên cao hơn =)
Robin Winslow

39

Lưu trạng thái của nocasematch (trong trường hợp một số chức năng khác phụ thuộc vào chức năng này bị vô hiệu hóa):

local orig_nocasematch=$(shopt -p nocasematch)
shopt -s nocasematch
[[ "foo" == "Foo" ]] && echo "match" || echo "notmatch"
$orig_nocasematch

Lưu ý: chỉ sử dụng localnếu nó nằm trong hàm.


4
Rất vui vì những casephát biểu (bao gồm cả những câu trả lời của ghostdog) sẽ luôn khiến da tôi bò lên
SeldomNeedy

15

Một cách sẽ là chuyển đổi cả hai chuỗi thành trên hoặc dưới:

test $(echo "string" | /bin/tr '[:upper:]' '[:lower:]') = $(echo "String" | /bin/tr '[:upper:]' '[:lower:]') && echo same || echo different

Một cách khác là sử dụng grep:

echo "string" | grep -qi '^String$' && echo same || echo different

Tôi đã sử dụng trphương thức này trong các ứng dụng đóng băng của mình dựa trên alpine (cung cấp shthông qua busybox). Cảm ơn bạn.
MXWest

7

Đối với shell korn, tôi sử dụng lệnh tích hợp sắp chữ (-l cho chữ thường và -u cho chữ hoa).

var=True
typeset -l var
if [[ $var == "true" ]]; then
    print "match"
fi

2
Đây là cách tốt hơn, về mặt hiệu suất so với bắt đầu awk hoặc bất kỳ quá trình nào khác.
Alex

1
Trong bash, khai báo -l hoặc -u có thể được sử dụng để đặt các thuộc tính.
Bharat

5

Rất dễ dàng nếu bạn fgrep thực hiện so sánh dòng không phân biệt chữ hoa chữ thường:

str1="MATCH"
str2="match"

if [[ $(fgrep -ix $str1 <<< $str2) ]]; then
    echo "case-insensitive match";
fi

Nó sẽ tốt hơn để sử dụng if fgrep -qix -- "$str1" <<<"$str2"; thenthay thế.

3

Đây là giải pháp của tôi bằng cách sử dụng tr:

var1=match
var2=MATCH
var1=`echo $var1 | tr '[A-Z]' '[a-z]'`
var2=`echo $var2 | tr '[A-Z]' '[a-z]'`
if [ "$var1" = "$var2" ] ; then
  echo "MATCH"
fi

3

grepcó một -icờ có nghĩa là trường hợp không nhạy cảm, vì vậy hãy yêu cầu nó cho bạn biết nếu var2 nằm trong var1.

var1=match 
var2=MATCH 
if echo $var1 | grep -i "^${var2}$" > /dev/null ; then
    echo "MATCH"
fi

3
sẽ không hoạt động nếu có bất kỳ ký tự đặc biệt regex nào trong var2.
haridsv

3

Đối với zshcú pháp hơi khác nhau, nhưng vẫn ngắn hơn hầu hết các câu trả lời ở đây:

> str1='mAtCh'
> str2='MaTcH'
> [[ "$str1:u" = "$str2:u" ]] && echo 'Strings Match!'
Strings Match!
>

Điều này sẽ chuyển đổi cả hai chuỗi thành chữ hoa trước khi so sánh.


Một phương pháp khác sử dụng zsh globbing flags, cho phép chúng tôi trực tiếp sử dụng kết hợp không phân biệt chữ hoa chữ thường bằng cách sử dụng icờ toàn cầu:

setopt extendedglob
[[ $str1 = (#i)$str2 ]] && echo "Match success"
[[ $str1 = (#i)match ]] && echo "Match success"


1

Tôi đã xem qua blog / hướng dẫn tuyệt vời này / bất cứ điều gì về việc xử lý mô hình phân biệt chữ hoa chữ thường . Ba phương pháp sau đây được giải thích chi tiết với các ví dụ:

1. Chuyển đổi mẫu thành chữ thường bằng lệnh tr

opt=$( tr '[:upper:]' '[:lower:]' <<<"$1" )
case $opt in
        sql)
                echo "Running mysql backup using mysqldump tool..."
                ;;
        sync)
                echo "Running backup using rsync tool..."
                ;;
        tar)
                echo "Running tape backup using tar tool..."
                ;;
        *)
                echo "Other options"
                ;;
esac

2. Sử dụng regex với các mẫu trường hợp

opt=$1
case $opt in
        [Ss][Qq][Ll])
                echo "Running mysql backup using mysqldump tool..."
                ;;
        [Ss][Yy][Nn][Cc])
                echo "Running backup using rsync tool..."
                ;;
        [Tt][Aa][Rr])
                echo "Running tape backup using tar tool..."
                ;;
        *)
                echo "Other option"
                ;;
esac

3. Bật nocasematch

opt=$1
shopt -s nocasematch
case $opt in
        sql)
                echo "Running mysql backup using mysqldump tool..."
                ;;
        sync)
                echo "Running backup using rsync tool..."
                ;;
        tar)
                echo "Running tape backup using tar tool..."
                ;;
        *)
                echo "Other option"
                ;;
esac

shopt -u nocasematch
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.