shell脚本学习笔记

1、脚本的基本写法

第一部分:指定解释器(必写)

# 表示以下内容会被bash解析
#!/bin/bash      

注意:如果将解释器路径写死在脚本里,可能在某些系统里就会存在找不到解释器的兼容性问题,所以可以写成:

#!/bin/env bash

注释使用 #

第二部分 :具体的代码逻辑

第一个脚本: hello.sh

#!/bin/env bash

# 输出hello,world
echo "hello,world"
echo "hello,world"
echo "hello,world"

脚本的执行方式:

# 第一种 使用source
source hello.sh

# 第二种,给脚本添加执行权限,直接执行
chmod +x hello.sh
./hello.sh

2、变量

2.1 变量定义: 变量名=变量值

变量名区分大小写,变量一般使用大写

# 定义变量,=两边不能有空格
A=hello

# 对于有空格的字符串,需要使用""
A="hello world"

# 使用变量 $VAR  ${VAR}
echo $A
echo ${A}

# 取消变量
unset A

2.2 变量切片

${VAR:start:end}    # 左闭右开

[root@localhost ~] NUM=123456
[root@localhost ~] echo ${NUM:0:2}
12
[root@localhost ~] echo ${NUM::2}
12
[root@localhost ~] echo ${NUM:2:-1}
345

2.3 将执行结果赋给变量

VAR=`expression`VAR=$(expression)

# 例如:
[root@localhost ~] HOSTNAME=`hostname`
[root@localhost ~] echo $HOSTNAME
localhost.localdomain

[root@localhost ~] CURNEL_VERSION=$(uname -r)
[root@localhost ~] echo $CURNEL_VERSION
3.10.0-1160.el7.x86_64

2.4 读取用户输入的变量

read [options] 变量名

options:
	-p		定义提示用户的信息
	-n       定义字符数(限制变量长度)
	-s		不显示(不显示用户输入的内容),比如在输入密码时不会显示
	-t		定义超时时间 单位:s
    
# 例如
[root@localhost ~] read -p "请输入姓名:" NAME
请输入姓名:kunkun
[root@localhost ~] echo $NAME
kunkun

2.5 从文件中读取变量

read FILE_CONTENT < FILE_NAME

# 例如:
mgh@ubuntu:~/shell_script$ read -p "请输入IP所在文件:" IP_FILE
请输入IP所在文件:ip.txt
mgh@ubuntu:~/shell_script$ read IP < $IP_FILE
mgh@ubuntu:~/shell_script$ echo $IP
192.168.226.128

2.6 定义有类型的变量

declare options VAR=VAL

options:
	-i		定义整型                       declare -i NUM=123
	-r		定义只读变量					  declare -r STR="hello"
	-a		定义普通数组;查看普通数组
	-A		定义关联数组;查看关联数组
	-x		将环境变量导出                  declare -x A=123  ==>   export A=123

2.7 变量的分类

(一)、本地变量

本地变量:当前用户自定义的变量。当前进程中有效,其它进程及当前进程的子进程无效。

(二)、环境变量

环境变量:当前进程有效,并且能够被子进程调用

  • env:查看当前用户的环境变量
  • set:查询当前用户的所有变量(临时变量与环境变量)
  • export 变量名=变量值 或 变量名=变量值;export 变量名

(三)、全局变量

全局变量:全局所有用户和程序都能调用,且继承,新建的用户也默认能调用

解读相关配置文件

文件名说明备注
$HOME/.bashrc当前用户的bash信息,用户登录时读取定义别名、umask、函数等
$HOME/.bash_profile当前用户的环境变量,用户登录时读取
$HOME/.bash_logout当前用户退出当前shell时最后读取定义用户退出时执行的程序
/etc/bashrc全局的bash信息,所有用户都生效
/etc/profile全局环境变量信息系统和所有用户都生效

说明:以上文件修改后,都需要重新source让其生效或者退出重新登录

用户登录系统读取相关文件的顺序

  1. /etc/profile
  2. $HOME/.bash_profile
  3. $HOME/.bashrc
  4. /etc/bashrc
  5. $HOME/.bash_logout

(四)、系统变量

