Linux系统学习笔记:BASH编程

来源:互联网 发布:做工瑕疵问题淘宝判罚 编辑:程序博客网 时间:2024/05/28 04:55

     前面两篇总结了shell的交互式环境,shell不仅支持交互式使用,也支持脚本编程,shell脚本可由shell解释器执行。本篇在前面两篇的基础上总结一下BASH编程的知识。

Contents

  • 变量和参数
    • 位置参数
  • 表达式
    • 运算符
  • 控制流
    • if...then
    • for
    • while和until
    • break和continue
    • case
    • select
  • 文件描述符
  • 内置命令
  • shell脚本

变量和参数

上一篇已经介绍了创建变量的方法,本节进一步总结不同类型变量的创建方式。

使用 var=(element element ...) 创建数组变量。引用数组中的元素时使用 ${var[i]} , i 为下标,下标@ 复制原数组,下标 * 也复制原数组,但加双引号时它将原数组作为一个元素。给数组中单个元素赋值时可以用 var[i]=value 。 ${#var[i]} 返回元素的长度, ${#var[*]} 返回数组中元素的个数。

$ array=(Alex Harry Nancy)$ arr1=("${array[@]}")$ arr2=("${array[*]}")$ declare -adeclare -a arr1='([0]="Alex" [1]="Harry" [2]="Nancy")'declare -a arr2='([0]="Alex Harry Nancy")'declare -a array='([0]="Alex" [1]="Harry" [2]="Nancy")'$ array[1]=Jerry$ echo ${array[*]}Alex Jerry Nancy$ echo ${array[@]}Alex Jerry Nancy$ echo ${#array[*]} ${#array[1]}3 5

变量的作用域为当前脚本,可以用 export 声明变量,它将父进程的变量变为对子进程是可用的。函数中的变量默认不是局部的,作用域也为当前脚本,为了避免冲突,可以用 typeset 将它声明为局部变量。

${#var} 返回变量的长度。

${var:-default} 使用变量的值,如果值为空或未赋值,则使用给出的默认值。 ${var:=default} 和前者类似,但它同时会在值为空或未赋值时将默认值赋给变量。 ${var:?message} 可以在值为空或未赋值时显示错误信息,如果未给出 message ,则显示默认错误信息。

$ cd ${dir:?$(date +%T) error, dir not set.}-bash: dir: 10:15:29 error, dir not set.

: 可以给其后的变量赋值但不去执行它,常常用 ${var:=default} 来给变量设置默认值。

BASH中有一种字符串模式匹配,形式为 ${varOPpattern} , OP 为: # 去除最小匹配前缀, ## 去除最大匹配前缀, % 去除最小匹配后缀, %% 去除最大匹配后缀。

$ file=/home/yeolar/a.sh$ echo ${file##/*/}a.sh$ echo ${file%/*}/home/yeolar

((var=base#n)) 语法可以给变量以其他基数赋值。

$ ((n=8#0101)); echo $n65

位置参数

位置参数保存命令和命令后的参数。可以用 set 改变位置参数的内容,但不能在脚本内改变命令名。 $# 保存参数的个数, $0 保存命令名, $1 - $n 保存命令后的参数, $@ 和 $* 保存全部参数,和数组变量类似,加双引号时 $* 作为一个参数,而 $@ 作为一组参数。 shift 左移参数。 set 初始化参数( set 没有参数时显示已设置的shell变量,还可以用它来设置shell特性)。

$ cat a.shecho "cmd: $0, args: $*, argnum: $#"echo "first arg: $1"echo "shift args..."shiftecho "cmd: $0, args: $*, argnum: $#"echo "first arg: $1"set "$@"echo "first arg: $1"set "$*"echo "first arg: $1"set a b cecho $*$ bash a.sh x y zcmd: a.sh, args: x y z, argnum: 3first arg: xshift args...cmd: a.sh, args: y z, argnum: 2first arg: yfirst arg: yfirst arg: y za b c

还有一些特殊参数: $$ 保存当前(shell)进程的PID, $! 保存最近转入后台运行的进程的PID, $? 保存上一个命令的返回状态码。

特殊参数和位置参数不能通过赋值语句改变。

表达式

可以用 let "expr" 或 ((expr)) 对算术表达式求值,多个表达式可以分别用空格和逗号分开。

$ x=1 y=1 z=0$ let "x = x * 10 + y" z=z+1$ echo $x $y $z11 1 1$ ((x = x * 10 + y, z = z + 1))$ echo $x $y $z111 1 2

条件表达式用 [[expr]] 求值。有个比较特别的运算符是 = ,在条件表达式中可以用它来判断相等。

运算符

BASH支持绝大部分C语言的运算符,有些运算符增加了一些特定语法结构中的含义,如管道。

控制流

if...then

if...then 的语法如下:

 if test-command then     command[elif test-command then     command ...][else     command] fi

为了减少缩进,常常用 ; 将 then 写到上一行。

test-command 为测试命令,可以用 test 命令进行测试,但一般使用它的同义词 [] 。

# 检查参数个数if [ $# -eq 0 ]; then             # 等价于:if test $# -eq 0; then    echo "Usage: cmd arg" 1>&2    exit 1fi

对于数值的测试,可以使用:

-eq等于-ne不等于-gt大于-ge大于等于-lt小于-le小于等于

字符串的比较可以使用 = 和 != 。

下面是一些和文件相关的检查选项:

-e检查文件是否存在-d检查文件是否存在且是目录-f检查文件是否存在且是普通文件-s检查文件是否存在且大于0字节-r检查文件是否存在且可读-w检查文件是否存在且可写-x检查文件是否存在且可执行

for

for 的语法如下:

for var[ in list]do    commanddone

seq 为可展开为列表的表达式。可以省略 in list ,这时列表为命令的参数,即 $@ 。

# whos脚本,打印用户名和全名 Usage: whos user ...for user; do    gawk -F: '{print $1, $5}' /etc/passwd |    grep -i "$user"done

while和until

while 和 until 类似,区别是 until 在 do 分支执行后测试,并且是测试结果为假时循环,测试结果为真时跳出循环。

语法为:

while test-commanddo    commanddoneuntil test-commanddo    commanddone
# 查找拼写错误的词while read line; do    if ! grep "^$line$" "$1" > /dev/null; then        echo $line    fidone# 猜名字rightname=yeolaruntil [ "$name" = "$rightname" ]; do    echo -n "Guess: "    read namedoneecho "Good, you've got it."

break和continue

break 和 continue 可以用于在 for 、 while 和 until 语句中跳出循环和继续下一循环。

case

case 用于多路选择。语法为:

case test-command in    pattern)        command        ;;   [pattern)        command        ;;    ...]esac

pattern 可以使用 * 匹配任意字符串, ? 匹配单个字符, [...] 给出可匹配的字符, | 分离不同的选择。

# 命令选择echo -e "\ncmds: A for date, B for who, C for pwd.\n"echo -n "Enter A, B or C: "read ccase "$c" in    a|A)        date        ;;    b|B)        who        ;;    c|C)        pwd        ;;    *)        echo "Invalid choice: $c"        ;;esac

select

select 显示一个菜单,根据用户的选择给变量赋予相应的值,然后执行命令。退出 select 可以使用 break,或者 exit 退出整个脚本。

select var[ in list]do    commanddone

和 for 一样,省略 in list 会用命令参数代替。 PS3 设置 select 的提示符,一般会设置为需要的提示语句。

# 命令菜单PS3="Choose what you want to do: "select c in date who pwd exit; do    if [ "$c" == "" ]; then        echo -e "Invalid choice.\n"        continue    elif [ $c = exit ]; then        echo "quit"        break    fi    echo "You choose: $c"    if [ $c = date ]; then        date    elif [ $c = who ]; then        who    elif [ $c = pwd ]; then        pwd    fi    echo ""done

文件描述符

在BASH中,使用 exec 命令执行文件描述符相关的操作:

exec n> outfile    打开outfile作为输出文件,分配文件描述符nexec n< infile     打开infile作为输入文件,分配文件描述符nexec n<&m          打开或重定向文件描述符n,作为文件描述符m的副本exec n<&-          关闭文件描述符n

内置命令

前面已经提到了很多BASH内置命令,这里做个总结和补充。

:返回0或 true (置空内部命令).把shell脚本当作当前进程的一部分执行bg挂起任务break跳出循环cd改变工作目录continue继续下一循环echo显示eval扫描并计算命令行exec执行shell脚本或程序并替换掉当前进程exit从当前shell退出export将变量放到被调用的环境中fg将后台任务移到前台getopts分析读取shell脚本的参数jobs列出后台任务kill向进程或作业发送信号pwd显示当前工作目录read从标准输入中读一行readonly声明变量为只读set列出全部变量,设置shell特性,设置命令行参数shift左移命令行参数test比较times显示当前shell及其子进程的运行时间trap捕获信号type显示参数给出的命令的相关信息umask返回文件创建的掩码,设置掩码unset删除变量或函数wait等待后台进程结束

read 支持一些选项:

-a array输入的单词作为 array 的元素-d delim使用 delim 代替换行来终止输入-e使用Readline库来获取输入(输入来自键盘时)-n num读取 num 个字符后返回-p promptprompt 作为输入的提示信息-s在终端上不打印字符-un从文件描述符为n的文件输入

有个特殊的变量 REPLY ,保存读取的输入。

getopts 的语法为 getopts optstr var[ arg ...] , optstr 给出合法的字母选项, var 保存每次接收的选项的值, arg 为将处理的参数,省略将默认处理命令行参数。 optstr 以 : 开始时由脚本负责产生错误信息,否则由 getopts 自己产生。 optstr 用字母后的 : 表示选项接受值, OPTARG 保存和选项相关的值。OPTIND 保存选项的索引,起始值为1。

exec 既可执行脚本又可执行程序,它不创建新进程,把当前(shell)进程替换为要执行的内容。

trap 的用法是 trap ['command'] [signal] ,它捕获信号,执行 command ,如果没有 command ,那么重置trap 。

trap '' 2 15                            # 捕获并忽略中断trap 'echo Interrupted.; exit 1' INT    # 捕获中断,打印信息并退出

kill 给进程发送信号,如终止进程。后面会详细讲有关进程的内容。

shell脚本

根据本篇介绍的内容和前两篇的一些知识就可以编写shell脚本了。

像Python脚本一样可以用 #! 为脚本定义解释器。

#!/bin/bash# 或者:#!/usr/bin/env bash
链接: http://www.yeolar.com/note/2012/03/09/linux-bash-programming/
原创粉丝点击