363 lines
8.4 KiB
Markdown
363 lines
8.4 KiB
Markdown
|
# 原创
|
|||
|
: Shell流程控制:case 分支
|
|||
|
|
|||
|
# Shell流程控制:case 分支
|
|||
|
|
|||
|
## 流程控制:case 分支
|
|||
|
|
|||
|
### case
|
|||
|
|
|||
|
```
|
|||
|
case word in
|
|||
|
[pattern [| pattern]...) commands ;;]...
|
|||
|
esac
|
|||
|
|
|||
|
```
|
|||
|
|
|||
|
```
|
|||
|
#!/bin/bash
|
|||
|
# case-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] > "
|
|||
|
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 Utilization ($USER)"
|
|||
|
du -sh $HOME
|
|||
|
fi
|
|||
|
;;
|
|||
|
*) echo "Invalid entry" >&2
|
|||
|
exit 1
|
|||
|
;;
|
|||
|
esac
|
|||
|
|
|||
|
```
|
|||
|
|
|||
|
### 模式
|
|||
|
|
|||
|
case 语句使用的模式和路径展开中使用的那些是一样的。模式以一个 “)” 为终止符。这里是一些有效的模式。
|
|||
|
|
|||
|
|模式|描述
|
|||
|
|------
|
|||
|
|a)|若单词为 “a”,则匹配
|
|||
|
|[[:alpha:]])|若单词是一个字母字符,则匹配
|
|||
|
|???)|若单词只有3个字符,则匹配
|
|||
|
|*.txt)|若单词以 “.txt” 字符结尾,则匹配
|
|||
|
|*)|匹配任意单词。把这个模式做为 case 命令的最后一个模式,是一个很好的做法, 可以捕捉到任意一个与先前模式不匹配的数值;也就是说,捕捉到任何可能的无效值。
|
|||
|
|
|||
|
```
|
|||
|
#!/bin/bash
|
|||
|
read -p "enter word > "
|
|||
|
case $REPLY in
|
|||
|
[[:alpha:]]) echo "is a single alphabetic character." ;;
|
|||
|
[ABC][0-9]) echo "is A, B, or C followed by a digit." ;;
|
|||
|
???) echo "is three characters long." ;;
|
|||
|
*.txt) echo "is a word ending in '.txt'" ;;
|
|||
|
*) echo "is something else." ;;
|
|||
|
esac
|
|||
|
|
|||
|
```
|
|||
|
|
|||
|
还可以使用竖线字符作为分隔符,把多个模式结合起来。这就创建了一个 “或” 条件模式。这对于处理诸如大小写字符很有用处。例如:
|
|||
|
|
|||
|
```
|
|||
|
#!/bin/bash
|
|||
|
# case-menu: a menu driven system information program
|
|||
|
clear
|
|||
|
echo "
|
|||
|
Please Select:
|
|||
|
A. Display System Information
|
|||
|
B. Display Disk Space
|
|||
|
C. Display Home Space Utilization
|
|||
|
Q. Quit
|
|||
|
"
|
|||
|
read -p "Enter selection [A, B, C or Q] > "
|
|||
|
case $REPLY in
|
|||
|
q|Q) echo "Program terminated."
|
|||
|
exit
|
|||
|
;;
|
|||
|
a|A) echo "Hostname: $HOSTNAME"
|
|||
|
uptime
|
|||
|
;;
|
|||
|
b|B) df -h
|
|||
|
;;
|
|||
|
c|C) 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
|
|||
|
;;
|
|||
|
*) echo "Invalid entry" >&2
|
|||
|
exit 1
|
|||
|
;;
|
|||
|
esac
|
|||
|
|
|||
|
```
|
|||
|
|
|||
|
添加的 “;;&” 的语法允许 case 语句继续执行下一条测试,而不是简单地终止运行。
|
|||
|
|
|||
|
```
|
|||
|
|
|||
|
#!/bin/bash
|
|||
|
# case4-2: test a character
|
|||
|
read -n 1 -p "Type a character > "
|
|||
|
echo
|
|||
|
case $REPLY in
|
|||
|
[[:upper:]]) echo "'$REPLY' is upper case." ;;&
|
|||
|
[[:lower:]]) echo "'$REPLY' is lower case." ;;&
|
|||
|
[[:alpha:]]) echo "'$REPLY' is 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
|
|||
|
|
|||
|
```
|
|||
|
|
|||
|
## 位置参数
|
|||
|
|
|||
|
### 访问命令行
|
|||
|
|
|||
|
shell 提供了一个称为位置参数的变量集合,这个集合包含了命令行中所有独立的单词。这些变量按照从0到9给予命名。
|
|||
|
|
|||
|
```
|
|||
|
#!/bin/bash
|
|||
|
# posit-param: script to view command line parameters
|
|||
|
echo "
|
|||
|
\$0 = $0
|
|||
|
\$1 = $1
|
|||
|
\$2 = $2
|
|||
|
\$3 = $3
|
|||
|
\$4 = $4
|
|||
|
\$5 = $5
|
|||
|
\$6 = $6
|
|||
|
\$7 = $7
|
|||
|
\$8 = $8
|
|||
|
\$9 = $9
|
|||
|
"
|
|||
|
|
|||
|
```
|
|||
|
|
|||
|
```
|
|||
|
[me@linuxbox ~]$ posit-param a b c d
|
|||
|
$0 = /home/me/bin/posit-param
|
|||
|
$1 = a
|
|||
|
$2 = b
|
|||
|
$3 = c
|
|||
|
$4 = d
|
|||
|
$5 =
|
|||
|
$6 =
|
|||
|
$7 =
|
|||
|
$8 =
|
|||
|
$9 =
|
|||
|
|
|||
|
```
|
|||
|
|
|||
|
### shift - 访问多个参数的利器
|
|||
|
|
|||
|
执行一次 shift 命令, 就会导致所有的位置参数 “向下移动一个位置”。
|
|||
|
|
|||
|
```
|
|||
|
#!/bin/bash
|
|||
|
# posit-param2: script to display all arguments
|
|||
|
# 只要参数个数不为零就会继续执行的 while 循环
|
|||
|
count=1
|
|||
|
while [[ $# -gt 0 ]]; do
|
|||
|
echo "Argument $count = $1"
|
|||
|
count=$((count + 1))
|
|||
|
shift
|
|||
|
done
|
|||
|
|
|||
|
```
|
|||
|
|
|||
|
```
|
|||
|
[me@linuxbox ~]$ posit-param2 a b c d
|
|||
|
Argument 1 = a
|
|||
|
Argument 2 = b
|
|||
|
Argument 3 = c
|
|||
|
Argument 4 = d
|
|||
|
|
|||
|
```
|
|||
|
|
|||
|
### 处理集体位置参数
|
|||
|
|
|||
|
shell 提供了两种特殊的参数,他们二者都能扩展成完整的位置参数列表,但以相当微妙的方式略有不同。
|
|||
|
|
|||
|
|参数|描述
|
|||
|
|------
|
|||
|
|$*|展开成一个从1开始的位置参数列表。当它被用双引号引起来的时候,展开成一个由双引号引起来 的字符串,包含了所有的位置参数,每个位置参数由 shell 变量 IFS 的第一个字符(默认为一个空格)分隔开。
|
|||
|
|$@|展开成一个从1开始的位置参数列表。当它被用双引号引起来的时候, 它把每一个位置参数展开成一个由双引号引起来的分开的字符串。
|
|||
|
|
|||
|
```
|
|||
|
#!/bin/bash
|
|||
|
# posit-params3 : script to demonstrate $* and $@
|
|||
|
print_params () {
|
|||
|
echo "\$1 = $1"
|
|||
|
echo "\$2 = $2"
|
|||
|
echo "\$3 = $3"
|
|||
|
echo "\$4 = $4"
|
|||
|
}
|
|||
|
pass_params () {
|
|||
|
echo -e "\n" '$* :'; print_params $*
|
|||
|
echo -e "\n" '"$*" :'; print_params "$*"
|
|||
|
echo -e "\n" '$@ :'; print_params $@
|
|||
|
echo -e "\n" '"$@" :'; print_params "$@"
|
|||
|
}
|
|||
|
pass_params "word" "words with spaces"
|
|||
|
|
|||
|
```
|
|||
|
|
|||
|
```
|
|||
|
[me@linuxbox ~]$ posit-param3
|
|||
|
$* :
|
|||
|
$1 = word
|
|||
|
$2 = words
|
|||
|
$3 = with
|
|||
|
$4 = spaces
|
|||
|
"$*" :
|
|||
|
$1 = word words with spaces
|
|||
|
$2 =
|
|||
|
$3 =
|
|||
|
$4 =
|
|||
|
$@ :
|
|||
|
$1 = word
|
|||
|
$2 = words
|
|||
|
$3 = with
|
|||
|
$4 = spaces
|
|||
|
"$@" :
|
|||
|
$1 = word
|
|||
|
$2 = words with spaces
|
|||
|
$3 =
|
|||
|
$4 =
|
|||
|
|
|||
|
```
|
|||
|
|
|||
|
### 一个更复杂的应用
|
|||
|
|
|||
|
```
|
|||
|
#!/bin/bash
|
|||
|
# sys_info_page: program to output a system information page
|
|||
|
PROGNAME=$(basename $0)
|
|||
|
TITLE="System Information Report For $HOSTNAME"
|
|||
|
CURRENT_TIME=$(date +"%x %r %Z")
|
|||
|
TIMESTAMP="Generated $CURRENT_TIME, by $USER"
|
|||
|
report_uptime () {
|
|||
|
cat <<- _EOF_
|
|||
|
<H2>System Uptime</H2>
|
|||
|
<PRE>$(uptime)</PRE>
|
|||
|
_EOF_
|
|||
|
return
|
|||
|
}
|
|||
|
report_disk_space () {
|
|||
|
cat <<- _EOF_
|
|||
|
<H2>Disk Space Utilization</H2>
|
|||
|
<PRE>$(df -h)</PRE>
|
|||
|
_EOF_
|
|||
|
return
|
|||
|
}
|
|||
|
report_home_space () {
|
|||
|
if [[ $(id -u) -eq 0 ]]; then
|
|||
|
cat <<- _EOF_
|
|||
|
<H2>Home Space Utilization (All Users)</H2>
|
|||
|
<PRE>$(du -sh /home/*)</PRE>
|
|||
|
_EOF_
|
|||
|
else
|
|||
|
cat <<- _EOF_
|
|||
|
<H2>Home Space Utilization ($USER)</H2>
|
|||
|
<PRE>$(du -sh $HOME)</PRE>
|
|||
|
_EOF_
|
|||
|
fi
|
|||
|
return
|
|||
|
}
|
|||
|
usage () {
|
|||
|
echo "$PROGNAME: usage: $PROGNAME [-f file | -i]"
|
|||
|
return
|
|||
|
}
|
|||
|
write_html_page () {
|
|||
|
cat <<- _EOF_
|
|||
|
<HTML>
|
|||
|
<HEAD>
|
|||
|
<TITLE>$TITLE</TITLE>
|
|||
|
</HEAD>
|
|||
|
<BODY>
|
|||
|
<H1>$TITLE</H1>
|
|||
|
<P>$TIMESTAMP</P>
|
|||
|
$(report_uptime)
|
|||
|
$(report_disk_space)
|
|||
|
$(report_home_space)
|
|||
|
</BODY>
|
|||
|
</HTML>
|
|||
|
_EOF_
|
|||
|
return
|
|||
|
}
|
|||
|
# process command line options
|
|||
|
interactive=
|
|||
|
filename=
|
|||
|
while [[ -n $1 ]]; do
|
|||
|
case $1 in
|
|||
|
-f | --file) shift
|
|||
|
filename=$1
|
|||
|
;;
|
|||
|
-i | --interactive) interactive=1
|
|||
|
;;
|
|||
|
-h | --help) usage
|
|||
|
exit
|
|||
|
;;
|
|||
|
*) usage >&2
|
|||
|
exit 1
|
|||
|
;;
|
|||
|
esac
|
|||
|
shift
|
|||
|
done
|
|||
|
# interactive mode
|
|||
|
if [[ -n $interactive ]]; then
|
|||
|
while true; do
|
|||
|
read -p "Enter name of output file: " filename
|
|||
|
if [[ -e $filename ]]; then
|
|||
|
read -p "'$filename' exists. Overwrite? [y/n/q] > "
|
|||
|
case $REPLY in
|
|||
|
Y|y) break
|
|||
|
;;
|
|||
|
Q|q) echo "Program terminated."
|
|||
|
exit
|
|||
|
;;
|
|||
|
*) continue
|
|||
|
;;
|
|||
|
esac
|
|||
|
fi
|
|||
|
done
|
|||
|
fi
|
|||
|
# output html page
|
|||
|
if [[ -n $filename ]]; then
|
|||
|
if touch $filename && [[ -f $filename ]]; then
|
|||
|
write_html_page > $filename
|
|||
|
else
|
|||
|
echo "$PROGNAME: Cannot write file '$filename'" >&2
|
|||
|
exit 1
|
|||
|
fi
|
|||
|
else
|
|||
|
write_html_page
|
|||
|
fi
|
|||
|
|
|||
|
```
|