系统变量(内置bash中变量):shell本身已经固定好的了它的名字和作用

内置变量含义
$?上一条命令执行后返回的状态;状态为0表示正常,非0表示异常或错误
$0当前执行的程序或脚本名
$#脚本后面接的参数的个数
$*脚本后面所有参数,参数当成一个整体输出,每一个变量参数之间以空格隔开
$@脚本后面所有参数,参数是独立的,也是全部输出
$1~$9脚本后面的位置参数,$1表示第一个位置的参数,以此类推
${10}~${n}扩展位置参数,第10个位置变量必须用{}括起来(2位数字以上括起来)
$$当前所在进程的进程号(当前终端)
$!后台运行的最后一个进程号(当前终端)
!$调用最后一条命令历史中的参数
# $? 可以在执行安装程序命令后,使用$?来查看是否执行成功	
mgh@ubuntu:~/shell_script$ echo $?
0
mgh@ubuntu:~/shell_script$ lll
Command 'lll' not found, did you mean:
mgh@ubuntu:~/shell_script$ echo $?
127

# var.sh:
#!/bin/env bash

echo "\$0 = $0"
echo "\$# = $#"
echo "\$* = $*"
echo "\$@ = $@"
echo "\$1 = $1"
echo "\$2 = $2"
echo "\$3 = $3"

# ./var.sh sing jump rap basketball
mgh@ubuntu:~/shell_script$ ./var.sh sing jump rap basketball
$0 = ./var.sh                           # 脚本名称
$# = 4                                  # 参数个数
$* = sing jump rap basketball           
$@ = sing jump rap basketball
$1 = sing
$2 = jump
$3 = rap

2.8 获取一个目录下的目录名和文件名

dirname:获取一个路径下的目录

basename:获取一个路径下的文件

root@ubuntu:/home/mgh/shell_script# A=/root/Desktop/shell/mem.txt
root@ubuntu:/home/mgh/shell_script# dirname $A
/root/Desktop/shell
root@ubuntu:/home/mgh/shell_script# basename $A
mem.txt

2.9 变量内容的删除和替换

”%“表示从右往左去掉一个/key/

”%%“表示从右往左最大去掉/key/

”#“表示从左往右去掉一个/key/

”##“表示从左往右最大去掉/key/

# 例如
root@ubuntu:/home/mgh/shell_script# url=www.taobao.com 
root@ubuntu:/home/mgh/shell_script# echo ${#url}       # 获取变量长度
14
root@ubuntu:/home/mgh/shell_script# echo ${url#*.}
taobao.com
root@ubuntu:/home/mgh/shell_script# echo ${url##*.}
com
root@ubuntu:/home/mgh/shell_script# echo ${url%.*}
www.taobao
root@ubuntu:/home/mgh/shell_script# echo ${url%%.*}
www

变量替换:

替换:/ 和 //

# 例如
root@ubuntu:/home/mgh/shell_script# url=www.taobao.com 
root@ubuntu:/home/mgh/shell_script# echo ${url/o/i}
www.taibao.com
root@ubuntu:/home/mgh/shell_script# echo ${url//o/i}
www.taibai.cim

3、简单四则运算

算术运算:默认情况下,shell就只能支持简单的整数运算

运算内容:加(+)、减(-)、乘(*)、除(/)、求余(%)、乘方(**)

表达式举例
$(( ))echo $((1+1))
$[ ]echo $[10-5]
exprexpr 10 / 5 运算符两边必须加空格,*需要转义\*
letn=1;let n+=1;let n++

4、条件判断

4.1 条件语句

语法:

格式1:test 条件表达式

格式2:[ 条件表达式 ] # 中括号两边需要有空格

格式3:[[ 条件表达式 ]] 支持正则 # 中括号两边需要有空格

判断文件类型

判断参数含义
-e判断文件是否存在(任何类型文件)
-f判断文件是否存在且是一个普通文件
-d判断文件是否存在且是一个目录
-s判断文件是否存在且是一个非空文件
mgh@ubuntu:~/shell_script$ touch hello.c
mgh@ubuntu:~/shell_script$ test -f hello.c          # 判断文件是否是普通文件
mgh@ubuntu:~/shell_script$ echo $?                  # 获取上一条命令的返回状态 0为正常
0

