(1)执行
sudo dpkg-reconfigure dash
(2)在弹出的对话框中选择No
(1)由字母、数字、下划线组成,数字不能作为开头。
(2)通过 “=” 来定义一个变量的值
myname='galley' # 字符串类型,不解析任何字符
courses="math" # 双引号内部会解析$和反斜杠特殊字符
sum=100;price=1.2544
now_date=`date` # 反引号执行系统命令
shell的变量类型只有字符串类型,所以当你不使用引号引起来的时候,就要保证变量的值不包含特殊的符号,如空格、$、&符。
(1)变量的引用,使用$
加变量名,来引用一个变量的值
# 定义变量
programe_name="httpd"
# 引用变量
echo $programe_name
echo ${programe_name}
(2)变量名外的花括号是可选的,加花括号是为了帮助解释器识别变量的边界,比如下面这种情况。
#!/bin/sh
for skill in php java linux db2
do
# 帮助shell解释器识别边界
echo "I am good at ${skill}Script"
done
ubantu@ubantu-virtual-machine:~$ sh test.sh
I am good at phpScript
I am good at javaScript
I am good at linuxScript
I am good at db2Script
(3)如果不加{}
,运行结果如下:
#!/bin/sh
for skill in php java linux db2
do
# 帮助shell解释器识别边界
echo "I am good at $skillScript"
done
ubantu@ubantu-virtual-machine:~$ sh test.sh
I am good at
I am good at
I am good at
I am good at
skillScript
是一个整体,而在我们的代码中找不到该变量关于单引号和双引号以及反引号的引用方法演示
(1)单引号的引用(不解析任何字符)
ubantu@ubantu-virtual-machine:~$ sh
sh-4.3$ testvar=100
sh-4.3$ echo 'The testvalue is $testvar'
The testvalue is $testvar
(2)双引号的引用(会解析$和反斜杠特殊字符)
ubantu@ubantu-virtual-machine:~$ sh
sh-4.3$ testvar=100
sh-4.3$ echo "The testvalue is $testvar"
The testvalue is 100
(3)反引号的引用(执行系统命令)
ubantu@ubantu-virtual-machine:~$ sh
sh-4.3$ now_date = `date`
sh: 6: now_date: not found
sh-4.3$ now_date=`date`
sh-4.3$ echo $now_date
Wed Feb 27 13:51:28 CST 2019
sh-4.3$
(1)定义:
环境变量一般是指在操作系统中用来指定操作系统运行环境的一些参数,如:PATH、PWD、USER、当前使用的SHELL名称等
(2)常见环境变量:
PATH:系统路径
HOME:当前用户家目录
HISTSIZE:保存历史记录的条数
LOGNAME:当前登录用户用户名
HOSTNAME:主机名称,若应用程序要用到主机名的话,一般是从这个环境变量中取得的
SHELL:当前用户用的是那种shell
LANG/LANGUGE:和语言相关的环境变量,使用多种语言的用户可以修改次环境变量
MAIL:当前用户的邮件存放目录
(3)查看环境变量
env:显示所有环境变量
echo $PATH:显示某一个环境变量的值
(1)定义:
在Shell脚本中由用户自定义的变量,其作用域是从变量被定义的地方开始,到shell结束为止,其作用域为脚本,离开本脚本,则变量无效
(1)编写一个脚本,定义一个变量,并输出其结果
#!/bin/sh
mystr=abcd
echo $mystr
~
ubantu@ubantu-virtual-machine:~/myshell$ sh test1.sh
abcd
(2)退出脚本再输出这个变量看看有没有结果
ubantu@ubantu-virtual-machine:~/myshell$ echo $mystr
ubantu@ubantu-virtual-machine:~/myshell$
(2)在用户登录的shell中定义的变量,重新登录后改变量消失
(1)登录到shell脚本,给一个变量赋值,显示该变量的结果
ubantu@ubantu-virtual-machine:~/myshell$ sh
sh-4.3$ var2=12345
sh-4.3$ echo $var2
12345
sh-4.3$ exit
(2)退出当前shell,重新登录,再输出这个变量,看看有无结果
ubantu@ubantu-virtual-machine:~/myshell$ sh
sh-4.3$ echo $var2
sh-4.3$
(1)定义:
预定义变量和环境变量相类似,也是在Shell一开始就定义了的变量,所不同的是,用户只能根据Shell的定义来使用这些变量,而不能重新定义它,所以预定义变量都是由$符合另一个符号组成的
(2)常用的Shell预定义变量有以下:
$#:位置参数的数量
$*:所有位置参数的内容
$?:命令执行后返回的状态,0表示成功,1表示失败
$$:当前进程的进程号
$!:后台运行的最后一个进程号,很少用
$0:当前执行的进程名
(3)示例:
#!/bin/sh
echo "这个进程的名字是:$0"
echo "参数的数量是:$#"
echo "所有的参数:$*"
echo "当前进程的进程号:$$"
echo "命令执行的返回状态:$?"
echo "后台运行的最后一个进程号:$!"
~
~
ubantu@ubantu-virtual-machine:~/myshell$ sh test2.sh
这个进程的名字是:test2.sh
参数的数量是:0
所有的参数:
当前进程的进程号:2648
命令执行的返回状态:0
后台运行的最后一个进程号:
ubantu@ubantu-virtual-machine:~/myshell$ sh test2.sh 1 2 3 4
这个进程的名字是:test2.sh
参数的数量是:4
所有的参数:1 2 3 4
当前进程的进程号:2656
命令执行的返回状态:0
后台运行的最后一个进程号:
fatpuffer@ubuntu:~/mybash$
(1)echo
命令发送数据到标准的输出
设备,数据采用的是字符串的方式,echo命令可以输出一个变量
ubantu@ubantu-virtual-machine:~/myshell$ sh
sh-4.3$ myprograme="myprograme is : mysql monitor script"
sh-4.3$ echo $myprograme
myprograme is : mysql monitor script
sh-4.3$
(2)echo两个重要参数
-e
:识别输出内容里的转义序列sh-4.3$ echo -e 'hello\tworld'
hello world
-n
:忽略结尾的换行sh-4.3$ echo -e -n 'hello\tworld'
hello world$
(3)printf
输出,和echo功能类似,也可以输出变量,printf还可以按照格式输出变量,需要注意的是:
printf
的默认输出没有换行,需要自己加 “\n”sh-4.3$ mystr="hello,world"
sh-4.3$ printf $mystr
hello,world$
sh-4.3$ mystr="hello,world"
sh-4.3$ printf "%s\n" $mystr # 使用占位符时$符和前引号内的字符串之间必须要有空格
hello,world
sh-4.3$
printf
支持格式化输出#!/bin/sh
name=zhangsan
age=22
address="beijing"
printf "name:%s,age:%s,address:%s\n" $name $age $address
ubantu@ubantu-virtual-machine:~/myshell$ sh test3.sh
name:zhangsan,age:22,address:beijing
ubantu@ubantu-virtual-machine:~/myshell$
(4)read
命令读取标准输入设备的下一行,标准输入
中的新的一行到换行符前的所有字符会被读取,并赋值给变量(可以结合echo一起实现读取并输出的功能)。
-p
:添加提示信息#!/bin/sh
# 接受输入并输出IP地址
echo "please input your ipaddress"
read ipaddr
echo "my ip address is $ipaddr"
ubantu@ubantu-virtual-machine:~/myshell$ sh test4.sh
please input your ipaddress
192.16.0.13
my ip address is 192.16.0.13
#!/bin/sh
# 接受输入并输出
now_time=`date +%F,%H:%M:%S`
read -p "please input your username:" username
read -p "please input your password:" password
# awk是用来提取列的主要工具
# {print $1}就是将某一行中以空格为分割符的第一个字段打印出来
password_md5=$(echo $password|md5sum|awk "{print $1}")
echo "$now_time,系统为您生成的用户密码为:$username/$password_md5"
ubantu@ubantu-virtual-machine:~/shell$ sh test.sh
please input your username:fatpuffer
please input your password:admin
2019-03-04,13:53:50,系统为您生成的用户密码为:fatpuffer/456b7016a916a4b178dd72b947c152b7 -
ubantu@ubantu-virtual-machine:~/shell$
shell运算操作
(1)let
整数运算
let
命令让BASH shell执行算数值操作,使用let,可以比较两个值或执行加减乘除等这样的算数操作,这种操作经常用于shell程序中的控制流程结构或执行需要的运算,注意let命令只能执行整数的相关运算,运算结果也只能保存整数。let 变量名 = 变量1 运算符 变量2
( + - * / %)
C
语言类似,let i=$i+1
也可以写成let i++
,从而简化书写#!/bin/sh
# let执行算数操作经常使用的方法演示
i=10
j=20
k=3
# 执行算数运算
let res1=$i+$j+$k
let res2=$j-$i-$k
let res3=$i*$j*$k
let res4=$i*$j/$k
# 输出结果
echo "i+j+k=$res1"
echo "j-i-k=$res2"
echo "i*j*k=$res3"
echo "i*j/k=$res4" # let会将整数运算得到的结果保留整数,将小数部分截取
ubantu@ubantu-virtual-machine:~/myshell$ sh test.sh
i+j+k=33
j-i-k=7
i*j*k=600
i*j/k=66
ubantu@ubantu-virtual-machine:~/myshell
let
方法来控制流程结构(此处不得不强调一下,[ ]
左右必须有空格,在此被坑了很久)#!/bin/sh
# 使用let方法来控制流程结构
i=1
n=3
while [ 1 ]
do
if [ $i -le $n ] # 小于等于
then
echo "$i"
else
break
fi
let i=$i+1 # 用let进行+1操作,此处也可以写成let i++
done
(2)expr
整数运算
expr
在linux中是一个功能非常强大的命令,和let
功能类似,它做算数运算时,只能进行整数类型运算,不能保存小数结果,除了进行算数运算,expr 还可以进行字符串的操作,因此 expr 功能非常强大。expr expression1 操作符 expression2
*
前必须加'\'
用于转义,并且操作符和两个expression之间必须有空格
(这一点与let
不同)sh-4.3$ expr 1 + 1
2
sh-4.3$ expr 1.1 + 1
expr: non-integer argument
sh-4.3$
( + - * / %)
expr
命令使用方法举例:(1)常见的算数运算操作
#!/bin/sh
# expr 执行算数操作经常使用的方法演练
i=10
j=20
k=3
# 执行算数运算
echo "i:$i;j:$j;k:$k"
res1=`expr $i + $j + $k` # expr作为外部命令要用反引号引起来。
res2=`expr $j - $i - $k`
res3=`expr $i \* $j \* $k`
res4=`expr $i \* $j / $k`
# 输出运算结果
echo "i+j+k=$res1"
echo "j-i-k=$res2"
echo "i*j*k=$res3"
echo "i*j\k=$res4"
ubantu@ubantu-virtual-machine:~/shell$ sh test.sh
i:10;j:20;k:3
i+j+k=33
j-i-k=7
i*j*k=600
i*j\k=66
ubantu@ubantu-virtual-machine:~/shell$
(2)expr方法来控制流程结构
#!/bin/sh
# expr 控制流程结构
i=1
n=5
# 用expr来控制输出,连续输出i变量的值
while [ 1 ]
do
if [ $i -le $n ]
then
echo "$i"
else
break
fi
i=`expr $i + 1` # expr操作符左右两端必须有空格
done
ubantu@ubantu-virtual-machine:~/shell$ sh test.sh
1
2
3
4
5
ubantu@ubantu-virtual-machine:~/shell$
(3)bc
浮点运算
let
和expr
不能处理浮点运算,并且缺乏特定的一些重要的精确操作,但是bc
可以进行浮点运算,是一个多功能的灵活的工具,提供精确的复杂计算功能,他是linux一个重要的工具,bc
经常使用在管道里。scale
作为 bc
一个最重要的选项,用来是定输出小数的位数。variable=`echo "OPTIONS; OPTIONS" | bc`
ubantu@ubantu-virtual-machine:~/shell$ sh
sh-4.3$ n=`echo "scale=3;13 / 2" | bc`
sh-4.3$ echo $n
6.500
sh-4.3$
#!/bin/sh
# expr 执行算数操作经常使用的方法演练
# bc 执行浮点运算方法演练
i=10
j=20
k=3
# 执行算数运算
echo "i:$i;j:$j;k:$k"
res1=`expr $i + $j + $k` # expr作为外部命令要用反引号引起来。
res2=`expr $j - $i - $k`
res3=`expr $i \* $j \* $k`
res4=`expr $i \* $j / $k`
# 执行浮点运算
res5=`echo "scale=5; $i * $j / $k" | bc` # 注意此处乘法不需要用转义
# 输出运算结果
echo "i+j+k=$res1"
echo "j-i-k=$res2"
echo "i*j*k=$res3"
echo "expr:i*j\k=$res4"
echo "bc:i*j\k=$res5"
ubantu@ubantu-virtual-machine:~/shell$ sh test.sh
i:10;j:20;k:3
i+j+k=33
j-i-k=7
i*j*k=600
expr:i*j\k=66
bc:i*j\k=66.66666
ubantu@ubantu-virtual-machine:~/shell$
(4)expr
字符串的运算
shell
中字符串操作也是常见的运算之一 ,expr
除了算数运算之外,还可以进行字符串相关的运算,以下简单介绍使用expr进行的常用字符串操作输出字符串的长度
ubantu@ubantu-virtual-machine:~/shell$ sh
sh-4.3$ str1="asds1223"
sh-4.3$ echo ${#str1}
8
sh-4.3$ expr length $str1
8
sh-4.3$
取字符串的操作
expr substr $string $position $length
# 注意位置编号从1开始echo $ {string: $pos: $length}
# 注意位置编号从0开始sh-4.3$ string="asdjbsakdjff12342434"
sh-4.3$ expr substr $string 1 3
asd
sh-4.3$ echo ${string:0:3}
asd
sh-4.3$
字符串连接的操作
expr
命令没有字符串连接的操作,但其也是很常见的sh-4.3$ str1=abc
sh-4.3$ str2=123
sh-4.3$ str3="${str1}$str2" # 这个地方可以定义字符串连接的分隔符
sh-4.3$ echo $str3
sh-4.3$ str3="${str1};$str2" # 这个地方可以定义字符串连接的分隔符
sh-4.3$ echo $str3
abc;123
sh-4.3$
字符串的替换操作
expr
命令没有字符串替换的操作,但其也是很常见的sh-4.3$ string='hello world hello python'
sh-4.3$ echo ${string/hello/Hello} # 替换一次
Hello world hello python
sh-4.3$ echo ${string//hello/Hello} # 替换全部
Hello world Hello python
sh-4.3$
test比较操作
(1)test
比较两个值
整数比较、字符串比较、逻辑比较(与、或、非)、文件比较
test
的命令语法:test value1 -option value2
option
:lt、gt、eq$?
为0,否则返回非0,此处用于判断操作。(2)test
整数比较的方法
|---------------------------------------|
| 大于 -gt |
| 小于 -lt |
| 大于等于 -ge |
| 小于等于 -le |
| 等于 -eq |
| 不等于 -ne |
|---------------------------------------|
#!/bin/sh
# test 整数比较方法熟练演练
a=100
b=200
c=100
d=300
# 输出a,b,c,d的值
echo -e "a:$a\t b:$b\t c:$c\t d:$d"
# 大于比较
test $b -gt $a # 成功则 $? 返回 0
if [ $? -eq 0 ]
then
echo "b>a"
else
echo "a
fi
# 大于等于比较
test $c -ge $a
if [ $? -eq 0 ]
then
echo "c>=a"
else
echo "a
fi
# 等于比较
test $c -eq 100
if [ $? -eq 0 ]
then
echo "c==100"
else
echo "c!=100"
fi
# 不等于比较
test $d -ne 400
if [ $? -eq 0 ]
then
echo "d!=400"
else
echo "d==400"
fi
ubantu@ubantu-virtual-machine:~/shell$ sh test.sh
a:100 b:200 c:100 d:300
b>a
c>=a
c==100
d!=400
ubantu@ubantu-virtual-machine:~/shell$
(3)test
字符串比较方法
|-----------------------------------------------------------|
| 测试空字符串 -z |
| 测试字符串的长度为非零 -n |
| 等于某一个字符串 = |
| 不等于某一个字符串 != |
|-----------------------------------------------------------|
#!/bin/sh
# test 字符串比较方法
str1="abc"
str2="abc"
str3="123"
str4=""
# 输出字符串的值
echo -e "str1: ${str1}\t str2: ${str2}\t str3: ${str3}\t str4: ${str4}\t"
# 长度是否为0
test -n $str1 # 长度不为0,则程序执行返回值为0(即非空字符串返回0)
if [ $? -eq 0 ]
then
echo "the length of str1 is not zero"
else
echo "the length of str1 is zero"
fi
# 字符串是否为空
test -z $str4 # 字符串长度为0,则程序返回0(空字符串返回0)
if [ $? -eq 0 ]
then
echo "the length of str4 is zero"
else
echo "the length of str4 is not zero"
fi
# 字符串相等
test str1=str2
if [ $? -eq 0 ]
then
echo "str1 equal str2"
else
echo "str1 not equal str2"
fi
# 字符串不相等
test str1!=str3
if [ $? -eq 0 ]
then
echo "str1 not equal str3"
else
echo "str1 equal str3"
fi
ubantu@ubantu-virtual-machine:~/shell$ sh test.sh
str1: abc str2: abc str3: 123 str4:
the length of str1 is not zero
the length of str4 is zero
str1 equal str2
str1 not equal str3
ubantu@ubantu-virtual-machine:~/shell$
(4)test
逻辑比较方法
|--------------------------|
| 逻辑与 -a |
| 逻辑或 -o |
| 逻辑非 ! |
|--------------------------|
#!/bin/sh
# test 逻辑比较方法熟练演练
basepath=$(pwd)
filename=$0 # 程序名
echo "$basepath目录下的$filename与或非运算演练....."
# 与运算( $#: 位置参数的数量 $1:第一个参数 )
test $# -eq 1 -a $1 -eq 100 # 输入的参数个数为1且第一个参数为100
if [ $? -eq 0 ]
then
echo "参数个数为1且参数值为100"
else
echo "不满足与运算的输入要求"
fi
# 或运算
test $# -ge 1 -o $1 -eq 100 # 输入的参数个数大于等于1或第一个参数为100
if [ $? -eq 0 ]
then
echo "参数个数为大于等于1,,或参数值为100"
else
echo "不满足或运算的输入要求"
fi
ubantu@ubantu-virtual-machine:~/shell$ sh test.sh 200 200
/home/ubantu/shell目录下的test.sh与或非运算演练.....
不满足与运算的输入要求
参数个数为大于等于1,,或参数值为100
ubantu@ubantu-virtual-machine:~/shell$
(5)test
文件比较的方法
|-------------------------------------------|
| 文件存在并且是一个常规文件 -f |
| 文件不为空 -s |
| 文件可读 -r |
| 文件可写 -w |
| 文件可运行 -x |
| 文件是一个目录名 -d |
| 文件是一个符号链接 -h |
| 文件名引用一个字符设备 -c |
| 文件名引用一个块文件 -b |
|-------------------------------------------|
常规文件:-rw-rw-r--
目录文件:drwxrwxr-x
字符设备或块设备文件:crw--w----
块设备文件:brw-rw----
套接口文件:srwxrwxrwx socket套接字文件
符号链接文件:lrwxrwxrwx 软连接文件
#!/bin/sh
# test文件比较方法演练
basepath=$(pwd)
filename=$0
filename2="./noneexist.txt"
dir_name="pythonShell"
echo "$basename目录下的$filename文件比较方法演练"
# 文件存在且为常规文件与运算
test -f $filename
if [ $? -eq 0 ]
then
echo "$filename文件存在且为常规文件"
else
echo "$filename文件不存在或不为常规文件"
fi
test -f $filename2
if [ $? -eq 0 ]
then
echo "$filename2 存在且为常规文件"
else
echo "$filename2 不存在或不为常规文件"
fi
test -d $dir_name
if [ $? -eq 0 ]
then
echo "$dir_name 是一个文件夹"
else
echo "$dir_name 不是一个文件夹"
fi
test -r $filename
if [ $? -eq 0 ]
then
echo "$filename 可读"
else
echo "$filename 不可读"
fi
test -w $filename
if [ $? -eq 0 ]
then
echo "$filename 可写"
else
echo "$filename 不可写"
fi
test -x $filename
if [ $? -eq 0 ]
then
echo "$filename 可执行"
else
echo "$filename 不可执行"
fi
ubantu@ubantu-virtual-machine:~/shell$ touch noneexist.txt
ubantu@ubantu-virtual-machine:~/shell$ mkdir pythonShell
ubantu@ubantu-virtual-machine:~/shell$ sh test.sh
test.sh文件存在且为常规文件
./noneexist.txt 存在且为常规文件
pythonShell 是一个文件夹
test.sh 可读
test.sh 可写
test.sh 不可执行
ubantu@ubantu-virtual-machine:~/shell$ ls -la
total 52
-rw-rw-r-- 1 ubantu ubantu 0 Mar 4 11:29 noneexist.txt
drwxrwxr-x 2 ubantu ubantu 4096 Mar 4 11:29 pythonShell
-rw-rw-r-- 1 ubantu ubantu 6116 Mar 4 11:29 test.sh
(1)顺序结构
#!/bin/sh
|
语句块1
|
语句块2
|
语句块N
变量名 | 说明 |
---|---|
$# | 不包括命令在内的命令行参数的数目 |
$* | 命令行所有参数组成的字符串 |
$@ | 命令行所有参数组成的字符串 |
$n | n为数字,$0表示命令名称,$1表示命令第一个参数,以此类推 |
$? | 上一个命令的返回值,如果正常退出则返回0,反之返回非0值 |
$$ | 当前的进程PID号 |
$! | 后台运行的最后一个进程的进程号 |
变量名 | 说明 |
---|---|
HOME | 当前用户的主目录 |
PATH | 命令搜索路径 |
LOGNAME | 用户登录名 |
PS1 | 第一命令提示符,是#或$ |
PS2 | 第二命令提示符,默认是> |
PWD | 用户的当前目录 |
UID | 当前用户标识 |
TERM | 终端类型 |
SHELL | 用户shell类型 |
HISFILE | 存储历史命令的文件 |
(2)选择结构
if-then
(1)单分支 if 结构,此类单分支结构,当条件满足的时候,就会执行 then 后面的语句,不满足时,就直接退出。
if [ 条件 ];
then
语句1...
else
语句2...
fi
(2)双分支 if 结构,当条件满足时就会运行 then 后面的语句,条件不满足时就运行 else 后面的语句。
if [ 条件 ];
then
语句...
fi
1 #!/bin/sh
2 # if-then双分支结构演练
3
4 # 获取对应用户UID
5 id=$(id -u $1)
6 if [ $? -eq 0 ]
7 then
8 # 存在该用户则直接输出该用户id
9 echo "$1 user alreday exist, uid is $id"
10 else
11 # 用户不存在则创建这个用户
12 useradd $1
13 id=$(id -u $1)
14 echo "$1 user is created, and uid is $id"
15 fi
ubantu@ubantu-virtual-machine:~/shell$ sh test.sh ubantu
ubantu user alreday exist, uid is 1000
ubantu@ubantu-virtual-machine:~/shell$ sudo sh test.sh ubuntu
[sudo] password for ubantu:
id: ‘ubuntu’: no such user
ubuntu user is created, and uid is 1001
(3)嵌套 if 结构,当条件满足条件1时,则执行 then 后面的语句,当条件再满足条件2,则执行 then 后面的语句,不满足条件2,则退出,当条件不满足条件1,则执行 else 后面的语句。
if [ 条件1 ];
then
if [ 条件2 ];
then
语句1...
else
语句2...
fi
else
语句...
fi
demo:首先判断运行脚本的系统参数有多少个,如果参数个数不等于1,则提示参数输入错误,否则,判断输入的用户是否存在,存在则输出该用户的UID,不存在则创建该用户,并且输出这个用户的UID
1 #!/bin/sh
2 # if嵌套结构
3
4 # 获取对应用户UID
5 if [ $# -ne 1 ]
6 then
7 echo "参数输入有误,只能输入一个参数..."
8 else
9 id=$(id -u $1)
10 if [ $? -eq 0 ]
11 then
12 echo "$1 user already exist, uid is $id"
13 else
14 useradd $1
15 id=$(id -u $1)
16 echo "$1 is created, and uid is $id"
17
18 fi
19 fi
ubantu@ubantu-virtual-machine:~/shell$ sh test.sh ubantu
ubantu user already exist, uid is 1000
ubantu@ubantu-virtual-machine:~/shell$ sudo sh test.sh fatpuffer
[sudo] password for ubantu:
id: ‘fatpuffer’: no such user
fatpuffer is created, and uid is 1002
ubantu@ubantu-virtual-machine:~/shell$
case-esac
case 语句适用于需要进行多重分支的应用情况,它也是选择结构中常用的一种控制结构
case $变量名 in # 严格掌握其语法
模式1) # 右括号不能省
命令序列1
;; # 两分号不能省
模式2)
命令序列2
;;
*)
默认执行的命令序列
;;
esac # 结尾反写case表示结束
demo:用户从键盘输入一个字符,判断该字符时字母还是其他字符,并给出提示信息。
#!/bin/sh
# case-esac分支结构演练
read -p "请输入内容(按回车结束):" data
case $data in
[0-9])
echo "你输入的时数字"
echo "数字是:$data"
;;
[a-z]|[A-Z])
echo "你输入的是字符"
echo "字符是:$data"
;;
*)
echo "你输入的是特殊字符"
echo "特殊字符是:$data"
;;
esac
ubantu@ubantu-virtual-machine:~/shell$ sh test.sh
请输入内容(按回车结束):s
你输入的是字符
字符是:s
ubantu@ubantu-virtual-machine:~/shell$ sh test.sh
请输入内容(按回车结束):4
你输入的时数字
数字是:4
ubantu@ubantu-virtual-machine:~/shell$ sh test.sh
请输入内容(按回车结束):&
你输入的是特殊字符
特殊字符是:&
ubantu@ubantu-virtual-machine:~/shell$
(3)循环结构
for
循环结构1、遍历/列表式循环结构
for cariable in list
do
statement
done
(1)用seq产生一个序列范围,来控制遍历的次数
1 #!/bin/sh
2
3 read -p "请输入一个数字:" num
4 for i in $(seq $num)
5 do
6 echo $i
7 done
8 break
ubantu@ubantu-virtual-machine:~/shell$ sh test.sh
请输入一个数字:10
1
2
3
4
5
6
7
8
9
10
(2)命令序列不是连续的情况,可以自定义来处理
1 #!/bin/sh
2
3 for mydir in A B C E G
4 do
# -v 打印提示信息
# -m 指定权限
5 mkdir -v -m 755 $mydir
6 done
ubantu@ubantu-virtual-machine:~/shell$ sh test.sh
mkdir: created directory 'A'
mkdir: created directory 'B'
mkdir: created directory 'C'
mkdir: created directory 'E'
mkdir: created directory 'G'
2、C语言风格的循环结构
for ((expr1;expr2;expr3))
do
statement
done
demo:创建一年中1月至12月所使用的数据库,将统计结果插入到相应的月份中
1 #!/bin/sh
2
3 for ((month=1;$month<=12;month++))
4 do
5 echo "create databases analyse_$month"
6 sleep 1
7 # mysql -e "create database analyse_$month"
8 # 统计结果入相应的月份库中
9 # ...
10 done
ubantu@ubantu-virtual-machine:~/shell$ sh test.sh
create databases analyse_1
create databases analyse_2
create databases analyse_3
create databases analyse_4
create databases analyse_5
create databases analyse_6
create databases analyse_7
create databases analyse_8
create databases analyse_9
create databases analyse_10
create databases analyse_11
create databases analyse_12
ubantu@ubantu-virtual-machine:~/shell$
while
循环结构1、语法结构
while expression
do
statement
done
(1)while [] 结构,此时while后面要跟空格,否则报错
(2)while(())结构,不需要空格
demo1:用while []结构控制循环的次数,输出相关的变量
1 #!/bin/sh
2
3 i=1
4 while [ $i -le 10 ]
5 do
6 echo $i
7 let i++
8 done
ubantu@ubantu-virtual-machine:~/shell$ sh test.sh
1
2
3
4
5
6
7
8
9
10
ubantu@ubantu-virtual-machine:~/shell$
demo2:用while(())结构控制循环的次数,输出相关的变量
1 #!/bin/sh
2
3 i=1
4 while((i<=10))
5 do
6 echo $i
7 let i++
8 done
ubantu@ubantu-virtual-machine:~/shell$ sh test.sh
1
2
3
4
5
6
7
8
9
10
ubantu@ubantu-virtual-machine:~/shell$
demo3:用while循环实现一个无限循环,每隔3秒调用一次程序,再解决队列一类的问题的时候会经常用到。
1 #!/bin/sh
2
3 while [ 1 ]
4 do
5 echo "the script is runing..."
6 sleep 3
7 done
1 #!/bin/sh
2
3 while [ 1 ]
4 do
5 echo "the script is runing..."
6 sleep 3
7 done
ubantu@ubantu-virtual-machine:~/shell$ sh test.sh
the script is runing...
the script is runing...
the script is runing...
the script is runing...
the script is runing...
the script is runing...
the script is runing...
continue、break
循环结构break:退出当前循环,并且将控制权传递到本循环后面的第一个命令。
continue:当程序执行过程中遇到这个命令,就会忽略本次循环剩余的命令,将控制权交给循环的顶部。
demo:break程序演示:循环从键盘读入一个字符,输出该字符,当输入的字符为 'x' 或 'X'时,退出当前循环。
1 #!/bin/sh
2
3 while [ 1 ]
4 do
5 read -p '请输入字符(输入'x'或'X'退出):' str
6 test $str = x -o $str = X
7 if [ $? -eq 0 ]
8 then
9 break
10 else
11 echo "你输入的内容是:$str"
12 fi
13 done
ubantu@ubantu-virtual-machine:~/shell$ sh test.sh
请输入字符(输入x或X退出):r
你输入的内容是:r
请输入字符(输入x或X退出):h
你输入的内容是:h
请输入字符(输入x或X退出):b
你输入的内容是:b
请输入字符(输入x或X退出):s
你输入的内容是:s
请输入字符(输入x或X退出):x
ubantu@ubantu-virtual-machine:~/shell$
demo:continue程序演示:循环从键盘读入一个字符,输出该字符,当输入的字符为 'x' 或 'X'时,进行下一次循环,当输入 'q' 或 'Q'时退出程序。
1 #!/bin/sh
2
3 while [ 1 ]
4 do
5 read -p '请输入字符(输入'x'或'X'退出):' str
6 test $str = x -o $str = X
7 if [ $? -eq 0 ]
8 then
9 continue
10 else
11 test $str = q -o $str = Q
12 if [ $? -eq 0 ]
13 then
14 break
15 else
16 echo "你输入的内容是:$str"
17 fi
18 fi
19 done
ubantu@ubantu-virtual-machine:~/shell$ sh test.sh
请输入字符(输入q或Q退出):d
你输入的内容是:d
请输入字符(输入q或Q退出):f
你输入的内容是:f
请输入字符(输入q或Q退出):5
你输入的内容是:5
请输入字符(输入q或Q退出):x
请输入字符(输入q或Q退出):F
你输入的内容是:F
请输入字符(输入q或Q退出):Q
ubantu@ubantu-virtual-machine:~/shell$
while read
循环while read line 可以按行读入,一直到所有行都读完,才退出循环,再实际工作中,经常会采用这种循环结构,进行数据处理。
语法格式:
cat file.txt | while read line # 此处的cat也可以时一个产生若干行的命令,如find
do
...
done
1 #!/bin/sh
2
3 sum_line=0
4 cat ./noneexist.txt | while read ipline
5 do
6 let sum_line=sum_line+1
7 # -n忽略行尾的换行
8 echo -n "第$sum_line行....."
9 # awk是用来提取列的主要工具
10 # {print $1}就是将某一行中以空格为分割符的第一个字段打印出来
11 from=`echo $ipline|awk '{print $1}'`
12 ip=`echo $ipline|awk '{print $2}'`
13 echo "$from-----------$ip"
14 sleep 1
15 done
16 echo "这个文件的行数为:$sum_line"
ubantu@ubantu-virtual-machine:~/shell$ cat noneexist.txt
111111111 1111111111
2222222222222222222
3333333333333333333
4444444444444444444
5555555555555555555
ubantu@ubantu-virtual-machine:~/shell$ sh test.sh
第1行.....111111111-----------1111111111
第2行.....2222222222222222222-----------
第3行.....3333333333333333333-----------
第4行.....4444444444444444444-----------
第5行.....5555555555555555555-----------
第6行.....-----------
这个文件的行数为:0
ubantu@ubantu-virtual-machine:~/shell$
我们看到最后显示文件行数为0,这明显是不对的,那么原因是什么?
while read line 循环体中的变量,当退出循环后,会被销毁,所以若要二次使用循环体中的变量,则要采用其他办法。
因为管道后的 while loop 是 sub shell,所以里面的变量自执行完成后,需要销毁。
demo:编写一个程序,读取一个带有IP地址的文件,该文件内容为:
192.168.1.31
192.168.1.32
192.168.1.33
....
192.168.1.100
要球:(1)在9:00-18:00不允许访问QQ服务器(218.17.209.23)的80端口
(2)在非上述时间段允许访问QQ服务器的(218.17.209.23)的80端口
(3)公司内部网络上采用linux iptable nat功能,上网服务器为一台PC机
(4)添加防火墙规则的命令:
/sbin/iptables -I FORWARD -p tcp -s 192.168.1.31 -d 218.17.209.23 --destination-port 80 -j DROP
(5)删除防火墙规则的命令:
/sbin/iptables -D FORWARD -p tcp -s 192.168.1.31 -d 218.17.209.23 --destination-port 80 -j DROP
(6)定时任务采用crontab实现
函数
(1)linux shell 函数
(2)shell 函数的组成
(3)shell 函数定义的格式
function 函数名()
# function可以省略,注意 ( ) 内部不带任何参数。{
命令1
命令2
....
}
(4)函数定义及引用实例一:最简单的定义及引用
1 #!/bin/sh
2
3 function print_welcome()
4 {
5 echo "练习函数的定义及引用方法"
6 echo "welecome,now time is `date`"
7 }
8 print_welcome
ubantu@ubantu-virtual-machine:~/shell$ sh func_1.sh
练习函数的定义及引用方法
welecome,now time is Tue Mar 5 17:05:26 CST 2019
ubantu@ubantu-virtual-machine:~/shell$
(5)函数定义及引用实例二:向函数传递参数
1 #!/bin/sh
2
3 sum()
4 {
5 echo "演练函数内部参数的传递方法"
6 if [ $# -eq 2 ]
7 then
8 echo "符合函数要求的参数"
9 a1=$1
10 a2=$2
11 let sum=a1+a2
12 else
13 echo "函数要求的参数个数不符,请重新输入"
14 fi
15 echo "$a1+$a2=$sum"
16 }
17 sum 10 90
ubantu@ubantu-virtual-machine:~/shell$ sh func_2.sh
演练函数内部参数的传递方法
符合函数要求的参数
10+90=100
ubantu@ubantu-virtual-machine:~/shell$
(6)函数文件和脚本文件不在同一个文件中,该如何调用该函数。
1 #!/bin/sh
2
3 file_md5()
4 {
5 if [ $# -ne 1 ]
6 then
7 echo "函数参数有误,请重新输入一个参数"
8 else
9 filename=$1
10 md5=$(md5sum $filename)
11 echo "$filename 的md5摘要为:$md5"
12 fi
13 }
1 #!/bin/sh
2
3 . ./func_3.sh
4 while [ 1 ]
5 do
6 read -p "请输入一个文件名:" filename
7 file_md5 $filename
8 done
ubantu@ubantu-virtual-machine:~/shell$ sh func_call.sh
请输入一个文件名:func_1.sh
func_1.sh 的md5摘要为:51822847a3c837c5d90a4d86a822f942 func_1.sh
请输入一个文件名:func_2.sh
func_2.sh 的md5摘要为:26e72857e283d33635867d9bb7aa6e85 func_2.sh
请输入一个文件名:func_5.sh
md5sum: func_5.sh: No such file or directory
func_5.sh 的md5摘要为:
请输入一个文件名:
数组
(1)数组的定义
相同类型的若干变量
按有序的形式组织起来,这些按序排列的同类数据元素
的集合称为数组。数组的定义
数组名=(元素1 元素2 元素n) # 一对括号表示是数组,数组元素用 "空格" 符号分割开来
如:myarray=(1 2 3 4 5) # 注意定义的方法,小括号、逗号
(2)数组常用操作
定义一个数组:myarray=(1 2 3 4 5)
读取数组的某一个元素:echo ${myarray[下标值]} # 注意数组名称必须使用{}括起来,下标取值从0开始编号。
数组元素的赋值:myarray[下标值] = xxx
显示数组的所有元素:echo ${myarray[*]}
获得数组的长度(元素的个数):echo ${#myarray[@]} 或者 echo ${#myarray[*]}
删除一个数组元素:unset myarray[下标值]
(3)数组常用操作实践
1 #!/bin/sh
2
3 myarray=(1 2 3 4 5 6 7 8)
4
5 echo "数组myarray初始的所有元素是:${myarray[*]}"
6 echo "数组myarray第一个元素的值是myarray[0]:${myarray[0]}"
7 echo "数组myarray的长度是:${#myarray[*]}"
8 echo "数组myarray的长度是:${#myarray[@]}"
9
10 # 修改第一个元素的值
11 myarray[0]=100
12 echo "修改第一个元素后,数组myarray的所有元素是:${myarray[*]}"
13
14 # 删除myarray[0]
15 unset myarray[0]
16 echo "删除第一个元素后,数组myarrsy的所有元素是:${myarray[*]}"
ubantu@ubantu-virtual-machine:~/shell$ sh array_1.sh
数组myarray初始的所有元素是:1 2 3 4 5 6 7 8
数组myarray第一个元素的值是myarray[0]:1
数组myarray的长度是:8
数组myarray的长度是:8
修改第一个元素后,数组myarray的所有元素是:100 2 3 4 5 6 7 8
删除第一个元素后,数组myarrsy的所有元素是:2 3 4 5 6 7 8
ubantu@ubantu-virtual-machine:~/shell$
(4)循环数组
${myarray[*]}
直接输出的所有元素的个数,对数组元素进行独立操作的时候,不太方便,所以有必要对其循环处理。 1 #!/bin/sh
2
3 myarray=(1 2 3 4 5 6 7)
4
5 len=${#myarray[@]}
6 echo "数组长度:$len"
7 echo "数组的元素依次为:"
8
9 for ((i=0;$i<$len;i++))
10 do
11 echo ${myarray[$i]}
12 sleep 1
13 done
ubantu@ubantu-virtual-machine:~/shell$ sh array_2.sh
数组长度:7
数组的元素依次为:
1
2
3
4
5
6
7
ubantu@ubantu-virtual-machine:~/shell$
(5)数组长度的动态扩展
1 #!/bin/sh
2
3 # 循环读取数组列表演示
4 # 功能:在授权期内形成机器可信任的列表
5 # 执行方法:脚本名 有效期 server1 server2 server3 server...
6
7 # 获得所有数组参数存入
8 list=(*)
9 len=${#list[@]}
10
11 # 第一个元素为有效期
12 echo ${list[0]} > ./trustip.txt
13
14 for ((i=1;$i<$len;i++))
15 do
16 echo "${list[$i]}" >> ./trustip.txt
17 done
18
19 # 显示这个时间可信任的IP列表
20 cat ./trustip.txt
ubantu@ubantu-virtual-machine:~/shell$ sh array_3.sh 2019-03-05 192.168.17.23/24 192.168.17.24/24 192.168.17.25/24 192.168.17.26/24
2019-03-05
192.168.17.23/24
192.168.17.24/24
192.168.17.25/24
192.168.17.26/24
ubantu@ubantu-virtual-machine:~/shell$ cat trustip.txt
2019-03-05
192.168.17.23/24
192.168.17.24/24
192.168.17.25/24
192.168.17.26/24
ubantu@ubantu-virtual-machine:~/shell$
(1)程序备份之前需要注意什么?
(2)数据库备份需要注意什么?
(3)运行环境的备份需要注意什么?
(4)定期备份
crontab
*
或者*/1
表示(5)自动化备份脚本
1 #!/bin/sh
2
3 ## modified by xiaoming 2019-01-20
4
5 # -------参数定义---------
6 # 备份目录
7 dst_mysql_back_dir="/app/mysql_backup"
8 # 日期
9 today=`date +%Y-%m-%d:%H:%M:%S`
10 # 备份保存时间(单位天)
11 datenum=5
12 # -------定义结束---------
13
14 read -p "请输入用户密码:" password
15
16 # 列出需要备份的数据库名称
17 for db_name in ctfd2 CTFd
18 do
19 # do not exist
20 if test ! -e $dst_mysql_back_dir/$db_name/$db_name.$today
21 then
22 echo "建立数据库 ${db_name}备份的文件夹...."
23 mkdir -p $dst_mysql_back_dir/$db_name/
24 chmod -R 777 $dst_mysql_back_dir/$db_name/
25 fi
26 echo "backup $db_name....."
27 # /usr/bin/mysqldump -uroot -p$password -R $db_name > $dst_mysql_back_dir/$db_name/${db_name}${today}_pf.sql
28 # 由于备份文件可能过大,我们可以使用gzip对其进行压缩处理
29 /usr/bin/mysqldump -uroot -p$password $db_name | gzip > $dst_mysql_back_dir/$db_name/${db_name}${today}_pf.sql.zip
30 done
31 # /usr/bin/mysqldump --opt -uroot -p$password -R $db_name --skip-lock-tables| gzip > $dst_mysql_back_dir/$db_name/${db_name}${today}_pf.sql.zip
32 # --opt是quick,add-drop-table,add-locks,extended-insert,lock-tables几个参数的合称,一般都要使用,具体意思自行搜索;
33 # 如果该数据库的用户没有分配 锁表 的权限,则备份会报错 when using LOCK TABLES 。那是因为mysqldump命令默认在导出时是要锁定表的,所以解决方式有两个。一个是给该用户开放 锁表 的权限;另一个是在命令中加
上 --skip-lock-tables 这个参数
34
35 # 将备份的数据库打包压缩
36 # cd $dst_mysql_back_dir/$db_name
37 # 解压缩
38 # gunzip ${db_name}${today}_pf.sql.zip
39
40 # 删除datenum天内的备份数据
41 find $dst_mysql_back_dir -name "*.zip" -mtime +$datenum -type f | xargs rm -rf
42
43 # 同上
44 # find $dst_mysql_back_dir -name "*.zip" -mtime +$datenum -exec rm -rf {} \;
ubantu@ubantu-virtual-machine:~/shell$ sudo sh backup_db.sh
请输入用户密码:123456
建立数据库 ctfd2备份的文件夹....
backup ctfd2.....
mysqldump: [Warning] Using a password on the command line interface can be insecure.
建立数据库 CTFd备份的文件夹....
backup CTFd.....
mysqldump: [Warning] Using a password on the command line interface can be insecure.
ubantu@ubantu-virtual-machine:~/shell$
ubantu@ubantu-virtual-machine:/app/mysql_backup$ pwd
/app/mysql_backup
ubantu@ubantu-virtual-machine:/app/mysql_backup$ ls
CTFd ctfd2
ubantu@ubantu-virtual-machine:/app/mysql_backup$ cd CTFd/
ubantu@ubantu-virtual-machine:/app/mysql_backup/CTFd$ ls
CTFd2019-03-06:13-41-34_pf.sql.zip
ubantu@ubantu-virtual-machine:/app/mysql_backup/CTFd$ cd ../ctfd2/
ubantu@ubantu-virtual-machine:/app/mysql_backup/ctfd2$ ls
ctfd22019-03-06:13-41-34_pf.sql.zip
ubantu@ubantu-virtual-machine:/app/mysql_backup/ctfd2$
crontab
建立定时任务ubantu@ubantu-virtual-machine:~$ crontab -e
no crontab for ubuntu - using an empty one
Select an editor. To change later, run 'select-editor'.
1. /bin/ed
2. /bin/nano <---- easiest
3. /usr/bin/vim.basic
4. /usr/bin/vim.tiny
Choose 1-4 [2]: 3
# 第一次使用该命令来创建定时任务时会让你选择一个编辑器:一般大都使用第三个 vim 编辑器
1 # Edit this file to introduce tasks to be run by cron.
2 #
3 # Each task to run has to be defined through a single line
4 # indicating with different fields when the task will be run
5 # and what command to run for the task
6 #
7 # To define the time you can provide concrete values for
8 # minute (m), hour (h), day of month (dom), month (mon),
9 # and day of week (dow) or use '*' in these fields (for 'any').#
10 # Notice that tasks will be started based on the cron's system
11 # daemon's notion of time and timezones.
12 #
13 # Output of the crontab jobs (including errors) is sent through
14 # email to the user the crontab file belongs to (unless redirected).
15 #
16 # For example, you can run a backup of all your user accounts
17 # at 5 a.m every week with:
18 # 0 5 * * 1 tar -zcf /var/backups/home.tgz /home/
19 #
20 # For more information see the manual pages of crontab(5) and cron(8)
21 #
22 # m h dom mon dow command
23 # 每天早上 5:00am 执行(根据项目实际情况来设定)
24 00 05 * * * /bin/sh /home/ubantu/shell/backup_db.sh
25
查看任务是否创建成功
ubantu@ubantu-virtual-machine:~$ crontab -l
# Edit this file to introduce tasks to be run by cron.
#
# Each task to run has to be defined through a single line
# indicating with different fields when the task will be run
# and what command to run for the task
#
# To define the time you can provide concrete values for
# minute (m), hour (h), day of month (dom), month (mon),
# and day of week (dow) or use '*' in these fields (for 'any').#
# Notice that tasks will be started based on the cron's system
# daemon's notion of time and timezones.
#
# Output of the crontab jobs (including errors) is sent through
# email to the user the crontab file belongs to (unless redirected).
#
# For example, you can run a backup of all your user accounts
# at 5 a.m every week with:
# 0 5 * * 1 tar -zcf /var/backups/home.tgz /home/
#
# For more information see the manual pages of crontab(5) and cron(8)
#
# m h dom mon dow command
# 每天早上 5:00am 执行(根据项目实际情况来设定)
00 05 * * * /bin/sh /home/ubantu/shell/backup_db.sh
ubantu@ubantu-virtual-machine:~$
注意几个要素的备份
(1)运行环境的备份
(2)应用程序的备份
(3)tomcat的备份
(4)apache的备份
(1)监控的内容
(2)通知和报警机制
(3)监控任务的部署