Tìm kiếm chuỗi con không phân biệt chữ hoa chữ thường trong tập lệnh shell [đã đóng]


22

Làm thế nào tôi có thể viết một tập lệnh shell sẽ thực hiện khớp chuỗi con không phân biệt chữ hoa chữ thường của đầu ra lệnh?


grep -icó lẽ?
Ramesh

Làm thế nào tôi sẽ đặt nó trong kịch bản của tôi? Tôi xin lỗi nếu đây là một câu hỏi mới. Tôi mới bắt đầu học Linux vì tôi cần nó cho kỳ thực tập của mình. Cảm ơn!
Miguel Roque

1
Những gì bạn đang hỏi là kịch bản shell - "linux" không phải là ngôn ngữ lập trình, nó là hạt nhân của hệ điều hành. Shell thường được sử dụng nhất với linux là bashsiêu lớp của tiêu chuẩn unixsh . Bạn có thể bắt đầu bằng cách nhìn vào một trong những điều sau: | 1 | | 2 | - chỉ để hiểu được bối cảnh thực tế là gì.
goldilocks

1
Câu hỏi này bây giờ có vẻ khá rõ ràng và phù hợp với các hướng dẫn trong trung tâm trợ giúp. Nó có thể được mở vì lợi ích của người khác?
BobDoolittle

2
Tôi không thấy fuzz tại sao câu hỏi này không rõ ràng. Tôi nên thêm gì cho nó rõ ràng?
Miguel Roque

Câu trả lời:


11

Đầu tiên, đây là một kịch bản ví dụ đơn giản không bỏ qua trường hợp:

#!/bin/bash
if [ $(echo hello) == hello ]; then
    echo it works
fi

Hãy thử thay đổi chuỗi xin chào ở bên phải và nó sẽ không còn lặp lại it works. Hãy thử thay thế echo hellobằng một lệnh bạn chọn. Nếu bạn muốn bỏ qua trường hợp và không chuỗi nào chứa ngắt dòng, thì bạn có thể sử dụng grep:

#!/bin/bash
if echo Hello | grep -iqF hello; then
    echo it works
fi

Chìa khóa ở đây là bạn đang dẫn một đầu ra lệnh tới grep. Câu iflệnh kiểm tra trạng thái thoát của lệnh ngoài cùng bên phải trong đường ống - trong trường hợp này là grep. Grep thoát ra với thành công khi và chỉ khi nó tìm thấy một trận đấu.

Các -itùy chọn của grep nói để bỏ qua vụ việc.
Các -qtùy chọn nói đến không phát ra bản_ rồi thoát sau khi trận đấu đầu tiên.
Các -Ftùy chọn cho biết để điều trị các tham số như là một chuỗi chứ không phải là một biểu thức chính quy.

Lưu ý rằng ví dụ đầu tiên sử dụng cho phép so sánh trực tiếp và các toán tử hữu ích khác nhau. Biểu mẫu thứ hai chỉ thực hiện các lệnh và kiểm tra trạng thái thoát của chúng.[ expression ]


Tôi không hiểu tại sao Gilles cảm thấy cần phải thay đổi mã tôi đã đóng góp. Anh ta đã không phá vỡ bất cứ điều gì nhưng nó hoạt động tốt. Bạn không cần dấu ngoặc kép trong ví dụ này - chúng rất quan trọng nếu đầu ra chứa khoảng trắng. Và == hoạt động tốt như = vì sh thực sự là bash trên Linux. Bourne Shell ban đầu đã mất từ ​​lâu tại thời điểm này. Tôi không nghĩ ngay cả Solaris cũng vận chuyển nó nữa. Mặc dù không cần thiết trong ví dụ này, tôi đồng ý rằng trích dẫn kép có thể là một cách thực hành tốt nhất, nhưng theo tôi thì '==', để giữ sự phân công và so sánh rõ ràng.
BobDoolittle

Chờ đã, vậy người ta có thể chỉnh sửa một bài không? Tôi không biết điều đó.
Miguel Roque

Với danh tiếng đầy đủ, có. Tuy nhiên, tôi hy vọng ai đó có uy tín cao sẽ suy nghĩ kỹ trước khi thực hiện các chỉnh sửa không cần thiết, đặc biệt là viết mã trong diễn đàn này. unix.stackexchange.com/help/priv đặc quyền
BobDoolittle

@BobDoolittle Có thể trong một số trường hợp, nó tạo ra sự khác biệt nhưng không phải với thiết lập của bạn - thật tốt khi biết điều đó.