mgh@ubuntu:~/shell_script$ [ -f hello.c ]
mgh@ubuntu:~/shell_script$ echo $?
0

判断整数

判断参数含义
-eq相等 equal
-ne不相等 not equal
-gt大于 greater than
-lt小于 less than
-ge大于等于 greater equal
-le小于等于 less equal

判断字符串

判断参数含义
-z判断字符串是否为空
-n判断是否为非空字符串
string1 = string2判断字符串是否相等 ,两边需要加空格
string1 != string2判断字符串是否不相等,两边需要加空格
mgh@ubuntu:~/shell_script$ STR="hello"
mgh@ubuntu:~/shell_script$ test "$STR"="hello";echo $?
0

类C风格判断

mgh@ubuntu:~/shell_script$ ((1==1));echo $?
0
mgh@ubuntu:~/shell_script$ ((1>2));echo $?
1

5、流程控制语句

5.1 判断语句

F:表示false,为假

T:表示true,为真

if [ condition ];then
	command
	command
fi

if [[ condition ]];then
	command
	command
fi

if test condition;then
	command
	command
fi

[ condition ] && command

if … else

if [ condition ];then
	command1
else
	command2
fi

[ condition ] && command1 || command2

if … else if …else

if [ condition1 ];then
	command1
elif [ condition2 ];then
	command2
...
else
	command3
fi
5.1.1 案例

判断两台主机是否ping的通

mgh@ubuntu:~/shell_script$ ping -c1 www.baidu.com       # -c 参数表示次数
PING www.a.shifen.com (112.80.248.76) 56(84) bytes of data.
64 比特,来自 112.80.248.76 (112.80.248.76): icmp_seq=1 ttl=128 时间=11.1 毫秒

--- www.a.shifen.com ping 统计 ---
已发送 1 个包, 已接收 1 个包, 0% 包丢失, 耗时 0 毫秒
rtt min/avg/max/mdev = 11.063/11.063/11.063/0.000 ms
mgh@ubuntu:~/shell_script$ echo $?
0
# 代码:ping_test.sh
#!/bin/env bash

if [ -z $1 ];then                               # -z 判断字符串是否为空
        echo "error, please input ip or host"
    else
        ping -c1 $1 > /dev/null                 # 将输出结果重定向到黑洞中,也就是不显示结果
        if [ $? -eq 0 ];then
                echo "ping $1 ok"
            else
                echo "ping $1 fail"
        fi
fi
# 执行结果
mgh@ubuntu:~/shell_script$ ./ping_test.sh
error, please input ip or host
mgh@ubuntu:~/shell_script$ ./ping_test.sh www.baidu.com
ping www.baidu.com ok

判断进程是否存在

ps -ef | grep docker | grep -v "grep"    # -v 参数 过滤字段

代码:

#!/bin/env bash

if [ -z $1 ];then
		echo "error, please input process name"
	else
		ps -ef | grep $1 | grep -v "grep" | grep -v $0 > /dev/null  # 要排除grep进程和当前shell进程
		[ $? -eq 0 ]  && echo "$1进程存在" || echo "$1进程不存在"
fi


5.2 循环语句

5.2.1 for循环

(1)、列表循环

语法格式

for variable in {list}
do 
	command
	command
	...
done
	
或者
for variable in a b c
do 
	command
	command
	...
done
# 例如:for_test.sh

#!/bin/env bash

for i in {1..5}
	do
		echo "i=$i"
	done
	
# 执行结果:
mgh@ubuntu:~/shell_script$ ./for_test.sh
i=1
i=2
i=3
i=4
i=5
{1..10} 表示从1到10
{1..100..2} 表示1 3 5 7 9... ,2表示步长

seq 可以生成序列
# 例如
mgh@ubuntu:~/shell_script$ seq 3
1
2
3

mgh@ubuntu:~/shell_script$ for i in $(seq 5);do echo $i;done
1
2
3
4
5

(二)、不带列表循环

执行时由用户指定,也就是执行脚本时带的参数,有多少个参数执行多少次

