it-swarm.com.de

Wie kann ich einer Variablen abhängig von einer anderen Variablen präzise unterschiedliche Werte zuweisen?

Wie kann ich dieses Shell-Skript kürzen?

CODE="A"

if test "$CODE" = "A"
then
 PN="com.tencent.ig"
Elif test "$CODE" = "a"
 then
 PN="com.tencent.ig"
Elif test "$CODE" = "B"
 then
 PN="com.vng.pubgmobile"
Elif test "$CODE" = "b"
 then
 PN="com.vng.pubgmobile"
Elif test "$CODE" = "C"
 then
 PN="com.pubg.krmobile"
Elif test "$CODE" = "c"
 then
 PN="com.pubg.krmobile"
Elif test "$CODE" = "D"
 then
 PN="com.rekoo.pubgm"
Elif test "$CODE" = "d"
 then
 PN="com.rekoo.pubgm"
else
 echo -e "\a\t ERROR!"
 echo -e "\a\t CODE KOSONG"
 echo -e "\a\t MELAKUKAN EXIT OTOMATIS"
 exit
fi
20
IISomeOneII

Verwenden Sie eine case -Anweisung (portabel, funktioniert in jeder sh-ähnlichen Shell):

case "$CODE" in
    [aA] ) PN="com.tencent.ig" ;;
    [bB] ) PN="com.vng.pubgmobile" ;;
    [cC] ) PN="com.pubg.krmobile" ;;
    [dD] ) PN="com.rekoo.pubgm" ;;
    * ) printf '\a\t%s\n' 'ERROR!' 'CODE KOSONG' 'MELAKUKAN EXIT OTOMATIS' >&2
        exit 1 ;;
esac

Ich würde auch empfehlen, Ihre Variablennamen von allen Großbuchstaben (wie CODE) in Klein- oder Großbuchstaben (wie code oder Code) zu ändern. Es gibt viele All-Caps-Namen, die eine besondere Bedeutung haben, und die versehentliche Wiederverwendung eines dieser Namen kann zu Problemen führen.

Sonstige Hinweise: Die Standardkonvention besteht darin, Fehlermeldungen an "Standardfehler" und nicht an "Standardausgabe" zu senden. das >&2 redirect macht das. Wenn ein Skript (oder Programm) fehlschlägt, beenden Sie am besten mit einem Status ungleich Null (exit 1), sodass jeder aufrufende Kontext erkennen kann, was schief gelaufen ist. Es ist auch möglich, unterschiedliche Status zu verwenden, um unterschiedliche Probleme anzuzeigen (ein gutes Beispiel finden Sie im Abschnitt "CODES BEENDEN" von Manpage curl ). (Dank an Stéphane Chazelas und Monty Harder für Vorschläge hier.)

Ich empfehle printf anstelle von echo -e (und echo -n), weil es zwischen Betriebssystemen, Versionen, Einstellungen usw. portabler ist. Ich hatte einmal eine Reihe von Skripten unterbrochen, weil ein Betriebssystem-Update eine Version von Bash enthielt, die mit verschiedenen Optionen kompiliert wurde und das Verhalten von echo veränderte .

Die doppelten Anführungszeichen um $CODE werden hier nicht wirklich gebraucht. Die Zeichenfolge in einem case ist einer der wenigen Kontexte, in denen es sicher ist, sie wegzulassen. Ich bevorzuge es jedoch, Variablenreferenzen in doppelte Anführungszeichen zu setzen, es sei denn, es gibt einen bestimmten Grund, dies nicht zu tun, da es schwierig ist, den Überblick darüber zu behalten, wo es sicher ist und wo nicht. Daher ist es sicherer, sie nur in doppelten Anführungszeichen zu setzen.

62
Gordon Davisson

Angenommen, Sie verwenden bash Release 4.0 oder neuer ...

CODE=A

declare -A domain

domain=(
   [a]=com.tencent.ig
   [b]=com.vng.pubgmobile
   [c]=com.pubg.krmobile
   [d]=com.rekoo.pubgm
)

PN=${domain[${CODE,,}]:?ERROR! CODE KOSONG, MELAKUKAN EXIT OTOMATIS}

