程序编程的风格
面向过程(Procedure Oriented 简称PO :如C语言):
从名字可以看出它是注重过程的。当解决一个问题的时候,面向过程会把事情拆分成: 一个个函数和数据(用于方法的参数) 。然后按照一定的顺序,执行完这些方法(每个方法看作一个过程),等方法执行完了,事情就搞定了。
面向对象(Object Oriented简称OO :如C++,JAVA等语言):
看名字它是注重对象的。当解决一个问题的时候,面向对象会把事物抽象成对象的概念,就是说这个问题里面有哪些对象,然后给对象赋一些属性和方法,然后让每个对象去执行自己的方法,问题得到解决。
编程 的三种处理逻辑
顺序执行:程序按从上到下顺序执行
选择执行:程序执行过程中,根据条件的不同,进行选择不同分支继续执行
循环执行:程序执行过程中需要重复执行多次某段语句(已知次数 已知条件 死循环)
Linux 系统中的 Shell 是一个特殊的应用程序,它介于操作系统内核与用户之间,充当了一个“命令解释器”的角色,负责接收用户输入的操作指令(命令)并进行解释,将需要执行的操作传递给内核执行,并输出执行结果。
常见的 Shell 解释器程序有很多种,使用不同的 Shell 时,其内部指令、命令行提示符等方面会存在一些区别。通过 /etc/shells 文件可以了解当前系统所支持的 Shell 脚本种类。
[root@localhost data]#cat /etc/shells //查看当前的系统支持的shell
/bin/sh
/bin/bash
/sbin/nologin
/usr/bin/sh
/usr/bin/bash
/usr/sbin/nologin
/bin/tcsh
/bin/csh
linux 中常见的 shell
shell脚本用途
其构成为
1.脚本申明(解释器):第一行开头“#!/bin/bash”,表示此行以下的代码语句是通过/bin/bash程序来解释执行。#!/bin/bash 为默认的解释器还有其他类型的解释器,
#!/bin/python #!/bin/expect
2.注释信息 :以 # 开头的为注释信息。 # 注释
3.可执行语句 :如 echo '你好' 的意思就是 输出 ' ' 中的字符串。
vim fist.sh
#!/bin/bash
echo 'hello word'
echo '当前所在位置:'
pwd
搭建本地yum仓库
[root@localhost data]#cat yum.sh
#!/bin/bash
mkdir /gua
mount /dev/sr0 /gua
cd /etc/yum.repos.d
mkdir bak
mv *.repo bak
echo "[local]
name=local
baseurl=file:///gua
gpgcheck=0" >/etc/yum.repos.d/local.repo
yum clean all
yum makecache
[root@localhost data]#bash yum.sh
mount: /dev/sr0 写保护,将以只读方式挂载
已加载插件:fastestmirror, langpacks
正在清理软件源: local
Cleaning up everything
Maybe you want: rm -rf /var/cache/yum, to also free up space taken by orphaned data from disabled or removed repos
Cleaning up list of fastest mirrors
已加载插件:fastestmirror, langpacks
local | 3.6 kB 00:00:00
(1/4): local/group_gz | 156 kB 00:00:00
(2/4): local/filelists_db | 3.1 MB 00:00:00
(3/4): local/primary_db | 3.1 MB 00:00:00
(4/4): local/other_db | 1.2 MB 00:00:00
Determining fastest mirrors
元数据缓存已建立
脚本执行逻辑
顺序执行:程序按从上到下顺序执行
选择执行:程序执行过程中,根据条件的不同,进行选择不同分支继续执行
循环执行:程序执行过程中需要重复执行多次某段语句
脚本执行方式
1.使用路径执行 (需要执行权限)
[root@localhost ~]# chmod +x /root/host.sh 加权限
指定相对路径./host.sh
指定绝对路径/root/host.sh
2.直接使用解释器 (不需要执行权限)
[root@localhost data]#bash fist.sh
hello
[root@localhost data]#ll fist.sh
-rw-r--r--. 1 root root 25 1月 22 15:57 fist.sh
3.source 和 . 执行 (不需要执行权限)
[root@localhost data]#source fist.sh
hello
[root@localhost data]#
[root@localhost data]#. fist.sh
hello
使用 前两种 方式执行脚本会开启 子 bash 环境去执行脚本。
使用 source 和 . 会影响当前的 bash 环境。 不推荐使用
例如:
[root@localhost data]#cat q.sh
#!/bin/bash
echo 'hello'
cd /mnt
touch 123
# 使用 bash 执行这个脚本
[root@localhost data]#bash q.sh
hello
[root@localhost data]#ll /mnt
总用量 0
-rw-r--r--. 1 root root 0 1月 22 16:02 123
可以看到 bash 对当前终端无影响 ,我们试试用 source
[root@localhost data]#source q.sh
hello
[root@localhost mnt]#
[root@localhost mnt]#ls
123
可以看到 脚本里的 cd /mnt 命令在当前终端执行了 ,影响了当前终端。
1、命令错误
命令出错不会影响接下来的命令继续
[root@localhost mnt]#vim 1.sh
echo "hello world"
hstname
ifconfig ens33|head -n2
[root@localhost mnt]#bash 1.sh
hello world
1.sh:行2: hstname: 未找到命令
ens33: flags=4163 mtu 1500
inet 192.168.80.7 netmask 255.255.255.0 broadcast 192.168.80.255
2、语法错误
会影响接下来的命令继续
[root@localhost mnt]#vim 1.sh
echo "hello world"
hstname
cat > /data/kgc.tx <
3、逻辑错误
只能自己去筛查
bash -n 脚本名称 (不在当前目录下加绝对路径) 检查语法错误
bash -x 脚本名称 (不在当前目录下加绝对路径) 逻辑错误
bash -n 脚本名称
检测语法错误
bash -x 脚本名称
将脚本的所有语句执行一遍。
总结:脚本错误常见的有三种区别
1. 语法错误,会导致后续的命令不继续执行,可以用bash -n 检查错误,提示的出错行数不一定是准确的。
2. 命令错误,默认后续的命令还会继续执行,用bash -n 无法检查出来 ,可以使用 bash -x 进行观察。
3. 逻辑错误:只能使用 bash -x 进行观察。
set -e 出错立即停止
[root@localhost mnt]#vim 1.sh
set -e #在 脚本的前面输入 set -e 一旦出错立即停止
echo "hello world"
hstname
ifconfig ens33|head -n2
[root@localhost data]#bash 1.sh
hello world
1.sh:行3: hstname: 未找到命令
set -u 变量不存在不执行
set -u 变量不存在不让执行
DIR=/opt
rm -rf $DIr/data #!!!!!!!注意 /data 前面变量不在无异于 rm -rf /data
类型 | 设备文件 | 文件描述编号 | 默认设备 |
---|---|---|---|
标准输入 | /dev/stdin | 0 | 键盘 |
标准输出 | /dev/stdout | 1 | 显示器 |
标准错误输出 | /dev/stderr | 2 | 显示器 |
交互式硬件设备
重定向的意思就是 ,不输出到默认设备上,输出到你指定的位置
1 代表 正确输入
2 代表 错误输入
& 代表混合
类型 | 操作符 | 用途 |
---|---|---|
重定向输入 | < | 从指定的文件读取数据,而不是从键盘输入 |
重定向输出 | 1> | 将输出结果保存到指定的文件(覆盖原有内容) |
追加输出 | >> | 将输出结果追加到指定的文件尾部 |
标准错误输出 | 2> | 将错误信息保存到指定的文件(覆盖原有内容) |
追加错误输出 | 2>> | 标准错误输出结果追加到指定的文件尾部 |
混合输出 | &>无论对错都可以重定向 | 将标准输出、标准错误的内容保存到同一个文件中 |
[root@localhost ~]#ls >/dev/pts/1
#打开两个终端,ls命令显示到终端1上 标准重定向省略了1>
[root@localhost ~]#xxx >/dev/pts/1
##错误重定向
bash: xxx: 未找到命令...
[root@localhost ~]#xxx 2>/dev/pts/1
##会在另一边显示
[root@localhost ~]#rm xxx.txt >/dev/pts/1
#提示信息也是错误
rm: 无法删除"xxx.txt": 没有那个文件或目录
[root@localhost ~]#rm xxx.txt 2>/dev/pts/1
[root@localhost ~]#ls /data /error >all.log 2>&1
#既有错误也有正确 &符号表示分隔符
[root@localhost ~]#cat all.log
ls: 无法访问/error: 没有那个文件或目录
/data:
apr-1.6.2.tar.gz
apr-util-1.6.0.tar.gz
httpd-2.4.29.tar.bz2
[root@localhost ~]#ls /data /error >all.log 2>1
#如果没有&会生成一个 1文件 将错误导入
[root@localhost ~]#cat bc.log
2*6
[root@localhost ~]#bc passwd.txt //单个覆盖,多个不覆盖追加
[root@test1 ~]# cat passwd.txt
123123
[root@test1 ~]# ls > passwd.txt //将命令结果放进文本中
[root@test1 ~]# cat passwd.txt
bin
cpu
disk.sh
first.sh
f.sh
gs.sh
g.txt
passwd.txt
sdb.sh
source
test.sh
[root@test1 ~]# cat passwd.txt
123123
[root@test1 ~]# echo "123123" >> passwd.txt
[root@test1 ~]# cat passwd.txt
123123
123123
[root@test1 ~]# id wa 2>error.log //将错误信息写入error.log
[root@test1 ~]# cat error.log
id: wa: no such user
[root@test1 ~]# id wa >error.log //不加2 无法写入
id: wa: no such user
[root@test1 ~]# cat passwd.txt error.log &>new //混合输入无论对错
[root@test1 ~]# cat new
bin
cpu
disk.sh
first.sh
f.sh
gs.sh
g.txt
passwd.txt
sdb.sh
source
test.sh
cat: error.log: 没有那个文件或目录
有几种方法 将错误结果和正确结果一起导给 一个文件中?
[root@centos7 ~]#ls /data /xxx 1> /data/all.log 2>&1
[root@centos7 ~]#ls /data /xxx 2> /data/all.log 1>&2
[root@centos7 ~]#ls /data /xxx &> /data/all.log
[root@centos7 ~]#ls /data /xxx >& /data/all.log
#以上方法可以把 错误输出和正确输出 一起导给 /data/all.log 文件中
[root@centos7 ~]#ls /data /xxx 2>&1 1> /data/all.log
[root@centos7 ~]#ls /data /xxx 1>&2 2> /data/all.log
#此命令不行
Here Document 概述
使用 I/O 重定向的方式将命令列表提供给交互式程序或命令,比如 ftp、cat 或 read 命令。
HereDocument是标准输入的一种替代品,
可以帮助脚本开发人员不必使用临时文件来构建输入信息,
而是直接就地生产出一个文件并用作命令的标准输入。
[root@localhost data]#wc -l < 123
> 123
> EOF
2
[root@localhost ~]#cat > 1.txt
#需要回车才会写入
hhh
111
123
[root@localhost ~]#cat >file.txt <11.txt < 123
> 345
> 567
> EOF
#####修改密码
[root@localhost data]#passwd zhangsan < 123123
> 123123 #需要输入两次密码
> EOF
更改用户 zhangsan 的密码 。
新的 密码:无效的密码: 密码少于 8 个字符
重新输入新的 密码:passwd:所有的身份验证令牌已经成功更新。
###变量赋值
[root@localhost ~]# read a < 10
> EOF
[root@localhost ~]# echo $a
10
[root@localhost data]#read i < fcks
> EOF
[root@localhost data]#echo $i
fcks
支持变量替换
在写入文件时会先将变量替换成实际值,再结合 cat 命令完成写入
#!/bin/bash
file="EOF1.txt"
i="school"
cat > $file <
将左侧的命令输出结果,作为右侧命令的输入(处理对象)可以 叠加使用
[root@localhost opt]# ls /opt |wc
2 2 12
修改密码
[root@localhost opt]# echo "123123" |passwd --stdin zhangsan
更改用户 zhangsan 的密码 。
passwd:所有的身份验证令牌已经成功更新
[root@test1 ~]# grep "/bin/bash$" /etc/passwd
root:x:0:0:root:/root:/bin/bash
zhangsan:x:1000:1000:zhangsan:/home/zhangsan:/bin/bash
lisi:x:1001:1001::/home/lisi:/bin/bash
[root@test1 ~]# grep "/bin/bash$" /etc/passwd | awk -F: '{print $1,$7}'
root /bin/bash
zhangsan /bin/bash
lisi /bin/bash
变量来源于数学,是计算机语言中能储存计算结果或能表示值的抽象概念。
保存将来会变化的数据,即使数据变化,直接调用变量即可,各种 Shell 环境中都使用到了“变量”的概念。Shell 变量用来存放系统和用户需要使用的特定参数(值),而且这些参数可以根据用户的设定或系统环境的变化而相应变化。通过使用变量,Shell 程序能够提供更加灵活的功能,适应性更强。
常见 Shell 变量的类型包括:
自定义变量 :由用户自己定义,修改和使用
预定义变量 :Bash中内置的一类变量 shell 不能修改 规定好的变量 放在那里让你使用
环境变量:由系统维护,用于设置工作环境 当前目录 当前主机名啊 $PATH
只读变量:只可以读取不可以更改 只能不能修改 常量
位置变量:通过命令行给脚本传递参数
系统内置变量:PATH,UID,HOSTNAME,USER
可以使用 unset 删除变量。
name='value'
变量名=变量值
变量名开头不能有数字
[root@localhost ~]#1a=1x
bash: 1a=1x: 未找到命令...
直接字串:name='root'
变量引用:name="$USER"
命令引用:name=`COMMAND` 或者 name=$(COMMAND)
注意:变量赋值是临时生效,当退出终端后,变量会自动删除,无法持久保存,脚本中的变量会随着脚本结束,也会自动删除
重要符号
双引号 " " 弱引用 可以识别变量
单引号 ' ' 强引用 不能识别变量
弱引用和强引用
"$name " 弱引用,其中的变量引用会被替换为变量值
'$name' 强引用,其中的变量引用不会被替换为变量值,而保持原字符串
{ } 定义变量名的范围
` `反撇 调用命令执行的结果 与$() 功能一样
定义变量
变量名=变量值 a=10
调用变量
echo $a
[root@localhost opt]# producet=qwq
[root@localhost opt]# echo $producet
qwq
[root@localhost opt]# version=y
[root@localhost opt]# echo $producet$version
qwqy
[root@localhost opt]# echo "$producet$version"
qwqy
[root@localhost opt]# echo '$producet$version'
$producet$version
[root@localhost opt]# echo $producet6.0
.0
[root@localhost opt]# echo ${producet}zxz
qwqzxz
[root@localhost opt]# echo ${producet}$version
qwqy
[root@node2 ~]#name=xiaoming
[root@node2 ~]#title=cto
[root@node2 ~]#echo $title_$name
xiaoming
[root@localhost ~]#echo ls
ls
[root@localhost ~]#echo $(ls)
abc.txt anaconda-ks.cfg initial-setup-ks.cfg 公共 模板 视频 图片 文档 下载 音乐 桌面
[root@localhost ~]#echo `ls`
abc.txt anaconda-ks.cfg initial-setup-ks.cfg 公共 模板 视频 图片 文档 下载 音乐 桌面
1.赋值时使用双引号(" ")可以直接调用变量
2.赋值时使用单引号(' ')变量$只会被认为是字符$ 不会调用变量
3.赋值时使用(``反撇在tab上面)命令替换,提取命令执行后的输出结 果 和$( ) 用法相同
4.{}可以分隔变量值
变量追加值
追加变量
变量名+=追加内容
[root@localhost ~]#name=wang
[root@localhost ~]#
[root@localhost ~]#echo $name
wang
[root@localhost ~]#name+=yi
[root@localhost ~]#
[root@localhost ~]#echo $name
wangyi
修改环境变量
PATH+=:/data
[root@localhost ~]#vim /etc/profile
PATH="/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/root/bin:/data"
交互式输入变量值 ,然后使用变量
方法1:
[root@localhost ~]#read -p "请输入ip地址:" ip #这个ip是变量名
请输入ip地址:192.168.80.7 #手动输入192.168.80.7
[root@localhost ~]#ping -c2 $ip
PING 192.168.80.7 (192.168.80.7) 56(84) bytes of data.
64 bytes from 192.168.80.7: icmp_seq=1 ttl=64 time=0.040 ms
64 bytes from 192.168.80.7: icmp_seq=2 ttl=64 time=0.034 ms
--- 192.168.80.7 ping statistics ---
2 packets transmitted, 2 received, 0% packet loss, time 1000ms
rtt min/avg/max/mdev = 0.034/0.037/0.040/0.003 ms
[root@localhost data]#vim xxi.sh
#!/bin/bash
read -p "输入你的班级名称:" ban1
echo "您的班级是$ban1"
sleep 2
read -p "输入你的学号:" xue1
echo "您的学号是$xue1"
如何使用脚本计算小数相加?
[root@localhost data]#vim xiaoshu.sh
#!/bin/bash
read -p "输入第一个数字:" a1
read -p "输入第二个数字:" a2
echo "计算结果为:`echo "$a1+$a2"|bc`"
[root@localhost data]#bash xiaoshu.sh
输入第一个数字:1.3
输入第二个数字:1.15
计算结果为:2.45
方法2:
[root@localhost opt]# vim 1.sh
#!/bin/bash
echo -n "请输入你的信息"
read info
echo $info
[root@localhost data]#bash 1.sh
请输入你的信息12121
12121
#12121是输入完后回车的结果
[root@test1 ~]# vim xinxi.sh
#!/bin/bash
echo "请输入你的班级"
read num1
echo "您输入的班级是$num1"
sleep 2
echo "请输入你的学号"
read num2
echo "您输入的学号是$num2"
运用:
[root@localhost opt]# vim 1.sh
#!/bin/bash
read -p "是否覆盖当前文件(yes/no)" ACK
[ $ACK = "yes" ] && echo "覆盖" || echo "不覆盖"
[root@localhost data]#bash 1.sh
是否覆盖当前文件(yes/no)no
不覆盖
[root@localhost data]#bash 1.sh
是否覆盖当前文件(yes/no)yes
覆盖
默认情况下,新定义的变量只在当前的shell环境中有效,因此称为局部变量,当进入子程序或新的shell环境中,局部变量将无法再起作用。
可以通过内部命令 export 将指定的变量为全局变量,使用户定义的变量在所子shell环境中可以继续使用
方法:
1. 格式1:export 变量名
2. 格式2:export 变量名=变量值
可以使用 pstree 查看 shell 的环境
输入bash 进入子shell
ctrl+D组合 或 输入 exit 退出子shell
举例:
[root@localhost opt]# abc=123
[root@localhost opt]# echo $abc
123
[root@localhost opt]# bash
[root@localhost opt]# echo $abc
为空
[root@localhost opt]# exit
exit
[root@localhost opt]# echo $abc
123
[root@localhost opt]# export abc
#export 变量名 定义全局变量
[root@localhost opt]# bash #进入子shell
[root@localhost opt]# echo $abc
123
运算符:
加法 +
减法 -
乘法 \*
除法 /
取余(取模) %
这些只能进行整数的运算
(1)let 变量名=算数表达式
[root@localhost data]#let sum=1+2
[root@localhost data]#
[root@localhost data]#echo $sum
3
[root@localhost ~]#a=1
[root@localhost ~]#b=2
[root@localhost ~]#let z=a+b
[root@localhost ~]#echo $z
3
[root@localhost ~]#let z=$[a-b]
[root@localhost ~]#echo $z
-1
[root@localhost ~]#let z=$((a-b))
[root@localhost ~]#echo $z
-1
(2)((变量名=算术表达式))
[root@localhost data]#((sum=1+10))
[root@localhost data]#echo $sum
11
[root@localhost ~]#sum=6
[root@localhost ~]#yu=4
[root@localhost ~]#echo $((sum+yu))
10
[root@localhost opt]# echo $((10 + 2))
12
(3)变量名=$[算术表达式]
[root@localhost data]#sum=$[1+123]
[root@localhost data]#echo $sum
124
[root@localhost ~]#sum=6
[root@localhost ~]#yu=4
[root@localhost ~]#echo $[sum+yu]
10
[root@localhost ~]#echo $[10+2]
12
(4)expr
[root@localhost ~]#a=1
[root@localhost ~]#b=2
[root@localhost ~]#expr $a + $b
#加减乘除前后有空格
3
[root@localhost opt]# expr 1+2
1+2
[root@localhost opt]# expr 1 + 2 注意空格
3
[root@localhost opt]# a=20
[root@localhost opt]# b=30
[root@localhost opt]# expr $a + $b
50
[root@localhost opt]# expr $a - $b
-10
[root@localhost opt]# expr $a \* $b
600
[root@localhost opt]# expr $b / $a
1
[root@localhost opt]# expr $b % $a
10
[root@localhost opt]# expr 1 + 2 \* 3
7
[root@localhost opt]# expr 2 \* $[ 3 + 1 ]
8
(5) 变量名=$(expr $arg1 $arg2 $arg3 ...)
[root@localhost ~]#sum=10
[root@localhost ~]#yu=123
[root@localhost ~]#var=$(expr $sum + $yu) #加减乘除前后有空格
[root@localhost ~]#echo $var
133
(6) var= `expr arg1 arg2 arg3 ...`
[root@localhost ~]#sum=10
[root@localhost ~]#yu=123
[root@localhost ~]#cho=`expr $sum + $yu` #加减乘除前后有空格
[root@localhost ~]#echo $cho
133
(7) echo '算术表达式' | bc #能够计算小数
[root@localhost ~]#echo '1.2+12.4'|bc
13.6
[root@localhost opt]# echo "1.2*1.3" |bc
1.5
#计算时有几位,结果就有几位 本来结果应为 1.56
[root@localhost ~]#echo "1.11*2.2"|bc
2.44
[root@localhost ~]#echo "scale=3;1.11*2.2"|bc
2.442
scale=3 :显示四位数字(小数点后三位)
拓展:
let 支持加加减减 使用较多
[root@localhost ~]#i=1
[root@localhost ~]#let i++
[root@localhost ~]#echo $i
2
[root@localhost ~]#i=1;let i++;echo $i
2
[root@localhost ~]#i=1;let ++i;echo $i
2
[root@localhost ~]#i=100;let j=i++;echo $i $j
101 100
[root@localhost ~]#i=100;let j=++i;echo $i $j
101 101
#i++ 是先赋值给ii后再加 ++i是加后再赋值
i++ 是先赋值再加
++i 是加后再赋值
i=$(expr 12 \ * 5 )
i=$((12 * 5))
i=$[12 * 5]
let i=12*5
i++ 相当于 i=$[ $i+1 ]
i-- 相当于 i=$[ $i - 1 ]
i+=2 相当于 i=$[ $i+2 ]
随机数生成器变量:
$RANDOM 取值范围:0-32767
echo $[RANDOM%34]
#这段的意思是输出 0-33 的随机数。
echo $[RANDOM%34 +1]
#加1 后的意思是随机输出 1-34 的随机数。
[root@localhost ~]#echo -e "\E[1;30mhello\E[0m"
#颜色
[root@localhost ~]# echo -e "\E[1;$[RANDOM%7+31]mhello\E[0m"
#随机颜色
[root@localhost ~]#echo $(expr $RANDOM % 33 + 1)
#注意运算符附近都要有空格
如何使用脚本提取系统信息?
#!/bin/bash
name=`hostname`
ip=`ifconfig ens33|grep netmask|tr -s " "|cut -d " " -f3`
cpu=`lscpu|grep 型号名称|tr -s " "|cut -d " " -f2-7`
k=`uname -r`
os=`cat /etc/redhat-release`
disk=`lsblk|grep disk|tr -s " "|cut -d " " -f4`
mem=`free -h|grep -i mem|tr -s " "|cut -d " " -f2`
echo -e "\E[1;32m------------------------system info-----------------------\E[0m"
echo "主机名: $name"
echo "IP地址: $ip"
echo "cpu型号 $cpu"
echo "内核版本 $k"
echo "系统类型 $os"
echo "磁盘大小 $disk"
echo "内存大小 $mem"
echo -e "\E[1;32m------------------------ end -----------------------\E[0m"
1. 由系统提前创建,用来设置用户的工作环境
2. 可以使用env查看环境变量
3. 需要记住的常用环境变量
[root@localhost ftp]#env
#可以看到所有环境变量
$USER 表示用户名称
$HOME 表示用户的宿主目录
$LANG 表示语言和字符集
$PWD 表示当前所在工作目录
$PATH 表示可执行用户程序的默认路径
环境变量:
export命令用于设置或显示环境变量。
#声明并赋值 这样在其它bash 环境里也可以使用此变量
export name=VALUE
declare -x name=VALUE
#或者分两步实现
name=VALUE
export name
系统可以通过$PATH 来执行文件 PATH=$PATH:/root/
[root@localhost opt]# PATH=$PATH:/root/
[root@localhost opt]# echo $PATH
/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/root/bin:/root/
#如果不加 $PATH 的后果
[root@localhost data]#PATH=:/root
[root@localhost data]#echo $PATH
:/root
#可以看到只有/root了
或者可以这样
[root@localhost data]#PATH=/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/root/bin:/root
[root@localhost data]#echo $PATH
/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/root/bin:/root
配置文件位置在
/etc/profile 如果修改此文件会作用于所有用户
~/.bash_profile 用户独立的配置文件,修改这个文件只作用于当前用户
可以用来长期变更或设置环境变量
[root@localhost ~]# vim /etc/profile
.....................省略到行末添加
export PATH=$PATH:/root
保存并退出后更改内容还没有生效 ,使用 source 或 . 立即生效
[root@localhost opt]# source /etc/profile
[root@localhost opt]# . /etc/profile
修改系统默认的命令数
[root@localhost opt]# echo $HISTSIZE #历史命令的最大条数
1000
[root@localhost opt]# vim /root/.bash_profile
export HISTSIZE=200
[root@localhost opt]# source /root/.bash_profile
[root@localhost opt]# echo $HISTSIZE
200
变量值不允许修改(重新赋值)的情况
无法使用 unset删除
最快方法重启
[root@localhost opt]# name=kjk
[root@localhost opt]# readonly name
[root@localhost opt]# echo $name
kjk
[root@localhost opt]# unset name
bash: unset: name: 无法反设定: 只读 variable
#只有退出进程
[root@localhost opt]# echo $name
kjk
[root@localhost opt]# name=jnj
bash: name: 只读变量
位置变量也称为位置参数,使用$1、$2、$3、…、$9 表示
[root@test1 ~]# vim 1.sh
#!/bin/bash
echo "$1" 位置1
echo "$2" 位置2
echo "${10}" 位置10
echo "$10" 位置1和0
echo "$*" 将所有项当成一个值
echo "$@" 所有项
echo "$0" 脚本自身
echo "$#" 后面参数的个数
范例:
[root@test1 ~]# vim weizhi.sh
#!/bin/bash
sum=$[$1+$2]
echo "$1+$2=$sum"
[root@test1 ~]# bash weizhi.sh 12 34 56
12+34=46
[root@test1 ~]#cat qiuhe.sh
#!/bin/bash
i=$1
m=$2
sum=0
let sum=$[i+m]
echo $sum
$* :表示所有位置参数的内容看成一个整体返回 返回所有
$@ :表示所有位置参数的内容分割成n份,每份作为一个独立的个体返回 返回所有
$? :表示前一条命令执行后的返回状态,返回值为 0 表示执行正确,返回任何非 0值均表示执行出现异常
$# :表示命令行中位置参数的总个数
$0 :表示当前执行的脚本或程序的名称 当前脚本的名字
$$ :当前bash的进程id
$! : 后台任务最后一个id
注意:$@ $* 只在被双引号包起来的时候才会有差异
[root@test1 ~]# vim 1.sh
#!/bin/bash
echo "$*" 将所有项当成一个值
echo "$@" 独立个体
echo "$#" 后面参数的个数
注意:$@ $* 只在被双引号包起来的时候才会有差异
将脚本1的结果 $@ 交给3 输出$1
将脚本2的结果 $* 交给3 输出$1
[root@localhost opt]# bash 1.sh a b c
#!/bin/bash
echo "@结果"
./3.sh "$@"
[root@localhost opt]# cat 2.sh 1 2 3
#!/bin/bash
echo "*结果"
./3.sh "$*"
[root@localhost opt]# cat 3.sh
#!/bin/bash
echo "$1"
$* 与 $@ 的区别
[root@localhost data]#vim dayin.sh
#!/bin/bash
echo "打印出\$*"
for var in "$*"
do
echo "$var"
done
echo "打印出\$@"
for var in "$@"
do
echo "$var"
done
[root@localhost data]#bash dayin.sh 12 123 1234
打印出$*
12 123 1234
打印出$@
12
123
1234
由此可以看出 ,$* 是把 12 123 1234 当做一个整体来输出的
$@ 是把 12 123 1234 当作几个个体来输出的
格式1:test 条件表达式
格式2:[ 条件表达式 ]
注意[]空格,否则会失败
测试 是否成功使用 $? 返回值
[ 操作符 文件或目录 ]
help test
操作符:
-d:测试是否为目录(Directory)
-e:测试目录或文件是否存在(Exist)
-a:测试目录或文件是否存在(Exist)
-f:测试是否为文件(File)
-r:测试当前用户是否有权限读取(Read)
-w:测试当前用户是否有权限写入(Write)
-x:测试当前用户是否有权限执行(eXcute)
-L: 测试是否为软连接文件
属性测试补充:
-s FILE #是否存在且非空
-t fd #fd 文件描述符是否在某终端已经打开
-N FILE #文件自从上一次被读取之后是否被修改过
-O FILE #当前有效用户是否为文件属主
-G FILE #当前有效用户是否为文件属组
条件测试:判断某需求是否满足,需要由测试机制来实现,专用的测试表达式需要由测试命令辅助完成
测试过程,实现评估布尔声明,以便用在条件性环境下进行执行
若真,则状态码变量 $? 返回0
若假,则状态码变量 $? 返回1
条件测试命令
例子:
[root@test1 ~]# test -d /etc/sysconfig
[root@test1 ~]# echo $?
0
[root@test1 ~]# test -f /etc/sysconfig
[root@test1 ~]# echo $?
1
[root@test1 ~]# [ -d /etc/sysconfig/ ] 注意前后空格
[root@test1 ~]# echo $?
0
[root@test1 ~]# [ -f /etc/sysconfig/ ]
[root@test1 ~]# echo $?
1
[root@localhost ~]# test -e qiuhe.sh &&echo "yes"
yes
&&表示且的意思 前面的表达式成立才会输出yes
[root@localhost ~]#ll /etc/shadow
---------- 1 root root 1549 10月 19 10:58 /etc/shadow
[root@localhost ~]#[ -r /etc/shadow ]
[root@localhost ~]#echo $?
0
#实际效果,不是表面显示,注意root权限
[root@localhost ~]#[ -x /etc/shadow ]
[root@localhost ~]#echo $?
1
#root执行权限别人没有root也没有,别人有root也有
###a 和 e 的区别
[root@localhost ~]#[ ! -e /etc/shadow ]
[root@localhost ~]#echo $?
1
[root@localhost ~]#[ ! -a /etc/shadow ]
[root@localhost ~]#echo $?
0
##建议使用e选项
[ 整数1 -操作符 整数2 ] 公式
实例:
[ 整数1 操作符 整数2 ]
[root@test1 ~]# a=2
[root@test1 ~]# b=3
[root@test1 ~] [ $a -eq $b ]
[root@test1 ~]# echo $?
1
[root@test1 ~]# [ 2 -le 3 ]
[root@test1 ~]# echo $?
0
常用的测试操作符
=:字符串内容相同
!=:字符串内容不同,! 号表示相反的意思
-z:字符串内容为空
-n: 字符是否存在
格式
[ 字符串1 = 字符串2 ] 是否相同
[ 字符串1 != 字符串2 ] 是否不相同
[ -z 字符串 ] 是否为空
[ -n 字符串 ] 字符是否存在
[root@localhost data]#str1=wang
[root@localhost data]#str2=zhou
[root@localhost data]#[ $str1 = $str2 ]
[root@localhost data]#echo $?
1
#不相同
[root@localhost etc]# [ $USER = root ]&& echo true
true
#当前用户为 root 输出 true
[root@localhost etc]# [ $USER != root ]&& echo true
#当前用户不是 root 输出 true ,否 则输出空行
[root@localhost etc]# read -p "yes/no:" ack
yes/no:
#直接回车
[root@localhost etc]# echo $ack
[root@localhost etc]# [ -z $ack ] && echo true
true
#判断 变量ack是否为空 ,如果 是 输出true ,不为 空 输出空行
[root@192 ~]# read -p "是否覆盖当前文件 (yes/no)" ACK
是否覆盖当前文件 (yes/no)yes
[root@192 ~]# [ $ACK = "yes" ] && echo "覆盖"
覆盖
[root@192 ~]# read -p "是否覆盖当前文件 (yes/no)" ACK
是否覆盖当前文件 (yes/no)no
[root@192 ~]# [ $ACK = "no" ] && echo "不覆盖"
不覆盖
格式1:[ 表达式1 ] 操作符 [ 表达式2 ] ...
格式2:命令1 操作符 命令2 ...
常见条件:
(1) -a 与 &&
[ $a -ne 1 ]&&[ $a != 2 ] #变量 a 不等于 1 且 变量 a 不等于 2
CMD1 && CMD2
一样的效果 ,不同的形式。
[ $a -ne 1 -a $a != 2 ] #变量 a 不等于 1 且 变量 a 不等于 2
[[ $a -ne 1 && $a != 2 ]]
全真才为真 一假即为假
第一个CMD1结果为真 ,第二个CMD2必须要参与运算,才能得到最终的结果
第一个CMD1结果为假 ,总的结果必定为假,因此不需要执行CMD2
[root@localhost data]#a=6
#变量大于等于7 且 变量等于6
[root@localhost data]#[ $a -ge 7 -a $a -eq 6 ] && echo true || echo false
false
(2)-o 与 ||
CMD1 CMD2 CMD3
[root@localhost etc]# [ 4 -lt 5 ] && echo true || echo false
true
#判断 4 是否小于 5 ,若小于 输出 true (不执行echo false),若不小于 直接执行 echo false。
[root@localhost data]#[ 6 -lt 5 ] &&echo true || echo false
false
[root@localhost data]#a=6
#变量大于等于7 或 变量等于6
[root@localhost data]#[ $a -ge 7 -o $a -eq 6 ] && echo true || echo false
true
一真即为真,全假才为假
第一个命令为真,不需要执行第二个命令了, 一定为真了
第一个命令为假,需要执行第二个命令来看 整个式子的结果
|| 只有前面不成立时才会执行后面的操作
(3) ! 逻辑否(取反)
[root@localhost data]#a=6
#判断变量是否等于 6 ,如果是 则输出true
[root@localhost data]#[ $a -eq 6 ] && echo true || echo false
true
#加了 ! 号后 意思是 把原结果变为 相反的结果 即 正确变为错误 ,错误变成正确。
[root@localhost data]#[ ! $a -eq 6 ] && echo true || echo false
false
其它:
ping 小脚本
[root@localhost data]#vim 2.sh
#!/bin/bash
ping -c 3 -i 0.5 -W2 $1 &> /dev/null && echo "$1 online" || echo "$1 off"
#注意w大写
[root@localhost data]#bash 2.sh 192.168.80.20
192.168.80.20 off
发送qq邮箱
[root@192 ~]#echo test |mail -s test [email protected]
#发送邮件
发送不成功步骤:
我们来到 linux 使用 vim /etc/mail.rc 下 进行配置。
[root@localhost data]#vim /etc/mail.rc
set [email protected] //发件方邮箱或昵称,经过测试必须得和下面的发件邮箱一致,否则发不了邮件
set smtp=smtp.qq.com //照着输即可
set [email protected] //发件邮箱
set smtp-auth-password=asxcjaabxshkcs //此处使用的就是前面生成的授权码
发送邮件的方法:
#第一种
echo "test" | mail -s 'test linux' [email protected]
#第二种
mailx -v -s " 主题 " [email protected] < a.sh
//-v可以动态显示邮件发送状态。可以把a.sh文件的内容作为邮件内容发送
磁盘使用量报警脚本
#!/bin/bash
use=$(df -h |grep "/dev/sd" |awk '{print $5}'|awk -F % '{print $1}')
[ $use -gt 80 ]&& echo "磁盘使用量过高" | mail -s diskinfo [email protected] ||echo "磁盘使用量正常"
或者
#!/bin/bash
use=80
disk=`df|grep "sd"|tr -s " "|cut -d " " -f5|cut -d "%" -f1`
[ $disk -ge $use ] && echo "磁盘使用率过高"|mail -s test [email protected]
判断当前用户是否为root 用户如果是就建立文件夹 ,不是则输出不成功。
[ `whoami` = root -a ! -e /data/test ] && mkdir -p /data/test ||echo "不成功"
[[ expression ]] 用法
== 左侧字符串是否和右侧的PATTERN相同
注意:此表达式用于[[ ]]中,PATTERN为通配符
=~ 左侧字符串是否能够被右侧的正则表达式的PATTERN所匹配
注意: 此表达式用于[[ ]]中;扩展的正则表达式
用法:
#通配符
[root@centos8 ~]#FILE=test.log
[root@centos8 ~]#[[ "$FILE" == *.log ]] #判断变量是否以.log结尾
[root@centos8 ~]#echo $?
0
#结果是 0 ,判断结果为正确
[root@centos8 ~]#FILE=test.txt
[root@centos8 ~]#[[ "$FILE" == *.log ]]
[root@centos8 ~]#echo $?
1
#结果是 1 ,判断结果为错误 ,即不是以.log结尾。
[root@centos8 ~]#FILE=test.txt
[root@centos8 ~]#[[ "$FILE" != *.log ]] #判断是否不以.log 结尾
[root@centos8 ~]#echo $?
0
# 结果为 0 ,此变量不以.log结尾。
#表达式
[root@centos8 ~]#FILE=test.log
[root@centos8 ~]#[[ "$FILE" =~ log$ ]] #判断变量是否以log结尾
[root@centos8 ~]#echo $?
0
#结果是 0 ,判断结果为正确
[root@centos8 ~]#FILE=test.log
[root@centos8 ~]#[[ "$FILE" =~ ^log ]] #判断变量是否以log开头
[root@centos8 ~]#echo $?
1
#结果是 1 ,判断结果为错误
(CMD1;CMD2;...)和 { CMD1;CMD2;...; } 都可以将多个命令组合在一起,批量执行
[root@centos8 ~]#( cd /data;ls )
test.log
[root@centos8 ~]#pwd
/root
#开启子shell 不影响当前 bash 环境
[root@centos8 ~]#{ cd /data;ls; }
test.log
[root@centos8 data]#pwd
/data
#不开启子shell 影响当前 bash 环境
[root@localhost data]#name=lc
[root@localhost data]#( name=mcl;echo $name );echo $name
mcl
lc
#可以看到 在括号里定义了一个name=mcl, 因为括号内的内容不影响当前bash环境
#所以 当前环境定义的name=lc 不会发生改变。
[root@localhost data]#name=lc
[root@localhost data]#{ name=mcl;echo $name; };echo $name
mcl
mcl
#因为 {} 里的内容会影响到当前bash环境 ,所以name=lc 被 {} 里的name=mcl 覆盖。
输出的结果都是mcl
单分支结构
if 判断条件的命令 ; then
则执行命令
fi
你写一个条件 ,如果成功则执行命令,否则直接结束。
#判断 10 是否 大于 5
if [ 10 -gt 5 ];then 如果判断条件为真 ,执行命令 。否则结束。
执行的命令
fi
双分支结构
if 判断条件的命令;then
执行命令1
else
执行命令2
fi
多分支结构
if 判断条件
then
执行命令1
elif
执行命令2
elif
执行命令3
………
else
执行命令n
fi
例子:
单分支:
[root@localhost data]#vim 1.sh
#!/bin/bash
read -p "输入数字" s
if [ $s -ge 60 ];then #判断变量是否大于等于 60,结果是 则执行命令,不是 无结果
echo "高"
fi
[root@localhost data]#bash 1.sh
输入数字1
#回车后无结果
[root@localhost data]#bash 1.sh
输入数字60
高
双分支:
###########判断是否为超级管理员#######################
#!/bin/bash
if [ "$USER" != "root" ]
then
echo "非管理员用户无权限操作"
else
echo "是管理员用户"
fi
#############判断是主机连通性#######################
#!/bin/bash
ping -c3 192.168.80.145 &>/dev/null
if [ $? = 0 ];then
echo "网络通顺"
else
echo "网络不通顺"
fi
多分支:
#######################判断分数 优秀 及格 不及格#######################
#!/bin/bash
read -p "请输入你的考试分数:" grade
if [ $grade -ge 90 ]&& [ $grade -le 100 ]
then
echo "你的成绩为$grade"
echo "你的成绩为优秀"
elif [ $grade -ge 70 ]&&[ $grade -le 89 ]
then
echo "你的成绩为$grade"
echo "你的成绩为良好"
elif
[ $grade -ge 60 ]&&[ $grade -le 69 ]
then
echo "你的成绩为$grade"
echo "你的成绩为合格"
elif [ $grade -ge 0 ]&&[ $grade -le 59 ]
then
echo "你的成绩为$grade"
echo "你的成绩为不合格"
else
echo "请重新输入"
bash $0
fi
#######################按时间打招呼#######################
#!/bin/bash
h=`date +%H`
if [ $h -ge 6 -a $h -le 10 ];then
echo "早上好"
elif [ $h -ge 11 -a $h -le 13 ];then
echo "中午好"
elif [ $h -ge 14 -a $h -le 18 ];then
echo "下午好"
else
echo "晚上好"
fi
判断一个变量的不同取值
格式:
case 变量值 in
模式1)
命令
;;
模式2)
命令
;;
.......
*)
命令
;;
esac
case 支持 glob 风格的通配符:
* 任意长度任意字符
? 任意单个字符
[0-9] 指定范围内的任意单个字符
| 或者,如: a|b
例子:
######################小心情#################################
#!/bin/bash
read -p "你今天心情好吗?(yes/no)" INPUT
INPUT=`echo $INPUT|tr [A-Z] [a-z]`
case $INPUT in
y|ye|es|yes)
echo "看来你心情不错。"
;;
n|no|o)
echo "x-x"
;;
*)
echo "@-@"
bash $0
esac
#!/bin/bash
read -p "你今天心情好吗?(yes/no)" INPUT
INPUT=`echo $INPUT|tr [A-Z] [a-z]`
case $INPUT in #对INPUT变量进行判断
y|ye|es|yes)
echo "看来你心情不错。"
;;
n|no|o)
echo "x-x"
;;
*)
echo "@-@"
bash $0
esac
或者用另一种方法
#!/bin/bash
read -p "你今天心情好吗?(yes/no)" INPUT
case $INPUT in
[yY]|[yY][eE]|[eE][sS]|[yY][eE][sS]) #y,ye,es,yes 的大小写组合都会被匹配
echo "看来你心情不错。"
;;
[nN]|[oO]|[nN][oO]) #n,o,no 的大小写组合都会被匹配
echo "x-x"
;;
*) #经过以上判断后 ,无法被匹配的将重新输入一次
echo "@-@"
bash $0
esac
石头,剪刀,布
#!/bin/bash
m=`echo $[RANDOM%3+1]`
read -p "请输入 1.石头2.剪刀3.布:" h
if [ $m -eq $h ]
then
echo "打成平局"
bash $0
elif [ $h -eq 1 -a $m -eq 2 -o $h -eq 2 -a $m -eq 3 -o $h -eq 3 -a $m -eq 1 ]
then
echo "你赢了"
else
echo "你输了"
fi
写一个 检查 80 端口 是否开启,如果开启则反馈 httpd 正在运行 否则 启动httpd服务。
[root@localhost data]#vim httpd.sh
#!/bin/bash
systemctl status httpd &> /dev/null
if [ $? -eq 0 ];then
echo "httpd 服务正在运行"
else
systemctl start httpd &> /dev/null
if [ $? -eq 0 ];then
echo "httpd 服务已开启"
else
echo "httpd 服务可能未安装或端口被占用"
fi
fi
安装 httpd 服务 ,先判断当前操作系统 ,如果是 centos 使用yum 安装。如果是 ubuntu 使用apt
。若其它系统 不支持。
#!/bin/bash
if grep -q centos /etc/os-release;then
yum install -y httpd &> /dev/null
if [ $? -eq 0 ];then
echo "安装成功"
else
echo "安装失败,请检查"
fi
elif grep -q ubuntu /etc/os-release;then
apt install apache2 -y &> /dev/null
if [ $? -eq 0 ];then
echo "安装成功"
else
echo "安装失败,请检查"
fi
else
echo "您的操作系统不支持"
fi