Groß- und Kleinschreibung wird beim Vergleich von Zeichenfolgen im Shell-Skript nicht berücksichtigt

129

Der ==Operator wird verwendet, um zwei Zeichenfolgen im Shell-Skript zu vergleichen. Ich möchte jedoch zwei Zeichenfolgen vergleichen, wobei Groß- und Kleinschreibung ignoriert wird. Wie kann das gemacht werden? Gibt es dafür einen Standardbefehl?

Sachin Chourasiya
quelle

Antworten:

72

wenn du bash hast

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

Andernfalls sollten Sie uns mitteilen, welche Shell Sie verwenden.

alternativ mit awk

str1="MATCH"
str2="match"
awk -vs1="$str1" -vs2="$str2" 'BEGIN {
  if ( tolower(s1) == tolower(s2) ){
    print "match"
  }
}'
Ghostdog74
quelle
32
Für alle, die Strings mit vergleichen if Anweisungen vergleicht, shoptmüssen Sie bei diesem Ansatz die Doppelklammerform [[ ]]der Bedingung anstelle der Einzelklammerform verwenden [ ]. Siehe auch: gnu.org/software/bash/manual/html_node/The-Shopt-Builtin.html
indiv
3
Die Frage gibt an, dass ==zum Vergleichen von zwei Zeichenfolgen verwendet wird. Die Antwort zeigt jedoch einen Vergleich ohne Berücksichtigung der Groß- und Kleinschreibungcase Anweisung. Beruhigend, das shoptermöglicht Lösung auch Groß- und Kleinschreibung Verwendung ==, =~und andere String - Vergleichsoperator.
Taranaki
7
Wahrscheinlich klug auszuführen shopt -u nocasematch nach Abschluss des Vergleichs um zur Standardeinstellung von bash zurückzukehren.
Ohad Schneider
6
Am besten speichern und wiederherstellen nocasematch. Schnapp es SHELLNOCASEMATCH=`shopt -p nocasematch`shopt -s nocasematch$SHELLNOCASEMATCH
dir
2
Besser noch : SHELLNOCASEMATCH=$(shopt -p nocasematch; true), weil shopt -pmit Code 1 beendet wird, wenn die Option nicht gesetzt ist, und dies kann dazu führen, dass das Skript abgebrochen wird, wenn set -ees in Kraft ist.
Wir sind alle Monica
158

In Bash können Sie die Parametererweiterung verwenden, um eine Zeichenfolge in Groß- / Kleinbuchstaben zu ändern:

var1=TesT
var2=tEst

echo ${var1,,} ${var2,,}
echo ${var1^^} ${var2^^}
Alphaniner
quelle
14
Zumindest eine Antwort, die nicht die Option shopt impliziert. Sie können also zwei Zeichenfolgen ignorieren, die Groß- und Kleinschreibung ignorieren, und im selben Test zwei andere mit Groß- und Kleinschreibung vergleichen. Danke
Jehon
37
Ist das neu in Bash 4? Zumindest in Bash 3.2.51 (verwendet in OS X 10.9) funktioniert es nicht - die erste echoAussage führt zu:-bash: ${var1,,}: bad substitution
Felix Rabe
1
Solche Vergleichsimplementierungen ohne Berücksichtigung der Groß- und Kleinschreibung sind anfällig für Lokalisierungsprobleme (wie das türkische I-Problem). Ich weiß nicht, wie shopt -s nocasematches implementiert wird, aber normalerweise behandeln solche Lösungen auf "Sprachebene" es richtig.
Ohad Schneider
5
@Ohad Schneider, lassen Sie die Türken sich über türkische Lokalisierungsprobleme Sorgen machen, ich brauche nur einen schnellen und effizienten Weg, um das Match zu bespannen, und dies bringt den Kuchen mit großem Vorsprung
niken
1
MacOS-Benutzer, aktualisieren Sie Ihre Bash-Version. Ihre ist zu diesem Zeitpunkt über ein Jahrzehnt veraltet. itnext.io/upgrading-bash-on-macos-7138bd1066ba
Jason Carter
112

Alle diese Antworten ignorieren den einfachsten und schnellsten Weg, dies zu tun (solange Sie Bash 4 haben):

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

Alles, was Sie dort tun, ist, beide Zeichenfolgen in Kleinbuchstaben umzuwandeln und die Ergebnisse zu vergleichen.