Im Code definiere ich ein assoziatives Array, das alle Domänennamen enthält, die jeweils einem einzelnen Kleinbuchstaben zugeordnet sind.

Der Variablen $PN Wird der Domänenname zugewiesen, der dem Kleinbuchstaben $CODE Entspricht (${CODE,,} Gibt den Wert von $CODE Zurück, der nur in Kleinbuchstaben umgewandelt wird). aus diesem Array, aber wenn $CODE keinem gültigen Eintrag in der Liste domain entspricht, wird das Skript mit einem Fehler beendet.

Die Ersetzung des Parameters ${variable:?error message} Würde auf den Wert von $variable (Die entsprechende Domäne im Code) erweitert, das Skript jedoch mit der Fehlermeldung beenden, wenn der Wert leer und nicht verfügbar ist. Sie erhalten nicht genau die gleiche Formatierung der Fehlermeldung wie in Ihrem Code, aber es wäre im Wesentlichen Verhalten dasselbe, wenn $CODE Ungültig ist:

$ bash script.sh
script.sh: line 12: domain[${CODE,,}]: ERROR! CODE KOSONG, MELAKUKAN EXIT OTOMATIS

Wenn Sie sich für die Anzahl der Zeichen interessieren, können wir dies weiter verkürzen:

CODE=A
declare -A domain=( [a]=tencent.ig [b]=vng.pubgmobile [c]=pubg.krmobile [d]=rekoo.pubgm )
PN=com.${domain[${CODE,,}]:?ERROR! CODE KOSONG, MELAKUKAN EXIT OTOMATIS}

Abgesehen vom Löschen unnötiger Zeilenumbrüche habe ich auch com. Aus jeder Domain entfernt (dies wird stattdessen in der Zuweisung zu PN hinzugefügt).

Beachten Sie, dass der gesamte obige Code auch für einen mehrstelligen Wert in $CODE Funktionieren würde (wenn für diese im Array domain Schlüssel mit niedrigerer Schreibweise vorhanden wären).


Wenn $CODE Stattdessen ein numerischer (nullbasierter) Index wäre, würde dies den Code ein wenig vereinfachen:

CODE=0

domain=( com.tencent.ig com.vng.pubgmobile com.pubg.krmobile com.rekoo.pubgm )
PN=${domain[CODE]:?ERROR! CODE KOSONG, MELAKUKAN EXIT OTOMATIS}

Dies würde es außerdem sehr einfach machen, das Array domain aus einer Hilfsdatei zu lesen, die einen Eintrag pro Zeile enthält:

CODE=0

readarray -t domain <domains.txt
PN=${domain[CODE]:?ERROR! CODE KOSONG, MELAKUKAN EXIT OTOMATIS}
19
Kusalananda

Wenn Ihre Shell Arrays zulässt, sollte die kürzeste Antwort wie in diesem Beispiel in bash lauten:

declare -A site
site=( [a]=com.tencent.ig [b]=com.vng.pubgmobile [c]=com.pubg.krmobile [d]=com.rekoo.pubgm )

pn=${site[${code,}]}

Das setzt voraus, dass $code konnte nur a, b, c oder d sein.
Wenn nicht, fügen Sie einen Test hinzu wie:

case ${site,} in
    a|b|c|d)        pn=${site[${code,}]};;
    *)              pn="default site"
                    printf '\a\t %s\n' 'ERROR!' 'CODE KOSONG' 'MELAKUKAN EXIT OTOMATIS'
                    exit 1
                    ;;
esac
11
Isaac

Ich werde diese Antwort in eine andere Richtung lenken. Anstatt Ihre Daten in das Skript zu codieren, fügen Sie diese Daten in eine separate Datendatei ein und durchsuchen Sie die Datei mit Code:

$ cat names.cfg 
a com.tencent.ig
b com.vng.pubgmobile
c com.pubg.krmobile
d com.rekoo.pubgm

