shell 脚本编程
变量赋值
(1) 直接赋值,如name="root"
(2) 将变量值赋值,如username="$USER"
(3) 将命令的结果赋值,如date=$(date +%F)
,$()可以用一对反向单引号代替``
- 变量弱引用" “,双引号内的变量引用会被替换为变量值
- 变量强引用’ ‘,单引号内的变量引用会保持原样的字符串
bash中的变量的种类
根据变量的生效范围等标准:
本地变量:生效范围为当前shell进程;对当前shell之外的其它shell进程,包括当前shell的子shell进程均无效;
环境变量:生效范围为当前shell进程及其子进程;
局部变量:生效范围为当前shell进程中某代码片断(通常指函数);
位置变量:
1$1, $2, ...来表示,用于让脚本在脚本代码中调用通过命令行传递给它的参数;
特殊变量:
1$?, $0, $*, $@, $#
本地变量
- 变量赋值 name=value
- 变量引用
1 ${name}, $name
- 查看变量:set
- 撤销变量 : unset name
- bash 开启子shell , 子shell 中无法获得父shell中的变量
环境变量
-
变量声明、赋值:
-
export name=VALUE
-
name=value
export name
-
declare -x name=VALUE
-
name=value
declare -x name
-
变量引用:
1$name, ${name}
-
-
显示所有环境变量:
1env 2printenv 3declare -x
-
销毁: unset name
-
bash有许多内建的环境变量:PATH, SHELL, UID, HISTSIZE, HOME, PWD, OLD, HISTFILE, PS1
1username=maozhongyu 2export username 3bash 4echo $username # maozhongyu 子shell中也生效 5username='maodada' 6exit 7echo $username # maozhongyu 子shell修改全局变量并不会影响父shell的值, 8bash 9username='maotiantian' 10export username 11exit 12echo $username #maozhongyu 13# 子shell重新定义username,并导出变量,但父shell 中的username 还是maozhongyu 另外子shell unset 变量,无法影响父shell
只读变量
只读变量定义后不能修改、不能删除,随所在进程的结束而清除
声明方式2种:
11.readonly name
2
3#username=maozhongyu
4#readonly username
5#username=maozhongyu1
6-bash: name: readonly variable
7
82. declare -r name
9 unset name //取消
数组变量
1mytest=(one two three four five)
2echo $mytest # one
3echo ${mytest[2]} #three
4echo ${mytest[*]} # one two three four five
5mytest[2]=seven # 修改某个下标
6echo ${mytest[*]} #one two seven four five
7unset mytest[2]
8echo ${mytest[*]} #one two four five
9# 下表还是保持删除前的
10echo ${mytest[3]} #four
11unset mytest #删除整个数组
位置变量和特殊变量
位置变量和特殊变量
1 $# 是传给脚本的参数个数
2 $0 是脚本本身的文件名
3 $1 是脚本后接的第一个参数
4 $2 是脚本后接的第二个参数
5 $@ 是传给脚本的所有参数列表,"$1" "$2" "$3" … "$n"
6 $* 是以一个单字符串显示传给脚本的所有参数,"$1 $2 $3 … $n"
7 $$ 是脚本运行的当前进程ID号
8 $? 是最后运行命令的结束状态码,0表示没有错误,1-255代表出现错误
9 ${!#} 返回最后一个参数(没有参数就是$0)
10 shift 造成参数变量号码偏移,第二个参数变为$1,以此类推。
11 - shift [n]:所有参数向左移动n位,$1至$n抛弃
12 set -- 清空所有位置变量
调试及注意点
检查脚本语法错误 bash -n scriptname
调试执行 bash -x scriptname
注意点:
11. $10表达的意思是地址变量$1的值和字符0,${10}表达的意思是第10个地址变量。
2
3 使用地址变量时当超出10个时要注意加大括号。
4
52. bash和绝对路径及相对路径打开脚本时开了一个子进程,不影响当前进程;source打开脚本时仍
6 然是在当前进程下,会影响当前进程。所以打开脚本时尽量不要用source。
7
83. 脚本里不识别别名
9
104. 本地变量和环境变量的区别
11
12 本地变量:只对当前shell有效
13
14 环境变量:父进程定义的变量可以传给子进程,但子进程定义的变量无法传给父进程。
15
165. 如果定义的变量值为多行,echo打印时要加上双引号,否则显示的是一行。
17
186. 声明只读变量后不能修改,不能取消,只能退出后才能取消,如果先定义为只读变量,就无法给只读变量赋值了。
19
207. 小括号的作用
21
22 小括号相当于开了一个子进程,只对当前括号里的环境有效,外面的环境相当于父进程,父进程定义的变量可以传给小括号,而小括号内定义的变量无法传给外面的父进程。
shell脚本的输入输出
echo
语法:echo [-neE][字符串]
echo会将输入的字符串送往标准输出。输出的字符串间以空白字符隔开, 并在最后加上换行号
选项参数
- -E (默认)不支持\解释功能
- -n 不自动换行
- e 启用\字符的解释功能
输出颜色,\033[0m 关闭颜色,恢复正常
1➜ ~ echo '\033[34mhello\033[0m'
2hello
3➜ ~ echo '\033[31mhello\033[0m'
4hello
5➜ ~ echo '\033[32mhello\033[0m'
6hello
printf
1name=maozhongyu
2age=12
3printf "name=%s,age=%d" $name $age
read
-p 指定要显示的提示
-s 静默输入,用于密码输入
-n N 指定输入的字符长度N
-d char 自定输入的结束符
-t N timeout为N秒
read从标准输入读入多个单词,每个单词一个变量,若变量个数少于单词数,则多出的单词也赋给最后一个变量
1read name
2# 输入
3echo $name
4
5echo -n "Enter a user name:"; read name
6read -p "Enter a user name:" name
7#maozhongyu
8
9echo $name
10read -p "enter a user name " -t 5 name ##超时,name 为 空
«
1cat <<EOF
2 内容
3EOF
退出状态码
- 进程通过退出状态报告进程运行成功或失败
echo $?
查看上一条命令执行的退出状态- 0代表运行成功,1-255代表运行失败
exit [n]
自定义退出状态码- 如果未指定退出状态码,脚本运行结束后的退出状态码为执行脚本最后一条命令的退出状态码
算术运算
运算符号:+(加),-(减),*(乘),/(除),%(取余),**(乘方)
11. let varName=算术表达式
2num1=7;
3num2=6;
4let sum=$num1+$num2;
5echo $sum;
6
72. varName=$[算术表达式]
8num1=7;
9num2=6;
10varName=$[$num1+$num2]
11echo $varName
12
133. varName=$((算术表达式))
14
154. varName=`expr $num1 + $num2`
16# 注意空格 必须空
17
185.declare -i sum=0;
bash内建有随机数生成器$RANDOM,可以用于生成一定范围的随机数,
如生成2-50的随机数
1a=$[$RANDOM%49+2]
2echo $a
增强型赋值:+=,-=,*=,/=,%=,例如a+=3等于a=a+3,其他符号类似
自增、自减:++,–,例如a++,b–
自增自减运算符在变量前后可能导致不同的结果,运算符在前如++a表示对变量a自增1再进行其他操作,运算符在后如b–表示对变量b先进行其他操作再自减1
字符串操作
输出字符串的长度
1a='abc'
2echo ${#a} #3
3b=`expr length $a` #3
取子串的操作
1`expr substr $string $position $length` 位置编号从1开始
2`echo ${string:position:length}` 位置从0开始
3
4a='abc'
5expr substr $a 1 1 //a
6echo ${string:0:1} //a 下标从0开始
字符串连接
1str1='abc'
2str2='def'
3echo $str1$str2
字符串替换
1str1='you and you abcdef'
2echo ${str1/you/You} #只替换一次
3echo ${str1//you/You} #全部替换
字符串切片
1${var:offset:number}
2取字符串的子串;
3取字符趾的最右侧的几个字符:${var: -length}
4注意:冒号后必须有一个空白字符;
基于模式取子串
${var#*word}:其中word是指定的分隔符;功能:自左而右,查找var变量所存储的字符串中,第一次出现的word分隔符,删除字符串开头至此分隔符之间的所有字符;
${var##*word}:其中word是指定的分隔符;功能:自左而右,查找var变量所存储的字符串中,最后一次出现的word分隔符,删除字符串开头至此分隔符之间的所有字符;
${var%word*}:其中word是指定的分隔符;功能:自右而左,查找var变量所存储的字符串中,第一次出现的word分隔符,删除此分隔符至字符串尾部之间的所有字符;
${var%%word*}:其中word是指定的分隔符;功能:自右而左,查找var变量所存储的字符串中,最后一次出现的word分隔符,删除此分隔符至字符串尾部之间的所有字符;
1mypath="/etc/init.d/functions"
2echo ${mypath##*/} # functions
3echo ${mypath#*/} #etc/init.d/functions
4echo ${mypath%/*} # /etc/init.d
5
6url=http://www.crblog.cc:80
7echo ${url##*:} # 80
8echo ${url%%:*} # http
查找删除
${var/PATTERN}:以PATTERN为模式查找var字符串中第一次的匹配,并删除之;
${var//PATERN}
${var/#PATTERN}
${var/%PATTERN}
字符大小写转换
${var^^}:把var中的所有小写字符转换为大写;
${var,,}:把var中的所有大写字符转换为小写;
变量赋值 (默认值)
${var:-VALUE}:如果var变量为空,或未设置,那么返回VALUE;否则,则返回var变量的值;
${var:=VALUE}:如果var变量为空,或未设置,那么返回VALUE,并将VALUE赋值给var变量;否则,则返回var变量的值;
${var:+VALUE}:如果var变量不空,则返回VALUE;
${var:?ERROR_INFO}:如果var为空,或未设置,那么返回ERROR_INFO为错误提示;否则,返回var值;
比较操作
1test 123 -eq 1234
2echo $? # 比较成功返回0
逻辑运算
逻辑运算的结果只有true或false,但是不同情况下对true或false的数字描述不同
与运算:只有均为true,结果才为true,否则结果均为false
或运算:只有均为false,结果才为false,否则结果均为true
非运算:true取非结果为false,false取非结果为true
短路与 &&:第一个为0,第二个跳过计算,结果一定为0; 第一个为1,继续计算第二个,才能计算出结果
短路或 ||: 第一个为1,第二个跳过计算,结果一定为1; 第一个为0,继续计算第二个,才能计算出结果
异或^:相同为假,不同为真,异或可以用于交换两个值
1a=5;b=3
2a=$[a^b]
3b=$[a^b]
4a=$[a^b]
5echo $a #3
6echo $b #5
条件测试
1test expression
2数值比较
3字符串比较
4文件比较
5
6[ expression]
7数值比较
8字符串比较
9文件比较
10
11
12((expression ))
13
14expression:任意的数学赋值或比较表达式 如果表达式中有大于 小于符号 不需要转义。
15
16[[ expression ]]
17
18使用了test命令中采用的标准字符串比较, 但它提供了test命令未提供的另一个特性-模式匹配 ,括号内的expression前后都需要有空格。
数值比较
1n1 -eq n2 等于
2n1 -ge n2 大于等于
3n1 -gt n2 大于
4n1 -le n2 小于等于
5n1 -lt n2 小于
6n1 -ne n2 是否不等于
7-v VAR 变量VAR是否设置
字符串比较
1test $str1=$str2
2str1 == str2 相等
3str1 != str2
4str1 < str2 str是否比str2小 (在bash中小写字母大于大写字母)
5str1 > str2
6-n str1 长度是否非0
7-z str1 长度是否为0
8=~ 左侧是字符串,右侧是一个模式,判定左侧的字符串能否被右侧的模式所匹配,
9 通常只在[[]]中使用模式中可以使用行首,行尾锚定符;但模式不要加引号
10
11notice: [ $val1 \< $val2 ] 小于符号要转义
字符串测试中的操作数都需要打引号,才能确保结果正确
可以看出变量var非空时为真,空时为假
变量abc为空,测试时使用-n选项应该非空为真,空为假,不会执行第二条命令打印true。但是当变量未有引号包含时,执行打印true,显然不对。变量有引号包含后,第二条命令不运行,符合预期。所以在字符串测试中一定要对变量打引号。
文件测试
- -a file 测试文件是否存在
- -e file 测试文件是否存在
- -f /path/to/file 测试是否是普通文件
- -d /path/to/somefile 测试是否是目录文件
- -b /path/to/somefile 测试文件是否存在并且是否是一个块设备文件
- -c /path/to/comefile 字符 设备文件;
- -p /path/to/somefile :管道文件;
- -s /path/to/somefile 测试文件是否存在并且不空
- -S /path/to/somefile 测试文件是否为套接字文件;
- -h|-L /path/to/somefile 测试文件是否存在并且为链接文件
文件权限测试
- -r /path/to/somefile 测试其执行者是否对此文件有读取权限
- -w /path/to/somefile 写权限
- -x /path/to/somefile 执行权限
文件特殊权限测试
- -u 是否存在且拥有suid权限
- -g 是否存在且拥有sgid权限
- -k 是否存在且拥有sticky权限
文件属性测试
- -O 文件上一次被读取后是否被修改过,即mtime是否新于atime
- -U 当前用户是否为文件属主
- -G 当前用户是否为文件属组
双目测试
- file1 -ef file2 两个文件是否属于相同分区同一个inode号
- file1 -nt file2 file1是否新于file2,比较mtime
- file1 -ot file2 file1是否旧于file2,比较mtime
bash展开命令行的顺序
把命令行分成单个命令词
展开别名
展开大括号的声明 {}
展开波浪符声明 ~
命令替换 $()和``
再次把命令行分成命令词
展开文件通配 *、?、[abc]等等
准备I/0重导向 <、>
运行命令
bash的退出任务
退出任务保存在~/bash_logout文件中
在退出登录的shell时运行~/bash_logout文件
可用于退出后创建自动备份、清除临时文件等功能
选择执行:if 语句
1单分支:
2if 判断条件; then
3 判断条件为真的代码
4fi
5
6双分支:
7if 判断条件; then
8
9 判断条件为真的代码
10else
11 判断条件为假的代码
12fi
13
14多分支:逐条件判断,直到满足条件执行分支代码,忽略之后的条件判断
15if 判断条件1; then
16 判断条件1为真的代码
17elif 判断条件2; then
18 判断条件2为真的代码
19elif 判断条件3; then
20 判断条件3为真的代码
21...
22else
23 上述所有条件为假的代码
24fi
case 语句
1case 变量引用 in
2PAT1)
3 分支语句1
4 ;;
5PAT2)
6 分支语句2
7 ;;
8PAT3)
9 分支语句3
10 ;;
11...
12*)
13 默认分支语句
14 ;;
15esac
16
17PAT:支持glob通配符
18*:任意长度任意字符
19?:任意单个字符
20[]:指定范围内的任意单个字符
21a|b:a或b
for 语句
循环结构的基本组成:初始值、循环开始和结束条件、循环体
语法:
1for 变量名 in 列表; do
2循环体
3done
-
列表生成方式: 直接给出列表
整数列表: {start..end}, {start..end…step}
返回列表的命令:$(COMMAND) 或
COMMAND
,如 $(seq start step end) -
使用glob
-
变量引用:
1$@, $*
-
特殊用法(双小括号方法):
双小括号法:用两组括号嵌套(()),可以实现C语言风格变量操作,如
-
let i++等同于((i++))
-
for 循环的特殊格式
语法:
1for ((控制变量初始化;条件判断表达式;控制变量的修正表达式)); do 2 循环体 3done
分隔符
bash shell 默认会将 空格,制表符,换行符 作为字段分隔符
临时修改分隔符
1IFS=$'\n' #那么只采用换行符做分隔了。
2IFS=: # 采用冒号做分隔
3IFS=$'\n':;" #那么 换行符,冒号,封号,双引号 都是分隔符号
处理代码较大的脚本,分隔用到多次。
1IFS.OLD=$IFS
2IFS=$'\n'
3# 代码块
4# 改回原来的
5IFS=$IFS.OLD
循环控制:while 语句和until 语句
1while CONDITON ; do
2 循环体
3done
1until CONDITION ; do
2 循环体
3done
4CONDITION循环控制条件
5值为false时执行循环体,当值为true时,终止循环
6
7进入条件:CONDITION=false
8退出条件:CONDITION=true
9
10无限循环:
11until false; do
12 COMMANDs
13done
循环控制:continue, break, shift语句
-
continue 语句
continue [N]:提前结束第N层的本轮循环,而直接进入下一轮判断
最内层为第1层
不写层数默认为第1层
-
break 语句
break [N]:提前结束第N层循环
最内层为第1层
不写层数默认为第1层
-
shift 语句
语法:shift [N]
用于将参数列表左移N次,缺省为左移一次
参数列表一旦被移动,最左端的那个参数就从列表中删除
while 循环遍历位置参量列表时,常用到shift
函数:function
函数的生命周期:每次被调用时创建,返回时终止;
其状态返回结果为函数体中运行的最后一条命令的状态结果;
自定义状态返回值,需要使用:return
return [0-255]
- 0: 成功
- 1-255: 失败
语法
1语法一:
2 function f_name {
3 ...函数体...
4 }
5
6语法二:
7 f_name() {
8 ...函数体...
9 }
例子:
给定一个用户名,取得用户的id号和默认shell;
1userinfo() {
2 if id "$username" &> /dev/null; then
3 grep "^$username\>" /etc/passwd | cut -d: -f3,7
4 else
5 echo "No such user."
6 fi
7}
8username=$1
9userinfo
10username=$2
11userinfo
函数返回值
(1) 使用echo或printf命令进行输出;
(2) 函数体中调用的命令的执行结果;
函数的退出状态码:
(1) 默认取决于函数体中执行的最后一条命令的退出状态码;
(2) 自定义:return
函数可以接受参数:
传递参数给函数:
在函数体中当中,可以使用$1,$2, ...引用传递给函数的参数;还可以函数中使用$*或$@引用所有参数,$#引用传递的参数的个数;
在调用函数时,在函数名后面以空白符分隔给定参数列表即可,例如,testfunc arg1 arg2 arg3 ...
函数递归
函数直接或间接调用自身;
10!=10*9!=10*9*8!=10*9*8*7!=...
n*(n-1)!=n*(n-1)*(n-2)!=
1fact() {
2 if [ $1 -eq 0 -o $1 -eq 1 ]; then
3 echo 1
4 else
5 echo $[$1*$(fact $[$1-1])]
6 fi
7}
8fact $1
select 语句
1select variable in list; do
2 循环体命令
3done
select 循环主要用于创建菜单,按数字顺序排列的菜单项将显示在标准错误上,并显示PS3 提示符,等待用户输入
用户输入菜单列表中的某个数字,执行相应的命令
用户输入被保存在内置变量REPLY 中
select是个无限循环,因此要记住用break命令退出循环,或用exit命令终止脚本,也可以按ctrl+c退出循环
select经常和case联合使用
实验:实现一个菜单,输入菜单编号显示价格,不存在的菜单号显示"wrong menu"并退出
1序号 菜名 价格
21 lamian 10
32 huimian 10
43 yangroutang 20
54 gaifan 15
65 jiaozi 20
1#! /bin/bash
2PS3="please type the menu num: " # 环境变量PS3指定提示符格式
3select menu in lamian huimian rangroutang gaifan jiaozi; do
4 case $REPLY in # 用户的输入自动存入REPLY变量中
5 1)
6 echo "the price of lamian is \$10"
7 ;;
8 2)
9 echo "the price of huimian is \$10"
10 ;;
11 3)
12 echo "the price of rangroutang is \$20"
13 ;;
14 4)
15 echo "the price of gaifan is \$15"
16 ;;
17 5)
18 echo "the price of jiaozi is \$20"
19 ;;
20 *)
21 echo "wrong menu"
22 break # select语句默认无限循环,需要有break命令退出循环
23 ;;
24 esac
25done
数组
1数组名[索引]
2
3${ARRAY_NAME[INDEX]}
注意:bash-4及之后的版本,支持自定义索引格式,而不仅仅是0,1,2,…数字格式;此类数组称之为“关联数组”
声明数组
1declare -a NAME:声明索引数组;
2declare -A NAME:声明关联数组;
数组中元素的赋值方式
1(1) 一次只赋值一个元素;
2 ARRAY_NAME[INDEX]=value
3(2) 一次赋值全部元素;
4 ARRAY_NAME=("VAL1" "VAL2" "VAL3" ...)
5(3) 只赋值特定元素;
6 ARRAY_NAME=([0]="VAL1" [3]="VAL4" ...)
7 注意:bash支持稀疏格式的数组;
8(4) read -a ARRAY_NAME
引用数组中的元素
1${ARRAY_NAME[INDEX]} 注意:引用时,只给数组名,表示引用下标为0的元素;
2数组的长度(数组中元素的个数):
3 ${#ARRAY_NAME[*]}
4 ${#ARRAY_NAME[@]}
引用数组中的所有元素
1${ARRAY_NAME[*]}
2${ARRAY_NAME[@]}
数组元素切片
1${ARRAY_NAME[@]:offset:number}
2
3offset:要路过的元素个数;
4
5number:要取出的元素个数;省略number时,表示取偏移量之后的所有元素;
数组添加,删除元素
向非稀疏格式数组中追加元素:
ARRAY_NAME[${#ARRAY_NAME[*]}]=
删除数组中的某元素:
unset ARRAY[INDEX]
关联数组
1declare -A ARRAY_NAME
2ARRAY_NAME=([index_name1]="value1" [index_name2]="value2" ...)
数组练习
生成10个随机数,并找出其中的最大值
1declare -a rand
2declare -i max=0
3
4for i in {0..9}; do
5 rand[$i]=$RANDOM
6 echo ${rand[$i]}
7 [ ${rand[$i]} -gt $max ] && max=${rand[$i]}
8done
9echo "MAX: $max"
定义一个数组,数组中的元素是/var/log目录下所有以.log结尾的文件;统计其下标为偶数的文件中的行数之和;
1#!/bin/bash
2declare -a files
3files=(/var/log/*.log)
4declare -i lines=0
5for i in $(seq 0 $[${#files[*]}-1]); do
6 if [ $[$i%2] -eq 0 ]; then
7 let lines+=$(wc -l ${files[$i]} | cut -d' ' -f1)
8 fi
9done
10echo "Lines: $lines.
在bash中使用ACSII颜色
1\033[31m hello \033[0m
2##m:
3 左侧#:
4 3:前景色
5 4:背景色
6 右侧#:颜色种类
7 1, 2, 3, 4, 5, 6, 7
8
9#m:
10 加粗、闪烁等功能;
11
12多种控制符,可组合使用,彼此间用分号隔开;
信号捕捉
列出信号:
- trap -l
- kill -l
- man 7 signal
trap ‘COMMAND’ SIGNALS
常可以进行捕捉的信号: HUP, INT
示例:
1#!/bin/bash
2 #
3 declare -a hosttmpfiles
4 trap 'mytrap' INT
5
6 mytrap() {
7 echo "Quit"
8 rm -f ${hosttmpfiles[@]}
9 exit 1
10 }
11
12
13 for i in {1..50}; do
14 tmpfile=$(mktemp /tmp/ping.XXXXXX)
15 if ping -W 1 -c 1 172.16.$i.1 &> /dev/null; then
16 echo "172.16.$i.1 is up" | tee $tmpfile
17 else
18 echo "172.16.$i.1 is down" | tee $tmpfile
19 fi
20 hosttmpfiles[${#hosttmpfiles[*]}]=$tmpfile
21 done
22
23 rm -f ${hosttmpfiles[@]}
练习
ping主机
ping命令去查看172.16.1.1-172.16.67.1范围内的所有主机是否在线;在线的显示为up, 不在线的显示down,分别统计在线主机,及不在线主机数;
分别使用for, while和until循环实现。
1#!/bin/bash
2
3declare -i uphosts=0
4declare -i downhosts=0
5
6for i in {1..17}; do
7 if ping -W 1 -c 1 172.16.$i.1 &> /dev/null; then
8 echo "172.16.$i.1 is up."
9 let uphosts+=1
10 else
11 echo "172.16.$i.1 is down."
12 let downhosts+=1
13 fi
14done
15
16echo "Up hosts: $uphosts, Down hosts: $downhosts."
1#!/bin/bash
2 #
3declare -i uphosts=0
4declare -i downhosts=0
5declare -i i=1
6
7hostping() {
8 if ping -W 1 -c 1 $1 &> /dev/null; then
9 echo "$1 is up."
10 return 0
11 else
12 echo "$1 is down."
13 return 1
14 fi
15}
16
17while [ $i -le 67 ]; do
18 hostping 172.16.$i.1
19 [ $? -eq 0 ] && let uphosts++ || let downhosts++
20 let i++
21done
22
23echo "Up hosts: $uphosts, Down hosts: $downhosts."
写一个服务框架脚本
$lockfile, 值/var/lock/subsys/SCRIPT_NAME
(1) 此脚本可接受start, stop, restart, status四个参数之一;
(2) 如果参数非此四者,则提示使用帮助后退出;
(3) start,则创建lockfile,并显示启动;stop,则删除lockfile,并显示停止;restart,则先删除此文件再创建此文件,而后显示重启完成;status,如果lockfile存在,则显示running,否则,则显示为stopped.
1#!/bin/bash
2#
3# chkconfig: - 50 50 //开机启动顺序50 关机启动顺序50 - 默认运行级别2,3,4,5
4# description: test service script
5#
6prog=$(basename $0)
7lockfile=/var/lock/subsys/$prog
8
9case $1 in
10start)
11 if [ -f $lockfile ]; then
12 echo "$prog is running yet."
13 else
14 touch $lockfile
15 [ $? -eq 0 ] && echo "start $prog finshed."
16 fi
17 ;;
18stop)
19 if [ -f $lockfile ]; then
20 rm -f $lockfile
21 [ $? -eq 0 ] && echo "stop $prog finished."
22 else
23 echo "$prog is not running."
24 fi
25 ;;
26restart)
27 if [ -f $lockfile ]; then
28 rm -f $lockfile
29 touch $lockfile
30 echo "restart $prog finished."
31 else
32 touch -f $lockfile
33 echo "start $prog finished."
34 fi
35 ;;
36status)
37 if [ -f $lockfile ]; then
38 echo "$prog is running"
39 else
40 echo "$prog is stopped."
41 fi
42 ;;
43*)
44 echo "Usage: $prog {start|stop|restart|status}"
45 exit 1
46esac
set
1set -e # 遇到错误停止执行
2set +e #继续执行
declare
1declare -i 指定整形 -r 只读变量 -a 指定数组 -f 指定函数名
2
3declare # 输出系统中定义读变量
文件描述符
1echo "你好" > /tmp/file1.txt
2# 0 标准输入
3# 1 标准输出
4# 2 错误输出
5
6# 定义4 输入, 输入给/tmp/file1.txt
7#exec 4</tmp/file1.txt
8#exec 5>/tmp/file2.out
9#
10#while read line
11#do
12# echo "文件内容: $line"
13#done <&4
14#
15## exec M >&N M,N都是文件描述符
16#exec >&5 # > 等价于 1> 定义标准输出到 5的文件描述符
17#echo "hello" #输出到标准输出 , 会输出到 /tmp/file1.txt
18#
19#exec 2>&5 # 错误输出到5的文件描述符
20#
21#
22#exec 6<>/tmp/file.in.out # 既可以是输入也可以是输出
23#
24#exec 4<&- # 关闭文件描述符
25#exec 5>&- # 关闭文件描述符
26#exec 6<>&- # 关闭文件描述符
27#
28
29# 建立一个管道
30pipe_path=/tmp/pipe1
31[ -e ${pipe_path} ] || mkfifo $pipe_path
32exec 7<>${pipe_path}
33fo i in `seq 1 5`
34do
35 echo "向管道写入hello$i"
36 echo "hello$i" >&7
37 read -u7 name
38 echo "从管道中读取内容: $name"
39done