手紙

手紙

このシェルスクリプトをどのように短縮できますか?

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

答え1

ステートメントの使用case(移植可能、同様のシェルで動作sh):

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

CODEまた、変数名をすべて大文字(たとえば)から小文字または大文字と小文字の混合(たとえば、またはcodeCodeに変更することをお勧めします。特別な意味を持つ大文字の名前がたくさんあり、そのうちの1つを誤って再利用すると問題が発生する可能性があります。

追加の注意:標準ルールは、「標準出力」ではなく「標準エラー」にエラーメッセージを送信することです>&2。また、スクリプト(またはプログラム)が失敗した場合は、exit 1呼び出しコンテキストで何が間違っているのかを知るために、ゼロ以外の状態()で終了することをお勧めします。また、さまざまな状態を使用してさまざまな問題を示すこともできます(参照:マニュアルcurlページ良い例)。 (提案をしてくれたStéphane ChazelasとMonty Harderに感謝します。)

オペレーティングシステム、バージョン、設定などの間で移植性が高いため、(および)をprintf使用しないことをお勧めします。 OSアップデートには、別のオプションでコンパイルされたbashバージョンが含まれており、動作が変更されたため、多くのスクリプトが破損する状況がありました。echo -eecho -necho

$CODEここでは実際に二重引用符は必要ありません。内の文字列は、case安全に保存できる数少ないコンテキストの1つです。ただし、特別な理由がない限り、変数参照を二重引用符で囲むことをお勧めします。どこが安全で、どこが安全でないかを追跡するのは難しいので、習慣的に二重引用符で引用する方が安全です。

答え2

bashバージョン4.0以降を使用していると仮定すると...

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}

コードでは、私はすべてのドメイン名を含む連想配列を定義しました。各ドメイン名は単一文字小文字キーに関連付けられています。

変数$PNには、配列の小文字の値に対応するドメイン名が割り当てられますが$CODE(小文字に変換された値のみが返されます${CODE,,})、値がリストの有効な項目に対応しない場合、スクリプトはエラーとともに終了します。$CODE$CODEdomain

パラメータ${variable:?error message}置換は(コードの対応するフィールド)値に拡張されますが、$variable値が空で使用できない場合、スクリプトはエラーメッセージで終了します。コードとまったく同じエラーメッセージ形式を取得できませんが、本質的にパフォーマンス$CODE無効な場合でも同じ:

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

文字数に興味がある場合は、文字数をさらに減らすことができます。

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}

不要な改行文字を削除することに加えて、各com.ドメインからも削除しました(代わりにディストリビューションに追加しましたPN)。

上記のすべてのコードは複数文字の値でも機能します$CODE(対応する小文字のキーが配列にある場合domain)。


数値(0から始まる)インデックス付けの場合、$CODEコードは少し単純化されます。

CODE=0

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

domainまた、1行に1つのエントリを含む補助ファイルから配列を読み取ることも非常に簡単です。

CODE=0

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

答え3

シェルが配列を受け入れる場合、最も短い答えはbashの次の例のようになります。

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

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

これは$code、a、b、c、またはdのみが可能であると仮定します。
それ以外の場合は、次のテストを追加します。

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

答え4

文字を使用して値のインデックスを作成します。数字を使用すると、次のように簡単になります。

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

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

これは、ほとんどのシェルで動作する移植可能なシェルコードです。
Bashの場合は、次のものを使用できます。pn=${!code}または、bash/ksh/zsh の場合、次のものを使用できますpn=${@:code:1}

手紙

文字(a〜zまたはA〜Z)を使用する必要がある場合は、その文字をインデックスに変換する必要があります。

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  ))}\"

長いコードで各部分の意図と意味を明確にします。

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.

小文字に変換する必要がある場合は、以下を使用してください($(( asciival & ~32 ))ASCII値のビット6が設定されていないことを確認してください)。

エラーコード

エラーが発生したときにスクリプトが印刷する出力は非常に長く、非常に具体的です。
これを処理する最も一般的な方法は、関数を定義することです。

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

次に、必要な特定のメッセージを使用して関数を呼び出します。

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

最終終了値はexitcode(ここでは27)として与えられる。

スクリプト全体(エラーチェックを含む)は次のとおりです。

errorcode(){ exitcode=$1; shift; printf '\a\t %s\n' "$@"; 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"

関連情報