$ cat lookup.sh
PN=$(awk -v code="${1:-}" 'tolower($1) == tolower(code) { print $2; }' names.cfg)
if [ -z "${PN}" ]; then
  printf '\a\t%s\n' 'ERROR!' 'CODE KOSONG' 'MELAKUKAN EXIT OTOMATIS' >&2
  exit 1
fi
echo "${PN}"

$ bash lookup.sh A
com.tencent.ig
$ bash lookup.sh a
com.tencent.ig
$ bash lookup.sh x
    ERROR!
    CODE KOSONG
    MELAKUKAN EXIT OTOMATIS

Die Trennung dieser Bedenken hat einige Vorteile:

  • Hinzufügen und Entfernen von Daten einfach und unkompliziert, ohne die Codelogik umgehen zu müssen.
  • Andere Programme können die Daten wiederverwenden, z. B. die Anzahl der Übereinstimmungen in einer bestimmten Unterdomäne.
  • Wenn Sie eine große Liste von Daten haben, können Sie diese auf der Festplatte sortieren und look effizient verwenden binäre Suche es (anstatt Zeile für Zeile grep oder awk)
3
bishop

Sie verwenden Buchstaben, um die Werte zu indizieren. Wenn Sie Zahlen verwenden, wird dies so einfach wie:

code=1
set -- com.tencent.ig com.vng.pubgmobile com.pubg.krmobile com.rekoo.pubgm

eval pn\=\${"$code"}

Das ist portabler Shell-Code, der auf den meisten Shells funktioniert.
Für Bash können Sie verwenden: pn=${!code} Oder für Bash/ksh/zsh: pn=${@:code:1}.

briefe

Wenn Sie Benutzerbuchstaben (von A bis Z oder A bis Z) benötigen, müssen diese in einen Index konvertiert werden:

code=a                              # or A, B, C, ... etc.
set -- com.tencent.ig com.vng.pubgmobile com.pubg.krmobile com.rekoo.pubgm
eval pn\=\"\${$(( ($(printf '%d' "'$code")|32)-96  ))}\"

In einem längeren Code, um die Absicht und Bedeutung jedes Teils zu verdeutlichen:

code=A

set -- com.tencent.ig com.vng.pubgmobile com.pubg.krmobile com.rekoo.pubgm

asciival=$(( $(printf '%d' "'$code") ))      # byte value of the ASCII letter.
upperval=$(( asciival |  32 ))               # shift to uppercase.
indexval=$(( upperval -  96 ))               # convert to an index from a=1.
eval arg\=\"\$\{$indexval\}\"                # the argument at such index.

Wenn Sie in Kleinbuchstaben konvertieren müssen, verwenden Sie: $(( asciival & ~32 )) (stellen Sie sicher, dass Bit 6 des ASCII-Werts nicht gesetzt ist).

fehlercode

Die Ausgabe, die Ihr Skript bei einem Fehler druckt, ist ziemlich lang (und insbesondere).
Der vielseitigste Weg, damit umzugehen, besteht darin, eine Funktion zu definieren:

errorcode(){ exitcode=$1; shift; printf '\a\t %s\n' "[email protected]"; exit "$exitcode"; }

Rufen Sie diese Funktion dann mit den spezifischen Nachrichten auf, die Sie benötigen.

errorcode 27  "ERROR!" "CODE KOSONG" "MELAKUKAN EXIT OTOMATIS"

Beachten Sie, dass der resultierende Exit-Wert durch exitcode gegeben ist (Beispiel hier ist 27).

Ein vollständiges Skript (mit Fehlerprüfung) wird dann:

errorcode(){ exitcode=$1; shift; printf '\a\t %s\n' "[email protected]"; exit "$exitcode"; }

code=${1:-A}

case "$code" in 
    [a-d]|[A-D]) : ;;
    *)           errorcode 27  "ERROR!" "CODE KOSONG" "MELAKUKAN EXIT OTOMATIS" ;;
esac

set -- com.tencent.ig com.vng.pubgmobile com.pubg.krmobile com.rekoo.pubgm
eval pn\=\"\${$(( ($(printf '%d' "'$code") & ~32) - 64  ))}\"

printf 'Code=%s Argument=%s\n' "$code" "$pn"
1
Isaac