#!/bin/bash # 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" exit 1 fi exit
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 1 fi }
#!/bin/bash # test-string: evaluate the value of a string ANSWER=maybe if [ -z "$ANSWER" ]; then echo"There is no answer." >&2 exit 1 fi if [ "$ANSWER" = "yes" ]; then echo"The answer is YES." elif [ "$ANSWER" = "no" ]; then echo"The answer is NO." elif [ "$ANSWER" = "maybe" ]; then echo"The answer is MAYBE." else echo"The answer is UNKNOWN." fi
这个脚本中,我们计算常量 ANSWER。我们首先确定是否此字符串为空。如果为空,我们就终止 脚本,并把退出状态设为1。注意这个应用于 echo 命令的重定向操作。其把错误信息 “There is no answer.” 重定向到标准错误,这是处理错误信息的“正确”方法。如果字符串不为空,我们就计算 字符串的值,看看它是否等于“yes,” “no,” 或者“maybe”。为此使用了 elif,它是 “else if” 的简写。
#!/bin/bash # test-integer2: evaluate the value of an integer. INT=-5 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"INT is not an integer." >&2 exit 1 fi
[[ ]]添加的另一个功能是==操作符支持类型匹配,正如路径名展开所做的那样
这就使[[ ]]有助于计算文件和路径名。
1 2 3
if [[ $FILE == foo.* ]]; then > echo"$FILE matches pattern 'foo.*'" > fi
#!/bin/bash # test-integer2a: evaluate the value of an integer. INT=-5 if [[ "$INT" =~ ^-?[0-9]+$ ]]; then if ((INT == 0)); then echo"INT is zero." else if ((INT < 0)); then echo"INT is negative." else echo"INT is positive." fi if (( ((INT % 2)) == 0)); then echo"INT is even." else echo"INT is odd." fi fi else echo"INT is not an integer." >&2 exit 1 fi
#!/bin/bash # test-integer3: determine if an integer is within a # specified range of values. MIN_VAL=1 MAX_VAL=100 INT=50 if [[ "$INT" =~ ^-?[0-9]+$ ]]; then if [[ INT -ge MIN_VAL && INT -le MAX_VAL ]]; then echo"$INT is within $MIN_VAL to $MAX_VAL." else echo"$INT is out of range." fi else echo"INT is not an integer." >&2 exit 1 fi
我们也可以对表达式使用圆括号,为的是分组。如果不使用括号,那么否定只应用于第一个 表达式,而不是两个组合的表达式。用 test 可以这样来编码:
1 2 3 4 5
if [ ! \( $INT -ge $MIN_VAL -a $INT -le $MAX_VAL \) ]; then echo"$INT is outside $MIN_VAL to $MAX_VAL." else echo"$INT is in range." fi
#!/bin/bash count=1 while [ $count -le 5 ]; do echo$count count=$((count + 1)) done echo"Finished."
只要退出状态为零,它就执行循环内的命令。 在上面的脚本中,创建了变量 count ,并初始化为1。 while 命令将会计算 test 命令的退出状态。 只要 test 命令返回退出状态零,循环内的所有命令就会执行。每次循环结束之后,会重复执行 test 命令。 第六次循环之后, count 的数值增加到6, test 命令不再返回退出状态零,且循环终止。
#!/bin/bash DELAY=3 # Number of seconds to display results # while [[ $REPLY != 0 ]]; do 使用了break这个就没有必要了 whiletrue; do clear cat <<- _EOF_ Please Select: 1. Display System Information 2. Display Disk Space 3. Display Home Space Utilization 0. Quit _EOF_ read -p "Enter selection [0-3] > " if [[ $REPLY =~ ^[0-3]$ ]]; then if [[ $REPLY == 1 ]]; then echo"Hostname: $HOSTNAME" uptime sleep$DELAY continue fi if [[ $REPLY == 2 ]]; then df -h sleep$DELAY continue 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 sleep$DELAY continue fi if [[ $REPLY == 0 ]]; then break fi else echo"Invalid entry." sleep$DELAY fi done echo"Program terminated."
until
until 命令与 while 非常相似,除了当遇到一个非零退出状态的时候, while 退出循环, 而 until 不退出。一个 until 循环会继续执行直到它接受了一个退出状态零。
1 2 3 4 5 6 7 8
#!/bin/bash # until-count: display a series of numbers count=1 until [ $count -gt 5 ]; do echo$count count=$((count + 1)) done echo"Finished."
使用循环读取文件
1 2 3 4 5 6 7 8
#!/bin/bash # while-read: read lines from a file whileread distro version release; do printf"Distro: %s\tVersion: %s\tReleased: %s\n" \ $distro \ $version \ $release done < distros.txt
#!/bin/bash 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$REPLYin 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 命令的最后一个模式,是一个很好的做法, 可以捕捉到任意一个与先前模式不匹配的数值;也就是说,捕捉到任何可能的无效值。
1 2 3 4 5 6 7 8 9
#!/bin/bash read -p "enter word > " case$REPLYin [[: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$REPLYin 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 语句继续执行下一条测试,而不是简单地终止运行。
1 2 3 4 5 6 7 8 9 10 11 12 13 14
#!/bin/bash # case4-2: test a character read -n 1 -p "Type a character > " echo case$REPLYin [[: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
$ for i in distros*.txt; doecho$i; done distros-by-date.txt distros-dates.txt distros-key-names.txt distros-key-vernums.txt distros-names.txt distros.txt distros-vernums.txt distros-versions.txt
命令替换:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16
#!/bin/bash while [[ -n $1 ]]; do if [[ -r $1 ]]; then max_word= max_len=0 for i in $(strings $1); do len=$(echo$i | wc -c) if (( len > max_len )); then max_len=$len max_word=$i fi done echo"$1: '$max_word' ($max_len characters)" fi shift done
在这个示例中,我们要在一个文件中查找最长的字符串。当在命令行中给出一个或多个文件名的时候, 该程序会使用 strings 程序(其包含在 GNU binutils 包中),为每一个文件产生一个可读的文本格式的 “words” 列表。 然后这个 for 循环依次处理每个单词,判断当前这个单词是否为目前为止找到的最长的一个。当循环结束的时候,显示出最长的单词。
如果省略掉 for 命令的可选项 words 部分,for 命令会默认处理位置参数()。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15
#!/bin/bash for i; do if [[ -r $i ]]; then max_word= max_len=0 for j in $(strings $i); do len=$(echo$j | wc -c) if (( len > max_len )); then max_len=$len max_word=$j fi done echo"$i: '$max_word' ($max_len characters)" fi done
正如我们所看到的,我们已经更改了最外围的循环,用 for 循环来代替 while 循环。通过省略 for 命令的 words 列表, 用位置参数替而代之。在循环体内,之前的变量 i 已经改为变量 j。同时 shift 命令也被淘汰掉了。
for: C 语言格式
最新版本的 bash 已经添加了第二种格式的 for 命令语法,该语法相似于 C 语言中的 for 语法格式。 其它许多编程语言也支持这种格式:
1 2 3
for (( expression1; expression2; expression3 )); do commands done
这里的 expression1、expression2和 expression3 都是算术表达式,
在行为方面,这相当于以下构造形式:
1 2 3 4 5
(( expression1 )) while (( expression2 )); do commands (( expression3 )) done