for variable
	do 
		command
		command
		...
	done
	
# 例如 for_test2.sh
#!/bin/bash

for i
do
    echo "hello,world"
done

# 执行结果
mgh@ubuntu:~/shell_script$ ./for_test2.sh a b c
hello,world
hello,world
hello,world

(三)、类C风格

for((expr1;expr2;expr3))
do
	command
	command
	...
done

# 例如
for((i=0;i<5;i++))
do
	echo $i
done
5.2.2 while循环
while expression
do
	command
	...
done

# 例如:
while [ 1 -eq 1 ] 或者 ((1==1))
do
	command
	command
done

案例:脚本同步系统时间

需求:

  1. 写一个脚本,30s同步一次系统时间,时间同步服务器203.107.6.88
  2. 如果同步失败,则进行邮件报警,每次失败都报警
  3. 如果同步成功也报警,但是成功100次才报警

思路:

  1. 每30s同步一次,脚本是个死循环
  2. 同步失败发送邮件,1)ntp date 203.107.6.88 2)rdate -s 203.107.6.88

代码

#!/bin/bash

NTP_SERVER=203.107.6.88
count=0

while true
do
	ntpdate $NTP_SERVER > /dev/null
	if [ $? -ne 0 ];then          # 执行失败
		echo "system update time failed" | mail -s "check system time " root@localhost
	else
		let count++
		if [ $[$count%100] -eq 0 ];then
			echo "system update time failed" | mail -s "check system time " root@localhost
		fi
	fi
	
	sleep 30
done
5.2.3 影响shell程序的内置命令
exit		退出整个程序
break		结束当前循环
continue	忽略本次循环的代码,直接进入下一次循环
shift		脚本输入的参数向左移一位 也可以移多位:shift 2

6、随机数

系统变量:RANDOM,默认会产生0~32767的随机整数

mgh@ubuntu:~/shell_script$ echo $RANDOM
14073
mgh@ubuntu:~/shell_script$ echo $RANDOM
8299
mgh@ubuntu:~/shell_script$ echo $RANDOM
31547

# 产生0~100的随机数
mgh@ubuntu:~/shell_script$ echo $[$RANDOM%101]
77

# 产生10~100的随机数
mgh@ubuntu:~/shell_script$ echo $[$RANDOM%91+10]
93

6.1 案例

6.1.1 随机产生139开头的电话号码

需求:

写一个脚本,生成一个phonenum.txt文件,随机产生139开头的手机号1000个,每行一个

代码1:

#!/bin/env bash

FILE_PATH="phone.txt"

for i in {1..1000}
do
	let phonenum=139$[$RANDOM%9000+1000]$[$RANDOM%9000+1000]  # $[$RANDOM%9000+1000]产生1000~9999
	echo $phonenum >> $FILE_PATH
done

代码2:

#!/bin/env bash

FILE_PATH="phone.txt"

for i in {1..1000}
do
	phonenum=139
	for i in {1..8}
	do
		let n=$[$RANDOM%10]           # 一次生成一位,最后拼接
		let phonenum=$phonenum$n
	done
	echo $phonenum >> $FILE_PATH
done
6.1.2 随机抽取5位幸运观众

需求:

在上面的1000个手机号码里抽取5个号码作为幸运观众,显示这五个幸运观众

但只显示头3位和尾4位,中间的用*代替

代码:

#!/bin/env bash

# 生成5个0~1000的随机数,数子对应的行的电话就是幸运观众的号码

FILE_PATH="phone.txt"

for i in {1..5}
do
	line=`wc -l $FILE_PATH | cut -d ' ' -f1`          # 获取文件行数
	let luck_line=$[$RANDOM%$line+1]
	luck_num=`head -$luck_line $FILE_PATH | tail -1`
	echo "第$i位幸运观众的号码:"
	echo "139****${luck_num:7:4}"
	sed -i "/$luck_num/d" $FILE_PATH                    # 从文件中删除该行	
done

7、数组定义

数组分类

  • 普通数组:只能使用整数作为数组索引
  • 关联数组:可以使用字符串作为数组索引

7.1 普通数组定义

  • 一次赋一个值
arr[index]=value

