字母

字母

如何缩短这个 shell 脚本?

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类似的 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

我还建议将变量名称从全部大写字母(例如CODE)更改为小写或混合大小写(例如codeCode)。有许多全大写名称具有特殊含义,不小心重复使用其中之一可能会引起麻烦。

其他说明: 标准约定是将错误消息发送到“标准错误”而不是“标准输出”;重定向>&2就是这样做的。另外,如果脚本(或程序)失败,最好以非零状态 ( exit 1) 退出,这样任何调用上下文都可以知道出了什么问题。还可以使用不同的状态来指示不同的问题(请参阅手册curl一个很好的例子)。 (此处感谢 Stéphane Chazelas 和 Monty Harder 的建议。)

我建议printf不要使用echo -e( 和echo -n),因为它在操作系统、版本、设置等之间更具可移植性。我曾经有过一堆脚本被破坏的情况,因为操作系统更新包含使用不同选项编译的 bash 版本,这改变了echo行为方式。

$CODE这里实际上并不需要双引号。 a 中的字符串case是少数可以安全地保留它们的上下文之一。但是,我更喜欢对变量引用加双引号,除非有特定原因不这样做,因为很难跟踪哪里安全,哪里不安全,所以习惯性地用双引号引用它们会更安全。

答案2

假设您使用的是bash4.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)。


如果$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这还使得从每行包含一个条目的辅助文件中读取数组变得非常容易:

CODE=0

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

答案3

如果你的 shell 允许数组,最短的答案应该像 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"}

这是可移植的 shell 代码,适用于大多数 shell。
对于 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"

相关内容