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 ...来使用参数
  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值