Pencarian substring case-insensitive dalam skrip shell [ditutup]

22

Bagaimana saya bisa menulis skrip shell yang akan melakukan kecocokan substring case-output output perintah?

Miguel Roque
sumber
grep -imungkin?
Ramesh
Bagaimana saya memasukkannya ke dalam skrip saya? Maaf jika ini pertanyaan pemula. Saya baru mulai belajar Linux karena saya membutuhkannya untuk magang. Terima kasih!
Miguel Roque
1
Yang Anda tanyakan adalah shell scripting - "linux" bukan bahasa pemrograman, ini adalah kernel sistem operasi. Shell yang paling umum digunakan dengan linux adalah bash, yang merupakan superset dari standar unixsh . Anda mungkin mulai dengan melihat salah satu dari ini: | 1 | | 2 | - hanya untuk memahami konteks sebenarnya.
goldilocks
1
Pertanyaan ini sekarang tampaknya cukup jelas dan cocok dengan pedoman di pusat bantuan. Bisakah itu dibuka untuk kepentingan orang lain?
BobDoolittle
2
Saya tidak melihat masalah mengapa pertanyaan ini tidak jelas. Apa yang harus saya tambahkan agar jelas?
Miguel Roque

Jawaban:

11

Pertama, inilah contoh skrip sederhana yang tidak mengabaikan kasus:

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

Coba ubah string halo di sebelah kanan, dan seharusnya tidak lagi bergema it works. Coba ganti echo hellodengan perintah yang Anda pilih. Jika Anda ingin mengabaikan case, dan tidak ada string yang berisi satu baris pun, maka Anda bisa menggunakan grep:

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

Kuncinya di sini adalah bahwa Anda mengirim output perintah grep. The ifpernyataan menguji status keluar dari perintah paling kanan dalam pipa - dalam hal ini grep. Grep keluar dengan sukses jika dan hanya jika ia menemukan kecocokan.

The -ipilihan untuk grep mengatakan untuk mengabaikan kasus.
The -qpilihan mengatakan untuk tidak memancarkan dan keluar setelah pertandingan pertama.
The -Fpilihan kata untuk mengobati argumen sebagai string daripada ekspresi reguler.

Perhatikan bahwa contoh pertama menggunakan yang memungkinkan perbandingan langsung dan berbagai operator yang bermanfaat. Bentuk kedua hanya mengeksekusi perintah dan menguji status keluar mereka.[ expression ]

BobDoolittle
sumber
Saya tidak mengerti mengapa Gilles merasa perlu untuk mengubah kode yang saya sumbangkan. Dia tidak merusak apa pun, tapi itu berhasil. Anda tidak perlu tanda kutip ganda dalam contoh ini - mereka penting jika output mengandung spasi. Dan == bekerja sama baiknya dengan = karena sh sebenarnya bash di Linux. Bourne Shell yang asli sudah lama hilang pada saat ini. Saya bahkan tidak berpikir Solaris mengirimkannya lagi. Meskipun tidak perlu dalam contoh ini, saya setuju bahwa tanda kutip ganda mungkin merupakan praktik terbaik, tetapi demikian juga '==' menurut pendapat saya, untuk memisahkan tugas dan perbandingan.
BobDoolittle
Tunggu, jadi orang dapat mengedit posting? Saya tidak tahu hal itu.
Miguel Roque
Dengan reputasi yang cukup, ya. Saya berharap seseorang dengan reputasi tinggi akan berpikir dua kali sebelum melakukan pengeditan yang tidak perlu, terutama untuk kode di forum ini. unix.stackexchange.com/help/privileges
BobDoolittle
@ BobDoolittle Mungkin dalam kasus-kasus tertentu itu membuat perbedaan tetapi tidak dengan pengaturan Anda - itu baik untuk diketahui.
2
Perhatikan bahwa dalam praktiknya, ini bukan hanya tentang kulit Bourne. ==bukan POSIX. shtidak bashpada semua sistem berbasis Linux. ==tidak didukung oleh ash(yang menjadi dasar shdari banyaknya BSD dan turunan Debian setidaknya), atau posh, dan kebutuhan dikutip dalam zsh. Tidak ada gunanya menggandakan =. [adalah perintah untuk pengujian. Tidak perlu membingungkan antara tugas dan perbandingan di sini. Itu berbeda dalam (( a == b ))vs (( a = b)). Menggunakan ==skrip yang dimulai dengan #! /bin/shsalah. Jika Anda menganggap kshatau bashsintaksis, perbarui #!sesuai.
Stéphane Chazelas
49

Anda dapat melakukan pencocokan substrat case-insensitive dengan asli dalam bashmenggunakan operator regex =~jika Anda mengatur nocasematchopsi shell. Sebagai contoh

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
Steeldriver
sumber
6
lol! poin untuk pengetahuan shell yang tidak jelas.
BobDoolittle
2
Opsi ini juga memengaruhi operator pertandingan sederhana. [[ XYZ == xyz ]] && echo "match"=>match
itsadok
7

Untuk pencarian string case-sensitive dari nilai variabel needledalam nilai variabel haystack:

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

Untuk pencarian string yang tidak memiliki case-case, konversikan keduanya menjadi case yang sama.

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

Perhatikan bahwa trdalam coreutils GNU tidak mendukung lokal multibyte (misalnya UTF-8). Untuk bekerja dengan multibyte lokal, gunakan awk sebagai gantinya. Jika Anda akan menggunakan awk, Anda dapat membuatnya melakukan perbandingan string dan bukan hanya konversi.

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

The trdari BusyBox tidak mendukung sintaks; Anda bisa menggunakannya . BusyBox tidak mendukung lokal non-ASCII.[:CLASS:]tr a-z A-Z

Di bash (tetapi bukan sh), versi 4.0+, ada sintaks bawaan untuk konversi kasus, dan sintaksis lebih sederhana untuk pencocokan string.

if [[ "${haystack^^}" = *"${needle^^}"* ]]; then
  echo "present"
else
  echo "absent"
esac
Gilles 'SANGAT berhenti menjadi jahat'
sumber
Saya menyadari ini berumur beberapa tahun, tetapi semua itu printf | trmembuat kepala saya berputar. Jika memungkinkan, pertahankan perintah Anda seminimal mungkin ... dengan variabel v, Anda dapat menggunakan hal yang sama v=$(tr '[:lower:]' '[:upper:]' <<<$v). Bagi mereka yang belum pernah melihatnya sebelumnya, <<<ini pada dasarnya adalah "variabel di sini" seperti penggunaan <<EOFadalah untuk dokumen di sini. Jangan printfatau echokecuali Anda benar-benar harus melakukannya.
Will
@ Akankah itu hanya bekerja di shell yang memiliki <<<operator: ksh, bash, zsh, tetapi tidak sh polos. Dan itu cukup dekat dengan pemipaan printfdalam hal cara kerjanya: ada jumlah panggilan yang sama ke forkdan execve(dengan asumsi itu printfadalah built-in, yang merupakan kasus pada shell paling umum); perbedaannya adalah yang <<<membuat file sementara daripada menggunakan pipa. <<<nyaman untuk mengetik tetapi bukan peningkatan kinerja.
Gilles 'SO- stop being evil'