2
Lưu ý rằng trong thực tế, không chỉ về vỏ Bourne. ==không phải là POSIX. shkhông phải bashtrên tất cả các hệ thống dựa trên Linux. ==không được hỗ trợ bởi ash( shít nhất là dựa trên nhiều dẫn xuất BSD và Debian), hoặc posh, và nhu cầu được trích dẫn zsh. Không có điểm nào nhân đôi =. [là một lệnh để thử nghiệm. Không cần phân biệt giữa chuyển nhượng và so sánh ở đây. Đó là khác nhau trong (( a == b ))vs (( a = b)). Sử dụng ==trong một kịch bản bắt đầu với #! /bin/shlà sai. Nếu bạn giả định kshhoặc bashcú pháp, cập nhật cho #!phù hợp.
Stéphane Chazelas

49

Bạn có thể thực hiện khớp chuỗi con không phân biệt chữ hoa chữ thường bashbằng cách sử dụng toán tử regex =~nếu bạn đặt nocasematchtùy chọn shell. Ví dụ

s1="hElLo WoRlD"
s2="LO"

shopt -s nocasematch

[[ $s1 =~ $s2 ]] && echo "match" || echo "no match"
match

s1="gOoDbYe WoRlD"
[[ $s1 =~ $s2 ]] && echo "match" || echo "no match"
no match

6
haha điểm cho kiến ​​thức vỏ tối nghĩa.
BobDoolittle

2
Tùy chọn này cũng ảnh hưởng đến toán tử khớp đơn giản. [[ XYZ == xyz ]] && echo "match"=>match
itadok

7

Đối với tìm kiếm chuỗi phân biệt chữ hoa chữ thường của giá trị của biến needletrong giá trị của biến haystack:

case "$haystack" in
  *"$needle"*) echo "present";
  *) echo "absent";
esac

Đối với tìm kiếm chuỗi không phân biệt chữ hoa chữ thường, chuyển đổi cả hai sang cùng một trường hợp.

uc_needle=$(printf %s "$needle" | tr '[:lower:]' '[:upper:]' ; echo .); uc_needle=${uc_needle%.}
uc_haystack=$(printf %s "$haystack" | tr '[:lower:]' '[:upper:]' ; echo .); uc_haystack=${uc_haystack%.}
case "$uc_haystack" in
  *"$uc_needle"*) echo "present";;
  *) echo "absent";;
esac

Lưu ý rằng các trlõi trong GNU không hỗ trợ các địa điểm đa bào (ví dụ UTF-8). Để thực hiện công việc với các địa phương multibyte, sử dụng awk thay thế. Nếu bạn sẽ sử dụng awk, bạn có thể làm cho nó thực hiện so sánh chuỗi chứ không chỉ là chuyển đổi.

if awk 'BEGIN {exit !index(toupper(ARGV[2]), toupper(ARGV[1]))}' "$needle" "$haystack"; then
  echo "present"
else
  echo "absent"
fi

Các trtừ BusyBox không hỗ trợ cú pháp; bạn có thể sử dụng thay thế. BusyBox không hỗ trợ các ngôn ngữ không phải ASCII.[:CLASS:]tr a-z A-Z

Trong bash (nhưng không phải sh), phiên bản 4.0+, có một cú pháp tích hợp để chuyển đổi trường hợp và một cú pháp đơn giản hơn để khớp chuỗi.

if [[ "${haystack^^}" = *"${needle^^}"* ]]; then
  echo "present"
else
  echo "absent"
esac

Tôi nhận ra đây là một cặp vợ chồng, nhưng tất cả những điều đó printf | trlàm cho đầu óc tôi quay cuồng. Nếu có thể, hãy giữ lệnh gọi của bạn ở mức tối thiểu ... với một biến v, bạn có thể thực hiện điều tương tự bằng cách sử dụng v=$(tr '[:lower:]' '[:upper:]' <<<$v). Đối với những người chưa bao giờ nhìn thấy nó trước đây, về <<<cơ bản là "biến ở đây" giống như việc sử dụng <<EOFlà cho một tài liệu ở đây. Đừng printfhoặc echotrừ khi bạn hoàn toàn phải làm như vậy.
Sẽ

@Will Điều đó chỉ hoạt động trong các shell có <<<toán tử: ksh, bash, zsh, nhưng không phải sh đơn giản. Và nó khá gần với đường ống từ printfcách nó chạy: có cùng số lượng cuộc gọi đến forkexecve(giả sử đó printflà tích hợp, đó là trường hợp trên hầu hết các shell phổ biến); một sự khác biệt là <<<tạo ra một tập tin tạm thời thay vì sử dụng một đường ống. <<<là thuận tiện để gõ nhưng không phải là một cải tiến hiệu suất.
Gilles 'SO- ngừng trở nên xấu xa'
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.