# 例如
arr[0]=v1
arr[1]=v2
  • 一次赋予多个值
arr=(val1 val2 val3 ...)

# 例如
namearr=(zhangsan lisi wangwu)

# 将命令的执行结果赋给数组
files=(`ls /root`)

7.2 数组读取

${arr[index]}

echo ${arr[0]}		获取第一个元素
echo ${arr[*]}		获取所有元素
echo ${#arr[*]}		获取所有元素个数
echo ${!arr[@]}		获取元素的索引下标

declare -a		定义普通数组或查看所有普通数组
declare -A		定义关联数组查看所有关联数组

7.3 、关联数组定义

  • 定义关联数组
# 需要先声明才能使用
declare -A arr
  • 一次赋一个值
arr[key]=val

# 例如
inf[name]=zhangsan
inf[age]=lisi
  • 一次赋多个值
arr=([name]=zhangsan [age]=18 [addr]=hangzhou)

8、case语句

语法结构

case var in
pattern 1)      # 模式1,用|分割多个模式,相当于or
	command1	# 执行的语句
	;;			# 两个分号表示命令结束
pattern 2)
	command2
	;;
pattern 3)
	command3
	;;
*)				# default,默认执行
	command4
	;;
esac			# 语句结束

案例:给脚本传不同的参数,做不同的事

#!/bin/env bash

case $1 in
start|S)
	echo "server is running"
	;;
stop|T)
	echo "server is stopping"
	;;
reload|R)
	echo "server is reloading"
	;;
esac

9、函数

9.1 定义函数

# 方法一
函数名()
{
	函数体
}

# 方法二
function 函数名()
{
	函数体
}

9.2 调用函数

# 定义函数文件 func1.sh

hello()
{
	echo "hello,world"
}

# 在终端中执行
source func1.sh
hello

# 在脚本文件中调用本文件定义的函数,直接使用函数名
hello

# 在脚本中调用其它文件定义的函数,也需要先source
source /etc/func.sh
hello

