web-dev-qa-db-ja.com

シェルスクリプトでの大文字と小文字を区別しない部分文字列検索

コマンド出力の大文字と小文字を区別しない部分文字列の一致を行うシェルスクリプトを作成するにはどうすればよいですか?

22
Miguel Roque

最初に、大文字と小文字を区別しない簡単なスクリプト例を示します。

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

右側の文字列helloを変更すると、it worksがエコーされなくなります。 echo helloを任意のコマンドに置き換えてみてください。大文字と小文字を無視したい場合で、どちらの文字列にも改行が含まれていない場合は、grepを使用できます。

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

ここで重要なのは、コマンド出力をgrepにパイプ処理していることです。 ifステートメントは、パイプラインの右端のコマンド(この場合はgrep)の終了ステータスをテストします。一致が見つかった場合にのみ、grepは成功して終了します。

Grepの-iオプションは、大文字と小文字を区別しないと言っています。
-qオプションは、最初の一致後に出力を発行せずに終了することを示しています。
-Fオプションは、引数を正規表現ではなく文字列として扱うことを示しています。

最初の例では[ expression ]を使用しているため、直接比較やさまざまな便利な演算子を使用できます。 2番目の形式は、コマンドを実行し、その終了ステータスをテストするだけです。

12
BobDoolittle

bashシェルオプションを設定すると、正規表現演算子=~を使用して、nocasematchで大文字と小文字を区別しない部分文字列マッチングをネイティブに実行できます。例えば

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
49
steeldriver

変数needleの値で変数haystackの値の大文字と小文字を区別する文字列検索の場合:

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

大文字と小文字を区別しない文字列検索の場合、両方を同じ大文字と小文字に変換します。

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

GNU coreutilsのtrはマルチバイトロケール(UTF-8など)をサポートしていません。マルチバイトロケールを使用するには、代わりにawkを使用してください。 awkを使用するには、変換だけでなく文字列比較を行うようにすることができます。

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

BusyBoxのtr[:CLASS:]構文をサポートしていません。代わりにtr a-z A-Zを使用できます。 BusyBoxは非ASCIIロケールをサポートしていません。

Bash(shではない)バージョン4.0以降では、大文字と小文字を変換するための組み込みの構文と、文字列照合のためのより単純な構文があります。

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