AskOverflow.Dev

AskOverflow.Dev Logo AskOverflow.Dev Logo

AskOverflow.Dev Navigation

  • 主页
  • 系统&网络
  • Ubuntu
  • Unix
  • DBA
  • Computer
  • Coding
  • LangChain

Mobile menu

Close
  • 主页
  • 系统&网络
    • 最新
    • 热门
    • 标签
  • Ubuntu
    • 最新
    • 热门
    • 标签
  • Unix
    • 最新
    • 标签
  • DBA
    • 最新
    • 标签
  • Computer
    • 最新
    • 标签
  • Coding
    • 最新
    • 标签
主页 / unix / 问题 / 531795
Accepted
IISomeOneII
IISomeOneII
Asked: 2019-07-24 22:02:28 +0800 CST2019-07-24 22:02:28 +0800 CST 2019-07-24 22:02:28 +0800 CST

如何根据另一个变量简明地为变量分配不同的值?

  • 772

如何缩短这个 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
shell-script
  • 5 5 个回答
  • 4059 Views

5 个回答

  • Voted
  1. Best Answer
    Gordon Davisson
    2019-07-24T22:13:43+08:002019-07-24T22:13:43+08:00

    使用case语句(可移植,可在任何类似shshell 中工作):

    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)更改为小写或混合大小写(如codeor Code)。有许多具有特殊含义的全大写名称,并且不小心重复使用其中一个可能会造成麻烦。

    其他说明:标准约定是将错误消息发送到“标准错误”而不是“标准输出”;>&2重定向执行此操作。此外,如果脚本(或程序)失败,最好以非零状态 ( exit 1) 退出,这样任何调用上下文都可以判断出了什么问题。也可以使用不同的状态来指示不同的问题(有关一个很好的示例,请参见手册页的“退出代码”部分)。curl(感谢 Stéphane Chazelas 和 Monty Harder 提供的建议。)

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

    $CODE这里不需要双引号。a 中的字符串case是少数可以安全地将其关闭的上下文之一。但是,我更喜欢双引号变量引用,除非有特定的理由不这样做,因为很难跟踪它在哪里是安全的,在哪里不安全,所以习惯性地双引号会更安全。

    • 62
  2. Kusalananda
    2019-07-24T23:03:21+08:002019-07-24T23:03:21+08:00

    假设您使用的是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转换为小写字母的值),但如果$CODE不对应于domain列表中的有效条目,则退出脚本并返回错误。

    参数替换将${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}
    
    • 19
  3. user232326
    2019-07-24T22:52:45+08:002019-07-24T22:52:45+08:00

    如果你的 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
    
    • 11
  4. bishop
    2019-07-27T07:22:42+08:002019-07-27T07:22:42+08:00

    我打算把这个答案换个方向。与其将数据编码到脚本中,不如将数据放入单独的数据文件中,然后使用代码搜索文件:

    $ 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
    

    分离这些问题有几个好处:

    • 轻松简单地添加和删除数据,无需处理代码逻辑。
    • 其他程序可以重用数据,例如计算特定子域中有多少匹配项。
    • 如果你有一个庞大的数据列表,你可以在磁盘上对其进行排序并使用它look来有效地对它进行二进制搜索(而不是逐行grep或awk)
    • 3
  5. user232326
    2019-07-27T14:57:56+08:002019-07-27T14:57:56+08:00

    您正在使用字母来索引值,如果您要使用数字,它变得如此简单:

    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"
    
    • 1

相关问题

  • 在awk中的两行之间减去相同的列

  • 打印文件行及其长度的脚本[关闭]

  • 通过命令的标准输出以编程方式导出环境变量[重复]

  • 按分隔符拆分并连接字符串问题

  • MySQL Select with function IN () with bash array

Sidebar

Stats

  • 问题 205573
  • 回答 270741
  • 最佳答案 135370
  • 用户 68524
  • 热门
  • 回答
  • Marko Smith

    模块 i915 可能缺少固件 /lib/firmware/i915/*

    • 3 个回答
  • Marko Smith

    无法获取 jessie backports 存储库

    • 4 个回答
  • Marko Smith

    如何将 GPG 私钥和公钥导出到文件

    • 4 个回答
  • Marko Smith

    我们如何运行存储在变量中的命令?

    • 5 个回答
  • Marko Smith

    如何配置 systemd-resolved 和 systemd-networkd 以使用本地 DNS 服务器来解析本地域和远程 DNS 服务器来解析远程域?

    • 3 个回答
  • Marko Smith

    dist-upgrade 后 Kali Linux 中的 apt-get update 错误 [重复]

    • 2 个回答
  • Marko Smith

    如何从 systemctl 服务日志中查看最新的 x 行

    • 5 个回答
  • Marko Smith

    Nano - 跳转到文件末尾

    • 8 个回答
  • Marko Smith

    grub 错误:你需要先加载内核

    • 4 个回答
  • Marko Smith

    如何下载软件包而不是使用 apt-get 命令安装它?

    • 7 个回答
  • Martin Hope
    user12345 无法获取 jessie backports 存储库 2019-03-27 04:39:28 +0800 CST
  • Martin Hope
    Carl 为什么大多数 systemd 示例都包含 WantedBy=multi-user.target? 2019-03-15 11:49:25 +0800 CST
  • Martin Hope
    rocky 如何将 GPG 私钥和公钥导出到文件 2018-11-16 05:36:15 +0800 CST
  • Martin Hope
    Evan Carroll systemctl 状态显示:“状态:降级” 2018-06-03 18:48:17 +0800 CST
  • Martin Hope
    Tim 我们如何运行存储在变量中的命令? 2018-05-21 04:46:29 +0800 CST
  • Martin Hope
    Ankur S 为什么 /dev/null 是一个文件?为什么它的功能不作为一个简单的程序来实现? 2018-04-17 07:28:04 +0800 CST
  • Martin Hope
    user3191334 如何从 systemctl 服务日志中查看最新的 x 行 2018-02-07 00:14:16 +0800 CST
  • Martin Hope
    Marko Pacak Nano - 跳转到文件末尾 2018-02-01 01:53:03 +0800 CST
  • Martin Hope
    Kidburla 为什么真假这么大? 2018-01-26 12:14:47 +0800 CST
  • Martin Hope
    Christos Baziotis 在一个巨大的(70GB)、一行、文本文件中替换字符串 2017-12-30 06:58:33 +0800 CST

热门标签

linux bash debian shell-script text-processing ubuntu centos shell awk ssh

Explore

  • 主页
  • 问题
    • 最新
    • 热门
  • 标签
  • 帮助

Footer

AskOverflow.Dev

关于我们

  • 关于我们
  • 联系我们

Legal Stuff

  • Privacy Policy

Language

  • Pt
  • Server
  • Unix

© 2023 AskOverflow.DEV All Rights Reserve