# 函数传参,直接跟在函数后
hello 1 2 3 
# 函数中使用 $1 $2 ...来使用参数
第1章 BashShell命令 6 1.1 Shell提示符 6 1.2 文件与目录Shell命令 7 1.2.1 更改目录命令(cd) 7 1.2.2 列表命令(ls) 7 1.2.3 操作文件命令 10 1.2.4 目录处理命令 14 1.2.5 查看文件内容命令 15 1.3 监控程序 20 1.3.1 进程查看 20 1.3.2 实时进程监控 22 1.3.3 停止进程 24 1.4 监控磁盘空间 25 1.4.1 挂载介质 25 1.4.2 使用df命令 26 1.4.3使用du命令 27 1.5 操作数据文件 28 1.5.1 数据排序(sort) 28 1.5.2 搜索数据 (grep) 30 1.5.3 压缩数据 30 1.5.4 归档数据(tar) 33 1.6 使用Linux环境变量 34 1.6.1 设置环境变量 34 1.6.2 默认的shell环境变量与path变量的设置 37 1.7 Linux文件权限 40 1.7.1 Linux安全性 40 1.7.2 使用Linux用户组 46 1.7.3 解码文件权限 47 1.7.4 修改安全设置 49 1.8 vim编辑器 52 第2章 基本脚本编译 54 2.1 创建脚本与使用变量 54 2.1.1 创建脚本 54 2.1.2 使用变量 55 2.2 重定向输入输出与数学计算 57 2.2.1 输出重定向 57 2.2.2 输入重定向 58 2.2.3 管道 58 2.2.4 数学计算 58 2.3 退出脚本 60 第3章 结构化命令 61 3.1 if语句 61 3.1.1 if-then语句 61 3.1.2 if-then-else语句 61 3.1.3 嵌套if语句 62 3.2 if条件语句 63 3.2.1 数值比较 63 3.2.2字符串比较 64 3.2.3 文件比较 65 3.2.4 复合条件检查 65 3.3 if-then的高级特征与case命令 66 3.3.1 使用双圆括号 66 3.3.2 使用双方括号 67 3.3.3 case命令 67 3.4 for命令 67 3.4.1 读取列表 68 3.4.2 读取变量与读取命令 69 3.4.3 改变字段分隔符与使用通配符读取目录 69 3.4.5 C式的for命令 70 3.5 while、until命令 71 3.5.1 使用多条测试命令 71 3.5.2 until命令与循环嵌套 72 3.6 文件数据的循环与控制循环 73 3.6.1 文件数据的循环 73 3.6.2 break命令 73 3.6.3 continue命令 75 第4章 处理用户输入与显示数据 76 4.1 命令行参数与特殊的参数变量 76 4.1.1 读取参数 76 4.1.2 读取程序名称 77 4.1.3 测试参数 77 4.1.4 参数计数 77 4.1.5 获取所有数据 78 4.2 移位与选项 79 4.2.1 移位 79 4.2.2 找出选项 79 4.2.3 使用getopt命令 81 4.2.4 更高级的getopts命令 83 4.2.4 标准化选项 84 4.3 获取用户输入 84 4.3.1 基本读取 84 4.3.2 计时 85 4.3.3 默读与文件读取 85 4.4 显示数据 86 4.4.1 标准文件描述符 86 4.4.2 重定向错误 87 4.4.3 临时重定向 88 4.4.4永久重定向 88 4.4.5 在脚本中重定向输入 89 4.5 创建自己的重定向 90 4.5.1 创建输出文件描述符 90 4.5.2 重定向文件描述符 90 4.5.3 创建输入文件描述符 91 4.5.4 创建读取/写入文件描述符 91 4.5.5 关闭文件描述符 92 4.5.6列出开发文件描述符 92 4.5.7禁止命令输出 94 4.6 使用临时文件 94 4.6.1 创建本地临时文件 94 4.6.2 在/temp中创建临时文件 95 4.6.3 创建临时目录 96 4.6.4 记录消息 96 第5章 脚本控制 97 5.1 处理信号 97 5.1.1 Linux信号回顾 97 5.1.2 生成信号 97 5.1.3捕获信号 99 5.1.4捕获脚本退出 99 5.1.4移除捕获 100 5.2 以后台模式运行脚本 100 5.3 作业控制 102 5.3.1查看作业 102 5.3.2重新启动停止的作业 103 5.4 nice与renice命令 104 5.4.1 nice命令 104 5.4.2 renice命令 104 5.5 定时运行脚本 105 5.5.1使用at命令调度作业 105 5.5.2使用batch命令调 107 5.5.3 调用定期脚本 107 5.6 从头开始 109 5.6.1在启动时启动脚本 109 5.6.2随新shell一起启动 109 第6章 创建函数 110 6.1 基本脚本函数 110 6.1.1 创建函数 110 6.1.2 使用函数 110 6.2 返回值 111 6.2.1 默认退出状态 111 6.2.2 使用return命令 111 6.2.3 使用函数输出 112 6.3 在函数中使用变量 112 6.3.1 向函数传递参数 112 6.3.2 在函数中处理变量 113 6.4 数组变量与函数 114 6.4.1 向函数传递数组 114 6.4.2从函数返回数组 115 6.5 函数递归与创建库 116 6.5.1函数递归 116 6.5.2 创建库 116 6.6 在命令行中使用函数 117 6.6.1在命令行创建函数 117 6.6.2在.bashrc文件中定义函数 117 6.7 select命令使用 119 第7章 sed、gawk介绍与正则表达式 120 7.1 sed编辑器 120 7.1.1 在命令行中定义编辑器命令 120 7.1.2 在命令行中使用多个编辑器命令 121 7.1.3 从文件读取编辑器命令 121 7.2 gawk程序 122 7.2.1 gawk命令格式 122 7.2.2 自命令行读取程序脚本 122 7.2.3 使用数据字段变量 123 7.2.4 在程序脚本中使用多个命令 124 7.2.5从文件读取程序 124 7.2.6 在处理数据之前运行脚本 125 7.2.7 在处理数据之后运行脚本 125 7.3 sed编辑器基础知识 126 7.3.1 更多替换选项 126 7.3.2 使用地址 127 7.3.3 删除行 128 7.3.4 插入和附加文本 129
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值