Shell脚本流程控制语句CASE详解

本章节继续介绍流程控制语句,在前面的while语句,read语句生成了一些简单的菜单并构建了用户选择处理逻辑。使用了了一系列的if命令来识别可能的菜单选项。这种逻辑经常会出现在程序中,Shell提供了们处理多重选择的流程控制机制。


1.case命令

在Bash中,多重选择复合命令是case,用法如下:

case word in
	[parrern [| pattern]...) commands ;;]...
esac

使用case简化用户选择处理逻辑:

[sysadmin@ansible bin]$ cat case-menu
#!/bin/bash

#case-menu

clear
echo "
Please Select:

1.Display System Information
2.Display Disk Space
3.Display Home Space Utilization
4.Quit
"
read -p "Enter selection [0-3] > "

case "$REPLY" in
        0)      echo "Program terminated."
                exit
                ;;
        1)      echo "Hostname: $HOSTNAME"
                uptime
                ;;
        2)      df -h
                ;;
        3)      if [[ "$(id -u)" -eq 0 ]]; then
                        echo "Home Space Utilization (ALL Users)"
                        du -sh /home/*
                else
                        echo "Home Space Utilizaion ($USER)"
                        du -sh "$HOME"
                fi
                ;;
        *)      echo "Invalid entry." >&2
                exit 1
                ;;
esac

case命令查看word的值,本例中就是REPLY的值,然后将其与patterns指定的模式匹配。如果找到匹配,则执行与该模式关联的命令,之后不再尝试进行其他匹配。

1.1 模式

case使用的模式与路径名扩展使用的模式一样,模式以)结尾。下表描述了case模式示例:

模式 描述
a) 如果word是a,则匹配
[[:alpha:]] 如果word是单个字母,则匹配
???) 如果word是3个字符,则匹配
*.txt) 如果word是以.txt结尾,则匹配
*) 不管word是什么内容,均可匹配。将该模式作为case命令最后一个模式是一种不错的做法,可以匹配之前的模式无法匹配到的内容,也就是说,能捕获到所有的“漏网之鱼”
[sysadmin@ansible bin]$ cat case-sample
#!/bin/bash

# case-sample

read -p "enter word > "

case "$REPLY" in
        [[:alpha:]])    echo ""$REPLY" is a single alphabetic character." ;;
        [ABC][0-9])             echo ""$REPLY" is A, B, or C followed by a digit." ;;
        ???)                    echo ""$REPLY" is three characters long." ;;
        *.txt)                  echo ""$REPLY" is a word ending in '*.txt'" ;;
        *)                              echo ""$REPLY" is something else." ;;
esac

也可以使用|作为分隔符,将多个模式组合在一起,形成“逻辑或”(or)关系的条件模式,这在同时处理大小写字母的的时候很有用。

[sysadmin@ansible bin]$ cat case-menu
#!/bin/bash

#case-menu

clear
echo "
Please Select:

B.Display System Information
C.Display Disk Space
D.Display Home Space Utilization
Q.Quit
"
read -p "Enter selection [0-3] > "

case "$REPLY" in
        q|Q)    echo "Program terminated."
                        exit
                        ;;
        b|B)    echo "Hostname: $HOSTNAME"
                        uptime
                        ;;
        c|C)    df -h
                        ;;
        d|D)    if [[ "$(id -u)" -eq 0 ]]; then
                        echo "Home Space Utilization (ALL Users)"
                                du -sh /home/*
                        else
                                echo "Home Space Utilizaion ($USER)"
                                du -sh "$HOME"
                        fi
                        ;;
        *)              echo "Invalid entry." >&2
                        exit 1
                        ;;
esac

1.2 执行多次操作

Bash之前,case只允许在成功的匹配分支上执行一次操作,操作结束后,case命令随之终止。来看一个字符匹配脚本:

[sysadmin@ansible bin]$ cat case-1
#!/bin/bash

# case-1:测试一个字符

read -n 1 -p "Type a character > "
echo

case "$REPLY" in
        [[:upper:]])    echo "$REPLY is a upper case." ;;
        [[:lower:]])    echo "$REPLY is a lower case." ;;
        [[:alpha:]])    echo "$REPLY is a alphabetic." ;;
        [[:digit:]])    echo "$REPLY is a digit." ;;
        [[:graph:]])    echo "$REPLY is a visible character." ;;
        [[:punct:]])    echo "$REPLY is a punctuation symbol." ;;
        [[:space:]])    echo "$REPLY is a whitespace character." ;;
        [[:xdigit:]])   echo "$REPLY is a hexadecimal digit." ;;
esac

在Bash4.0之前,case无法匹配多个分支。现代版本的Bash添加了;;&语法,允许继续测试下一个模式,上一个代码改写为

[sysadmin@ansible bin]$ cat case-2
#!/bin/bash

# case-2:测试多个字符

read -n 1 -p "Type a character > "
echo

case "$REPLY" in
        [[:upper:]])    echo "$REPLY is a upper case." ;;&
        [[:lower:]])    echo "$REPLY is a lower case." ;;&
        [[:alpha:]])    echo "$REPLY is a alphabetic." ;;&
        [[:digit:]])    echo "$REPLY is a digit." ;;&
        [[:graph:]])    echo "$REPLY is a visible character." ;;&
        [[:punct:]])    echo "$REPLY is a punctuation symbol." ;;&
        [[:space:]])    echo "$REPLY is a whitespace character." ;;&
        [[:xdigit:]])   echo "$REPLY is a hexadecimal digit." ;;&
esac
[sysadmin@ansible bin]$ case-2
Type a character > a
a is a lower case.
a is a alphabetic.
a is a visible character.
a is a hexadecimal digit.
[sysadmin@ansible bin]$

有了;;&,case就可以继续测试模式,而不再直接终止。case是处理某些特定类型问题的绝佳工具。

你可能感兴趣的:(Shell,Scripts,CASE,流程控制,CASE模式匹配,CASE菜单)