# 原创 : Shell流程控制:if 分支结构 # Shell流程控制:if 分支结构 ### 流程控制:if 分支结构 #### if ``` x=5 if [ $x = 5 ]; then echo "x equals 5." else echo "x does not equal 5." fi ``` `echo $?`查看命令执行返回的状态。经常与 if 一块使用的命令是 test,它执行各种各样的检查与比较: ``` test expression [ expression ] ``` **测试文件表达式:** |表达式|如果下列条件为真则返回True |------ |file1 -ef file2|file1 和 file2 拥有相同的索引号(通过硬链接两个文件名指向相同的文件)。 |file1 -nt file2|file1新于 file2。 |file1 -ot file2|file1早于 file2。 |-b file|file 存在并且是一个块(设备)文件。 |-c file|file 存在并且是一个字符(设备)文件。 |-d file|file 存在并且是一个目录。 |-e file|file 存在。 |-f file|file 存在并且是一个普通文件。 |-g file|file 存在并且设置了组 ID。 |-G file|file 存在并且由有效组 ID 拥有。 |-k file|file 存在并且设置了它的“sticky bit”。 |-L file|file 存在并且是一个符号链接。 |-O file|file 存在并且由有效用户 ID 拥有。 |-p file|file 存在并且是一个命名管道。 |-r file|file 存在并且可读(有效用户有可读权限)。 |-s file|file 存在且其长度大于零。 |-S file|file 存在且是一个网络 socket。 |-t fd|fd 是一个定向到终端/从终端定向的文件描述符 。 这可以被用来决定是否重定向了标准输入/输出错误。 |-u file|file 存在并且设置了 setuid 位。 |-w file|file 存在并且可写(有效用户拥有可写权限)。 |-x file|file 存在并且可执行(有效用户有执行/搜索权限)。 ``` test_file () { # test-file: Evaluate the status of a file FILE=~/.bashrc if [ -e "$FILE" ]; then if [ -f "$FILE" ]; then echo "$FILE is a regular file." fi if [ -d "$FILE" ]; then echo "$FILE is a directory." fi if [ -r "$FILE" ]; then echo "$FILE is readable." fi if [ -w "$FILE" ]; then echo "$FILE is writable." fi if [ -x "$FILE" ]; then echo "$FILE is executable/searchable." fi else echo "$FILE does not exist" # 函数中用return 语句来代替 exit 命令 return 1 fi } ``` **测试字符串表达式:** |表达式|如果下列条件为真则返回True |------ |string|string 不为 null。 |-n string|字符串 string 的长度大于零。 |-z string|字符串 string 的长度为零。 |string1 = string2string1 == string2|string1 和 string2 相同。 单或双等号都可以,不过双等号更受欢迎。 |string1 != string2|string1 和 string2 不相同。 |string1 > string2|sting1 排列在 string2 之后。 |string1 < string2|string1 排列在 string2 之前。 > 当与 test 一块使用的时候, > 和 < 表达式操作符必须用引号引起来(或者是用反斜杠转义) #### 整型表达式 测试整数表达式: |表达式|如果为真… |------ |integer1 -eq integer2|integer1 等于 integer2。 |integer1 -ne integer2|integer1 不等于 integer2。 |integer1 -le integer2|integer1 小于或等于 integer2。 |integer1 -lt integer2|integer1 小于 integer2。 |integer1 -ge integer2|integer1 大于或等于 integer2。 |integer1 -gt integer2|integer1 大于 integer2。 #### 更现代的测试版本 ``` # 加强的 test 命令替代物 [[ expression ]] # 添加的另一个功能是==操作符支持类型匹配 if [[ $FILE == foo.* ]]; then ... ``` `string1 =~ regex`:匹配正则表达式则返回真 #### (( )) - 为整数设计 `(( ))` 复合命令,支持一套 完整的算术计算,`(( ))`被用来执行算术真测试。如果算术计算的结果是非零值,则其测试值为真。 ``` # 判断一个数的奇偶性 if (( ((INT % 2)) == 0)); then echo "INT is even." else echo "INT is odd." ``` #### 结合表达式 逻辑操作符: |操作符|测试|[[ ]] and (( )) |------ |AND|-a|&& |OR|-o||| |NOT|!|! #### 控制操作符:分支的另一种方法 ``` command1 && command2 command1 || command2 ``` 对于 && 操作符,先执行 command1,只有command1 执行成功后, 才会执行 command2。对于 || 操作符,先执行 command1,只有command1 执行失败后, 才会执行 command2。 ### 读取键盘输入 #### read - 从标准输入读取数值 ``` read [-options] [variable...] ``` ``` #!/bin/bash # read-integer: evaluate the value of an integer. # -n 选项(其会删除输出结果末尾的换行符)的 echo 命令,来显示提示信息 echo -n "Please enter an integer -> " read int if [[ "$int" =~ ^-?[0-9]+$ ]]; then if [ $int -eq 0 ]; then echo "$int is zero." else if [ $int -lt 0 ]; then echo "$int is negative." else echo "$int is positive." fi if [ $((int % 2)) -eq 0 ]; then echo "$int is even." else echo "$int is odd." fi fi else echo "Input value is not an integer." >&2 exit 1 fi ``` ``` alien@localhost:~ $ info-test Please enter an integer -> 3 3 is positive. 3 is odd. alien@localhost:~ $ info-test Please enter an integer -> 6 6 is positive. 6 is even. ``` read 可以给多个变量赋值: ``` read var1 var2 var3 var4 var5 ``` 执行脚本时输入时以空格隔开,默认值为空,额外的输入数据会包含到最后一个变量中。 如果 read 命令之后没有列出变量名,则一个 shell 变量,默认的REPLY,将会包含 所有的输入: **read选项:** |选项|说明 |------ |-a array|把输入赋值到数组 array 中,从索引号零开始。我们 将在第36章中讨论数组问题。 |-d delimiter|用字符串 delimiter 中的第一个字符指示输入结束,而不是一个换行符。 |-e|使用 Readline 来处理输入。这使得与命令行相同的方式编辑输入。 |-n num|读取 num 个输入字符,而不是整行。 |-p prompt|为输入显示提示信息,使用字符串 prompt。 |-r|Raw mode. 不把反斜杠字符解释为转义字符。 |-s|Silent mode. 不会在屏幕上显示输入的字符。当输入密码和其它确认信息的时候,这会很有帮助。 |-t seconds|超时. 几秒钟后终止输入。若输入超时,read 会返回一个非零退出状态。 |-u fd|使用文件描述符 fd 中的输入,而不是标准输入。 -t和-sp 选项,读取“秘密”输入,在特定的时间内 输入没有完成,就终止输入。 #### IFS **IFS** 的默认值包含一个空格,一个 tab,和一个换行符,每一个都会把 字段分割开。 ``` IFS=":" read user pw uid gid name home shell <<< "$file_info" ``` 这一行由三部分组成:对一个变量的赋值操作,一个带有一串参数的 read 命令,和一个奇怪的新的重定向操作符。这个 `<<<` 操作符指示一个 here 字符串。**不能把 管道用在 read 上**----管道线 会创建子 shell。 #### 菜单 ``` #!/bin/bash # read-menu: a menu driven system information program clear echo " Please Select: 1. Display System Information 2. Display Disk Space 3. Display Home Space Utilization 0. Quit " read -p "Enter selection [0-3] > " if [[ $REPLY =~ ^[0-3]$ ]]; then if [[ $REPLY == 0 ]]; then echo "Program terminated." exit fi if [[ $REPLY == 1 ]]; then echo "Hostname: $HOSTNAME" uptime exit fi if [[ $REPLY == 2 ]]; then df -h exit fi if [[ $REPLY == 3 ]]; then if [[ $(id -u) -eq 0 ]]; then echo "Home Space Utilization (All Users)" du -sh /home/* else echo "Home Space Utilization ($USER)" du -sh $HOME fi exit fi else echo "Invalid entry." >&2 exit 1 fi ``` 第一部分显示菜单和用户输入。第二部分确认用户反馈,并执行 选择的行动。