Randalieren
quelle
6
Dies ist nur in Bash 4 oder neuer verfügbar (z. B. nicht unter Mac OS X 10.11)
d4Rk
8
@ d4Rk, weshalb der erste Satz meiner Antwort sagt "solange du Bash 4 hast". Allerdings war Bash 4 zum Zeitpunkt des Schreibens dieses Kommentars seit über sieben Jahren nicht mehr verfügbar, und meine eigene OS X-Installation hatte es fast so lange.
Aufstand
@Riot sorry, habe das überhaupt nicht bemerkt. Ich weiß, dass Sie unter OS X jede gewünschte Bash installieren können, aber die Standardeinstellung ist 3.2. Da mein Skript auch auf verschiedenen Macs ausgeführt werden muss, ist dies für mich keine Option.
d4Rk
2
@ d4Rk das ist verständlich - wenn Sie wirklich Portabilität garantieren müssen, würde ich empfehlen, sich an den POSIX-Shell-Standard zu halten, da Sie in einigen Fällen garantiert keine Version von Bash finden.
Aufstand
1
Genau das habe ich gesucht. Sollte höher sein =)
Robin Winslow
39

Speichern Sie den Status von nocasematch (falls eine andere Funktion davon abhängt, dass sie deaktiviert ist):

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

Hinweis: Nur verwenden, localwenn es sich innerhalb einer Funktion befindet.

Gerry Hickman
quelle
4
Schön, weil caseAussagen (einschließlich der in der Antwort von Ghostdog) meine Haut immer kriechen lassen
SeldomNeedy
15

Eine Möglichkeit wäre, beide Zeichenfolgen in obere oder untere umzuwandeln:

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

Ein anderer Weg wäre, grep zu verwenden:

echo "string" | grep -qi '^String$' && echo same || echo different
Randy Proctor
quelle
Ich habe die trMethode in meinen Docker-basierten Anwendungen verwendet, die auf Alpin basieren (was shvia bietet busybox). Danke dir.
MXWest
7

Für die Korn-Shell verwende ich den integrierten Schriftsatzbefehl (-l für Kleinbuchstaben und -u für Großbuchstaben).

var=True
typeset -l var
if [[ $var == "true" ]]; then
    print "match"
fi
Ek C.
quelle
2
Dies ist in Bezug auf die Leistung viel besser als das Starten von awk oder einem anderen Prozess.
Alex
1
In bash kann deklarieren -l oder -u verwendet werden, um die Attribute festzulegen.
Bharat
5

Sehr einfach, wenn Sie einen Zeilenvergleich ohne Berücksichtigung der Groß- und Kleinschreibung durchführen:

str1="MATCH"
str2="match"

if [[ $(fgrep -ix $str1 <<< $str2) ]]; then
    echo "case-insensitive match";
fi
Cooper F. Nelson
quelle
Es wäre besser, if fgrep -qix -- "$str1" <<<"$str2"; thenstattdessen zu verwenden .
3

Hier ist meine Lösung mit 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
Steine333
quelle
3

grephat ein -iFlag, das bedeutet, dass die Groß- und Kleinschreibung nicht berücksichtigt wird. Bitten Sie es, Ihnen mitzuteilen, ob var2 in var1 ist.

var1=match 
var2=MATCH 
if echo $var1 | grep -i "^${var2}$" > /dev/null ; then
    echo "MATCH"
fi
Larry
quelle
3
funktioniert nicht, wenn in var2 Regex-Sonderzeichen vorhanden sind.
Haridsv
3

Denn zshdie Syntax ist etwas anders, aber immer noch kürzer als die meisten Antworten hier:

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

Dadurch werden beide Zeichenfolgen vor dem Vergleich in Großbuchstaben umgewandelt.


Bei einer anderen Methode werden zshs verwendet globbing flags, mit denen wir mithilfe des iGlob-Flags direkt von der Übereinstimmung ohne Berücksichtigung der Groß- und Kleinschreibung profitieren können:

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

shopt -s nocaseglob

ennuikiller
quelle
1

Ich bin auf dieses großartige Blog / Tutorial / was auch immer über den Umgang mit Groß- und Kleinschreibung reagiert . Die folgenden drei Methoden werden anhand von Beispielen ausführlich erläutert:

1. Konvertieren Sie das Muster mit dem Befehl tr in Kleinbuchstaben

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. Verwenden Sie Regex mit Fallmustern

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. Schalten Sie nocasematch ein

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
Abdul Rahman Sherzad
quelle