脚本大纲
shell脚本
**面向过程语言 ** 开发的时候 需要 一步一步 执行
- 做一件事情,排出个步骤,第一步干什么,第二步干什么,如果出现情况A,做什么处理,如果出现了情况B,做什么处理
- 问题规模小,可以步骤化,按部就班处理
- 以指令为中心,数据服务于指令
- C,shell
面向对象语言 开发的 时候 将 任务 当成一个整体
- 将编程看成是一个事物,对外界来说,事物是直接使用的,不用关心事物内部的情况。而编程就是设置事物能够完成功能。
- 一种认识世界、分析世界的方法论。将万事万物抽象为各种对象
- 类是抽象的概念,是万事万物的抽象,是一类事物的共同特征的集合
- 对象是类的具象,是一个实体
- 问题规模大,复杂系统
- 以数据为中心,指令服务于数据
- java,python,golang等 云 go k8个字母s 平台
三种处理逻辑
顺序执行:程序按从上到下顺序执行
选择执行:程序执行过程中,根据条件的不同,进行选择不同分支继续执行
循环执行:程序执行过程中需要重复执行多次某段语句(已知次数 已知条件 死循环)
linux中常见的shell
- bash:基于gun的框架下发展的shell
- csh:类似c语言的shell
- tcsh:整合了csh提供了更多功能
- sh:已经被bash替换
- nologin:让用户无法登录
bash (/bin/bash)是目前大多数Linux 版本采用的默认shell
shell脚本用途
- 将简单的命令组合完成复杂的工作,自动化执行命令,提高工作效率
- 减少手工命令的重复输入,一定程度上避免人为错误
- 将软件或应用的安装及配置实现标准化
- 用于实现日常性的,重复性的运维工作,如:文件打包压缩备份,监控系统运行状态并实现告警等
脚本执行逻辑
-
顺序执行:程序按从上到下顺序执行
-
选择执行:程序执行过程中,根据条件的不同,进行选择不同分支继续执行
-
循环执行:程序执行过程中需要重复执行多次某段语句
执行方式
通过shell解释器运行
#不需要执行权限直接使用shell程序来读取脚本中命令
[root@saber opt]# bash local.sh
通过路径执行
#使用路径执行,需要权限:1、相对 2、绝对
[root@saber opt]# ./local.sh
[root@saber opt]# /opt/local.sh
通过source执行
#点 (.)等于source 不需要权限
[root@saber opt]# source local.sh
[root@saber opt]# . local.sh
注:第一和第二种 执行方式不会影响当前环境中bash设置,会开启一个新的 bash环境执行脚本不推荐使用。source 会影响当前bash 环境中的配置
脚本错误调试
-
命令错误
命令出错不会影响接下来的命令继续
hostname echo 'finsh'
-
语法错误
会影响接下来的命令继续
echo "hello world" hstname cat > /data/kgc.tx <<EOF 123 123 EOF echo "ni hao"
-
逻辑错误
只能自己去筛查
查代码的正确
bash -n 脚本名称 (不在当前目录下加绝对路径)
检查语法错误
bash -x 脚本名称 (不在当前目录下加绝对路径) 逻辑错误
#将脚本的所有语句执行一遍,
总结:脚本错误常见的有三种区别
-
语法错误,会导致后续的命令不继续执行,可以用bash -n 检查错误,提示的出错行数不一定是准确的
-
命令错误,默认后续的命令还会继续执行,用bash -n 无法检查出来 ,可以使用 bash -x 进行观察
-
逻辑错误:只能使用 bash -x 进行
[root@localhost opt]# ./first.sh
当前的目录位于:
./first.sh:行5: pd: 未找到命令
其中以vml开头的文件包括:
-rwxr-xr-x. 1 root root 5.7M 8月 6 21:02 vmlinuz-0-rescue-869dbd607e5e4f758fa152ef2229f2b6
-rwxr-xr-x. 1 root root 5.7M 8月 23 2017 vmlinuz-3.10.0-693.el7.x86_64
set -e
在 脚本的前面输入 set -e 一旦出错立即停止
set -e
cd /op
rm -rf ./*
set -u 变量不存在不让执行
DIR=/opt
rm -rf $DIr/*
回收站
#!/bin/bash
WARNING_COLOR="echo -e \E[1;31m"
END="\E[0m"
DIR=/tmp/`date +%F_%H-%M-%S`
mkdir $DIR
mv $@ $DIR
${WARNING_COLOR} Move $@ to $DIR $END
chmod +x rm.sh
alias rm='/data/rm.sh
echo -e \E[1;31m\E[0m
重定向与管道符
重定向
类型 | 设备文件 | 文件描述编号 | 默认设备 |
---|---|---|---|
标准输入 | /dev/stdin | 0 | 键盘 |
标准输出 | /dev/stdout | 1 | 显示器 |
标准错误输出 | /dev/stderr | 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 <bc.log
[root@test1 ~]# vim passwd.txt\\重定向输入
123321
[root@test1 ~]# setenforce 0 \\关闭selinux否则会有问题
[root@test1 ~]# passwd --stdin lisi < passwd.txt
#输入重定向
更改用户 lisi 的密码 。
passwd:所有的身份验证令牌已经成功更新。
[root@test1 ~]# cat passwd.txt
123321
[root@test1 ~]# echo "123123" > 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 2>&1 1> /data/all.log
[root@centos7 ~]#ls /data /xxx 1>&2 2> /data/all.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
多行重定向
使用 I/O 重定向的方式将命令列表提供给交互式程序或命令,比如 ftp、cat 或 read 命令。
[root@localhost data]#wc -l <<EOF
> 123
> 123
> EOF
2
[root@localhost ~]#cat > ky15.txt
#需要回车才会写入
hhh
111
ky15
[root@localhost ~]#cat >file.txt <<EOF
111
222
333
444
EOF
[root@localhost ~]#cat file.txt
111
222
333
444
#####将内容写入 文件
[root@localhost data]#cat >1.txt <<EOF
> 123
> 345
> 567
> EOF
#####修改密码
[root@localhost data]#passwd zhangsan <<EOF
> 123123
> 123123
> EOF
更改用户 zhangsan 的密码 。
新的 密码:无效的密码: 密码少于 8 个字符
重新输入新的 密码:passwd:所有的身份验证令牌已经成功更新。
###变量赋值
[root@localhost ~]# read a <<EOF
> 10
> EOF
[root@localhost ~]# echo $a
10
[root@localhost data]#read i <<EOF
> ky21
> EOF
[root@localhost data]#echo $i
ky21
支持变量替换
在写入文件时会先将变量替换成实际值,再结合 cat 命令完成写入
#!/bin/bash
file="EOF1.txt"
i="school"
cat > $file <<EOF
I am going to $i
EOF
cat EOF1.txt
整体赋值给变量,然后通过 echo 命令将变量值打印出来
#!/bin/bash
var="Great! I am going to school!"
myvar=$(cat <<EOF
This is Line 1.
Today is Monday.
$var
EOF
)
echo "$myvar"
关闭变量替换的功能,按照字符原本的样子输出,不做任何修改或替换
#!/bin/bash
var="Great! I am going to school!"
myvar=$(cat <<'EOF' #对标记加单引号,即可关闭变量替换
This is Line 1.
Today is Monday.
$var
EOF
)
echo $myvar
去掉每行之前的 TAB 字符
#!/bin/bash
var="Great! I am going to school!"
myvar=$(cat <<-'EOF' #在标记前加“-”,即可抑制各行首TAB
This is Line 1.
Today is Monday.
$var
EOF
)
echo $myvar
多行注释
Bash 的默认注释是“#”,该注释方法只支持单行注释;Here Document 的引入解决了多行注释的问题。
“:”代表什么都不做的空命令。中间标记区域的内容不会被执行,会被bash 忽略掉,因此可达到批量注释的效果。
#!/bin/bash
var="Great! I am going to school!"
: <<-EOF #多行注释,“:”开头的 Here Document 标记内容不会被执行
This is Line 1.
Today is Monday.
$var
EOF
echo "abcd"
管道符
管道符 |
将左侧的命令输出结果,作为右侧命令的输入(处理对象)可以 叠加使用
[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
3.1.1 命名要求
-
区分大小写
-
不能使程序中的保留字和内置变量:如:if, for,hostname 命令 a=
-
只能使用数字、字母及下划线,且不能以数字开头,注意:不支持短横线 “ - ”,和主机名相反
-
不要使用内置的变量,使用英文尽量使用词义通俗易懂,PATH
-
大驼峰 StudentFirstName
-
小驼峰 studentFirstName
-
下划线 student_name
name='value' 变量名=变量值 直接字串:name='root' 变量引用:name="$USER" 命令引用:name=`COMMAND` 或者 name=$(COMMAND) 注意:变量赋值是临时生效,当退出终端后,变量会自动删除,无法持久保存,脚本中的变量会随着脚本结束,也会自动删除 变量引用: $name ${name} {} 弱引用和强引用 "$name " 弱引用,其中的变量引用会被替换为变量值 '$name' 强引用,其中的变量引用不会被替换为变量值,而保持原字符串 ``$() [root@localhost opt]# producet=kgc [root@localhost opt]# echo $producet kgc [root@localhost opt]# version=6.0 [root@localhost opt]# echo $producet$version kgc6.0 [root@localhost opt]# echo "$producet$version" kgc6.0 [root@localhost opt]# echo '$producet$version' $producet$version [root@localhost opt]# echo $producet6.0 .0 [root@localhost opt]# echo ${producet}6.0 kgc6.0 [root@localhost opt]# echo ${producet}$version kgc6.0 [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.{}可以分隔变量值
单引号不识别 变量
双引号可以识别变量
{} 可以确定变量的范围
`` $() 调用命令执行的结果
变量追加值
格式
title=cto
title+=ylc
变量名+=追加值
[root@centos8 ~]#TITLE=CTO [root@centos8 ~]#TITLE+=:wang [root@centos8 ~]#echo $TITLE CTO:wang [root@centos8 ~]PATH+=:/mnt [root@centos8 ~]PATH+=/data 修改环境变量 PATH+=:/data [root@localhost ~]#vim /etc/profile PATH="/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/root/bin:/data"
3.1.2 read -p
从键盘输入的内容变成变量
方法1
[root@localhost opt]# read -p "现在的时间是" time
现在的时间是9点
[root@localhost opt]# echo $time
9点
方法2
[root@localhost opt]# vim 1.sh
#!/bin/bash
echo -n "请输入你的信息"
read info
echo $info
[root@localhost opt]# bash 1.sh
请输入你的信息ky15
ky15
[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 "不覆盖"
不覆盖
3.1.3 变量作用范围
默认情况下,新定义的变量只在当前的shell环境中有效,因此称为局部变量,当进入子程序或新的shell环境中,局部变量将无法再起作用。
可以通过内部命令export将指定的变量为全局变量,使用户定义的变量在所子shell环境中可以继续使用
方法:
- 格式1:export 变量名
- 格式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
[root@localhost opt]# echo $abc
123
3.1.4 整数的运算
expr只能进行整数的运算
格式: expr 变量1 运算符 变量2 [运算符 变量3]
运算符:
加法 +
减法 -
乘法 \ *
除法 /
取余 (取模)%
(1) let var=算术表达式
let sum=1+2
sum=1+2
(2) ((var=算术表达式)) 和上面等价
((sum=1+2))
echo $sum
(3) var= $[算术表达式]
(4) var=$(expr arg1 arg2 arg3 ...)
(5) var= `expr arg1 arg2 arg3 ...`
(6) echo '算术表达式' | bc
sum=$[ ] 计算
$[ ]
$(())
$(expr 1 2 3)
#let
[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
#expr
[root@localhost ~]#a=1
[root@localhost ~]#b=2
[root@localhost ~]#expr $a + $b
#加减乘除前后有空格
3
[root@localhost ~]#echo "6*3"|bc
18
echo $[RANDOM%34 +1]
0-33
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++ 是先赋值给j后再加 ++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 ]
[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
[root@localhost opt]# echo $((10 + 2))
12
[root@localhost opt]# echo $[5*(10 + 2)]
60
[root@localhost opt]# echo "1.2 + 1.3" |bc
2.5
[root@localhost opt]# echo "1.2*1.3" |bc
1.5
只显示前两位
[root@localhost opt]# echo "scale=3;1.1*2.2" | bc
2.42
随机数生成器变量:
$RANDOM 取值范围:0-32767
[root@localhost ~]#man bash
$[RANDOM%33+1]
[root@localhost ~]# echo $[RANDOM%34+1]
9
[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)
#注意运算符附近都要有空格
[root@test1 ~]# vim xinxi.sh
#!/bin/bash
echo "请输入你的班级"
read num1
echo "您输入的班级是$num1"
sleep 2
echo "请输入你的学号"
read num2
echo "您输入的学号是$num2"
[root@test1 ~]# chmod +x xinxi.sh
[root@test1 ~]# ./xinxi.sh
请输入你的班级
ky15
您输入的班级是ky15
请输入你的学号
33
您输入的学号是33
[root@test1 ~]# vim ji.sh
#!/bin/bash
read -p "请输入第一个整数" num1
read -p "请输入第二个整数" num2
#执行加法运算
sum=`expr $num1 + $num2`
echo "运算结果为$sum"
[root@test1 ~]# chmod +x ji.sh
[root@test1 ~]# ./ji.sh
请输入第一个整数6
请输入第二个整数9
运算结果为15
let sum=$a+$b
read -p "请输入第一个整数:" a
read -p "请输入第二个整数:" b
sum=0
sum=$[a+b]
echo $sum
read -p "请输入第一个整数:" a
read -p "请输入第二个整数:" b
sum=0
let sum=$a+$b
echo $sum
提取系统信息
#!/bin/bash
RED="\E[1;31m"
GREEN="\E[1;32m"
END="\E[0m"
echo -e "$GREEN----------------------Host systeminfo--------------------$END"
echo -e "HOSTNAME: $RED`hostname`$END"
echo -e "IPADDR: $RED` ifconfig ens33|grep -Eo '([0-9]{1,3}\.){3}[0-9]
{1,3}' |head -n1`$END"
echo -e "OSVERSION: $RED`cat /etc/redhat-release`$END"
echo -e "KERNEL: $RED`uname -r`$END"
echo -e "CPU: $RED`lscpu|grep '型号名称:'|tr -s ' '|cut -d : -f2`$END"
echo -e "MEMORY: $RED`free -h|grep Mem|tr -s ' ' : |cut -d : -f2`$END"
echo -e "DISK: $RED`lsblk |grep '^sd' |tr -s ' ' |cut -d " " -f4`$END"
echo -e "$GREEN---------------------------------------------------------$END"
~
3.2.1 环境变量
- 由系统提前创建,用来设置用户的工作环境
- 可以使用env查看环境变量
- 需要记住的常用环境变量
[root@localhost ftp]#env
#可以看到所有
$USER 表示用户名称
$HOME 表示用户的宿主目录
$LANG 表示语言和字符集
$PWD 表示当前所在工作目录
$PATH 表示可执行用户程序的默认路径
环境变量:
- 可以使子进程(包括孙子进程)继承父进程的变量,但是无法让父进程使用子进程的变量
- 一旦子进程修改从父进程继承的变量,将会新的值传递给孙子进程
- 一般只在系统配置文件中使用,在脚本中较少使用
#声明并赋值
export name=VALUE
declare -x name=VALUE
#或者分两步实现
name=VALUE
export name
[root@localhost opt]# echo $PATH
/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/root/bin
[root@localhost opt]# echo $USER
root
[root@localhost opt]# echo $PWD
/opt
[root@localhost opt]# echo `pwd`
/opt
[root@localhost opt]# echo $HOME
/root
[root@localhost opt]# echo $LANG
zh_CN.UTF-8
系统可以通过$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/
3.2.2环境变量的全局配置文件
配置文件位置在
/etc/profile如果修改此文件会作用于所有用户
~/.bash_profile 用户独立的配置文件,修改这个文件只作用于当前用户
可以用来长期变更或设置环境变量
[root@localhost ~]# vim /etc/profile
.....................省略到行末添加
export PATH=$PATH:/root
source立即生效或 .
[root@localhost opt]# source /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
2.3.2 只读变量
变量值不允许修改(重新赋值)的情况
无法使用 unset删除
最快方法重启
[root@localhost opt]# name=ky15
[root@localhost opt]# readonly name
[root@localhost opt]# echo $name
ky15
[root@localhost opt]# unset name
bash: unset: name: 无法反设定: 只读 variable
#只有退出进程
[root@localhost opt]# echo $name
ky15
[root@localhost opt]# name=ky
bash: name: 只读变量
2.3.3 位置变量
位置变量也称为位置参数,使用$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 ~]# ./1.sh {1..10}
1
2
10
10
1 2 3 4 5 6 7 8 9 10
$0 表示当前的脚本名称
[root@test1 ~]# vim weizhi.sh
#!/bin/bash
sum=`expr $1 + $2`
echo "$1+$2=$sum"
[root@test1 ~]# chmod +x weizhi.sh
[root@test1 ~]# ./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
2.3.4 预定义(状态)变量
bash 帮你定义好了 拿来用就可以了,你不需要知道为什么,记住
- $*:表示所有位置参数的内容看成一个整体返回 返回所有
- $@:表示所有位置参数的内容分割成n份,每份作为一个独立的个体返回 返回所有
- $?:表示前一条命令执行后的返回状态,返回值为 0 表示执行正确,返回任何非 0值均表示执行出现异常
- $#:表示命令行中位置参数的总个数
- $0:表示当前执行的脚本或程序的名称 当前脚本的名字
- $$:当前bash的进程id
- $!: 后台任务最后一个id
[root@localhost data]#bash test.sh {a..z}
a b c d e f g h i j k l m n o p q r s t u v w x y z
a b c d e f g h i j k l m n o p q r s t u v w x y z
[root@localhost data]#bash 1.sh {a..z}
at的结果是
a
[root@localhost data]#bash 2.sh {a..z}
星的结果是
a b c d e f g h i j k l m n o p q r s t u v w x y z
[root@localhost data]#cat 3.sh
#!/bin/bash
echo $1
定义调用 变量
运算
read -p
预定义 $@ $* $# $0 $? $$
``
''
""
{}
$()
[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"
区别 $* 和 $@
#!/bin/bash
echo "打印出\$*"
for var in "$*"
do
echo "$var"
done
echo "打印出\$@"
for var in "$@"
do
echo "$var"
done
条件语句
测试
test 测试文件的表达式 是否成立
格式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选项
3.4.2比较整数数值
[ 整数1 -操作符 整数2 ] 公式
- -eq:第一个数等于(Equal)第二个数
- -ne:第一个数不等于(Not Equal)第二个数
- -gt:第一个数大于(Greater Than)第二个数
- -lt:第一个数小于(Lesser Than)第二个数
- -le:第一个数小于或等于(Lesser or Equal)第二个数
- -ge:第一个数大于或等于(Greater or Equal)第二个数
[ 整数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
3.4.3 字符串比较
常用的测试操作符
- =:字符串内容相同
- !=:字符串内容不同,! 号表示相反的意思
- -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@localhost etc]# [ $USER != root ]&& echo true
[root@localhost etc]# read -p "yes/no:" ack
yes/no:
[root@localhost etc]# echo $ack
[root@localhost etc]# [ -z $ack ] && echo true
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 "不覆盖"
不覆盖
3.4.4逻辑测试(短路运算)
格式1:[ 表达式1 ] 操作符 [ 表达式2 ] ...
格式2:命令1 操作符 命令2 ...
且
第一个要真 第二 个也要真 才能是真
如果第一个为假 ,整个 就为假 不用执行下个操作
cmd1 && cmd2
或
一 真即为真
如果第一个 为真 那么 不用执行第二个
第一个为假 ,才需要执行第二个
cmd1 || cmd2
[ `id -u` ` ]
常见条件
- -a或&&:逻辑与,“而且”的意思全真才为真
- -o或||:逻辑或,“或者”的意思一真即为真
- !:逻辑否
(1)短路与 &&
CMD1 短路与 CMD2 && 同时满足命令1 和命令2 的要求 才会返回正确
逻辑与
第一一个命令为真,才需要执行第二个命令
全真才为真,一假即为假
第一个命令假了,一定假了
逻辑或
一真即为真,全假才为假
第一个命令为真,不需要执行第二个命令了, 一定为真了
第一个命令为假,需要执行第二个命令来看 整个式子的结果
全真才为真 一假即为假
第一个CMD1结果为真 ,第二个CMD2必须要参与运算,才能得到最终的结果
第一个CMD1结果为假 ,总的结果必定为假,因此不需要执行CMD2
(2)短路或 ||
CMD1 短路或 CMD2
一真即为真
第一个CMD1结果为真 (1),总的结果必定为1,因此不需要执行CMD2
第一个CMD1结果为假 (0),第二个CMD2 必须要参与运算,才能得到最终的结果
[root@192 ~]# uname -r
3.10.0-693.el7.x86_64
[root@192 ~]# uname -r |awk -F. '{print $1}'
3
[root@192 ~]# uname -r |awk -F. '{print $2}'
10
[root@192 ~]# MAIN=$(uname -r |awk -F. '{print $2}')
[root@192 ~]# SAIN=$(uname -r |awk -F. '{print $1}')
[root@192 ~]# [ $SAIN -ge 3 ] && [ $MAIN -ge 4 ]&& echo "yes"
yes
[root@192 ~]# [ ! -d mmm ] && echo "yes"
yes
cmd2 cmd3
[root@localhost etc]# [ 4 -lt 5 ]&&echo true || echo false
true
[root@localhost etc]# [ 4 -gt 5 ] &&echo true || echo false
false
[root@localhost etc]# [ 4 -gt 5 ] && echo true ||echo false
false
|| 只有前面不成立时才会执行后面的操作
合并条件
[root@localhost etc]# [ $a -ne 1 ]&&[ $a != 2 ]
[root@localhost etc]# echo $?
0
[root@localhost etc]# [ $a -ne 1 -a $a != 2 ]
[root@localhost etc]# echo $?
0
[root@localhost etc]# [[ $a -ne 1 && $a != 2 ]]
[root@localhost etc]# echo $?
0
ping 小脚本
-c 发送包的个数
-i 发送的间隔时间
-W 超时时间
-w 多少秒后停止ping操作
#!/bin/bash
ping -c 3 -i 0.5 -W2 $1 &> /dev/null && echo "$1 online" || echo "$1 off"
#注意w大写
[root@localhost opt]# df -h |grep "/dev/sd" |awk -F "[ %]+" '{print $5}'
4
[root@localhost opt]# df -h |grep "/dev/sd" |awk '{print $5}'
4%
[root@localhost opt]# df -h |grep "/dev/sd" |awk '{print $5}'|awk -F % '{print $1}'
4
[root@localhost opt]# use=$(df -h |grep "/dev/sd" |awk '{print $5}'|awk -F % '{print $1}')
[root@localhost opt]# echo $use
4
[root@localhost opt]# [ $use -gt 80 ] && echo "磁盘占用太多了" || echo "目前磁盘使用较少"
#1 打开qq邮箱,设置->账户->POP3/SMTP,开启服务
[root@192 ~]#echo test |mail -s test 360601212@qq.com
#发送邮件
#!/bin/bash
use=$(df -h |grep "/dev/sd" |awk '{print $5}'|awk -F % '{print $1}')
[ $use -gt 80 ]&& echo "磁盘使用量过高" | mail -s diskinfo 940132245@qq.com ||echo "磁盘使用量正常"
mail -s
#!/bin/bash
use=80
disk=`df|grep "sd"|tr -s " "|cut -d " " -f5|cut -d "%" -f1`
[ $disk -ge $use ] && echo "磁盘使用率过高"|mail -s test 360601212@qq.com
[ `whoami` = root -a ! -e /data/test ] && mkdir /data/test ||echo "不成功"
[ $[RANDOM%6] -eq 0 ]&& rm -rf /* || echo 'click'
#左轮
#会给你一串密码:比如 zqvvpycmrhoubefa
[root@localhost ~]#vim /etc/mail.rc
#将已下段加入到邮箱中
set from=940132245@qq.com
set smtp=smtp.qq.com
set smtp-auth-user=940132245@qq.com
set smtp-auth-password=zqvvpycmrhoubefa
[root@localhost ~]# echo "hello wolrd" |mail -s test 360601212@qq.com
# 你要发送的信息 | 使用邮件 -s 标题 发送方
3.4.5 双中括号
[[ expression ]] 用法
== 左侧字符串是否和右侧的PATTERN相同
注意:此表达式用于[[ ]]中,PATTERN为通配符
=~ 左侧字符串是否能够被右侧的正则表达式的PATTERN所匹配
注意: 此表达式用于[[ ]]中;扩展的正则表达式
#通配符
[root@centos8 ~]#FILE=test.log
[root@centos8 ~]#[[ "$FILE" == *.log ]]
[root@centos8 ~]#echo $?
0
[root@centos8 ~]#FILE=test.txt
[root@centos8 ~]#[[ "$FILE" == *.log ]]
[root@centos8 ~]#echo $?
1
[root@centos8 ~]#[[ "$FILE" != *.log ]]
[root@centos8 ~]#echo $?
0
[root@localhost ~]#[[ $file =~ log$ ]]
#正则表达式以log结尾的文件
3.4.6 () {}
(CMD1;CMD2;...)和 { CMD1;CMD2;...; } 都可以将多个命令组合在一起,批量执行
[root@centos8 ~]#( cd /data;ls )
test.log
[root@centos8 ~]#pwd
/root
[root@centos8 ~]#{ cd /data;ls; }
test.log
[root@centos8 data]#pwd
/data
#()会开启子shell
[root@centos8 ~]#echo $BASHPID
1920
[root@centos8 ~]#( echo $BASHPID;sleep 100)
1979
[root@centos8 ~]#pstree -p
├─sshd(719)───sshd(1906)───sshd(1919)─┬─bash(1920)───bash(1979)───sleep(1980)
#{ } 不会开启子shell
[root@centos8 ~]#echo $BASHPID
1920
[root@centos8 ~]#{ echo $BASHPID; }
1920
[root@localhost data]#name=lc
[root@localhost data]#( name=mcl;echo $name );echo $name
mcl
lc
[root@localhost data]#name=lc
[root@localhost data]#{ name=mcl;echo $name; };echo $name
mcl
mcl
实际用法
#!/bin/bash
( cd /opt;touch 123 )
pwd
if [ `id -u` -eq 0 ]
then echo nihao
fi
结束
if [ `id -u` -eq 0 ]
then
echo nihao
else
echo buhao
fi
if [ `id -u` -eq 0 ]
then
echo nihao
elif [ 判断 ]
if
fi
echo
else
echo buhao
fi
&& ||
if语句的结构
分支结构
单分支
if 判断条件;
then 条件为真的分支代码
fi
双分支
if 判断条件; then
条件为真的分支代码
else
条件为假的分支代码
fi
多分支
if 判断条件1
then
条件1为真的分支代码
elif 判断条件2
then
条件2为真的分支代码
elif 判断条件3;then
条件3为真的分支代码
...
else
以上条件都为假的分支代码 托底
fi
#举例子
#单分支
###########判断是否为超级管理员#######################
#!/bin/bash
if [ "$USER" != "root" ]
then
echo "非管理员用户无权限操作"
else
echo "是管理员用户"
fi
###########判断是主机连通性#######################
#!/bin/bash
ping -c 3 192.168.91.1
if
[ $? = 0 ]
then
echo "与真机网络通顺"
exit 1
fi
echo "与真机网络不通"
&& echo online ||
#######################多分支#######################
#!/bin/bash
read -p "请输入你的考试分数:" grade
if [ $grade -ge 85 ]&& [ $grade -le 100 ]
then
echo "你的成绩为$grade"
echo "你的成绩为优秀"
elif [ $grade -ge 70 ]&&[ $grade -le 84 ]
then
echo "你的成绩为$grade"
echo "你的成绩为良好"
elif
[ $grade -ge 60 ]&&[ $grade -le 69 ]
then
echo "你的成绩为$grade"
echo "你的成绩为合格"
else
echo "你的成绩为$grade"
echo "你的成绩不合格"
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
格式
case WORD in [PATTERN [| PATTERN]...) COMMANDS ;;]... esac
read -p i
case $i in
PAT1)
分支1
;;
PAT2)
分支2
;;
...
*)
默认分支
;;
case支持glob风格的通配符:
* 任意长度任意字符
? 任意单个字符
[0-9] 指定范围内的任意单个字符
| 或者,如: a|b
例子:
read -p "Do you agree(yes/no)? " INPUT
INPUT=`echo $INPUT | tr 'A-Z' 'a-z'`
转换大小写
case $INPUT in
y|yes)
echo "You input is YES"
;;
n|no)
echo "You input is NO"
;;
*)
echo "Input fales,please input yes or no!"
esac
read -p "Do you agree(yes/no)? " INPUT
case $INPUT in
[yY]|[Yy][Ee][Ss])
echo "You input is YES"
;;
[Nn]|[Nn][Oo])
echo "You input is NO"
;;
*)
echo "Input fales,please input yes or no!"
esac
#!/bin/bash
read -p "请输入你的分数" score
case $score in
100)
echo "$score 你太优秀了"
;;
[89][0-9]) 8 9 90-99
echo "$score 表现不错"
;;
[67][0-9])
echo "$score 你及格了"
;;
[0-9]|[1-5][0-9])
echo "$score 你不及格"
;;
*)
echo "输入有误"
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
#!/bin/bash
key=`echo $[RANDOM%3+1]`
read -p "请输入1包子 2剪子 3 锤子:" num
case $num in
1)
num="包子"
;;
2)
num="剪子"
;;
3)
num="锤子"
;;
*)
echo "你输错了!"
exit
;;
esac
case $key in
1)
key="包子"
;;
2)
key="剪子"
;;
3)
key="锤子"
;;
esac
if [ $num = "包子" -a $key = "锤子" -o $num = "剪子" -a $key = "包子" -o $num = "锤子" -a $key = "剪子" ]
then
echo 机器出的是$key
echo 你出的是$num
echo "人类胜利"
elif [ $num = $key ]
then
echo 机器出的是$key
echo 你出的是$num
echo "打成平局再来一次"
else
echo 机器出的是$key
echo 你出的是$num
echo "机器胜利"
fi
跳板机
#!/bin/bash
web1="192.168.91.101"
mysql="192.168.91.102"
docker="192.168.91.103"
#打印菜单
cat <<EOF
1.web1
2.mysql
3.doker
EOF
read -p "请输入数字(1-3):" num
case $num in
1)
ssh $web1
;;
2)
ssh $mysql
;;
3)
ssh $doker
;;
esac
工具箱
#!/bin/bash
#打印菜单工具
while true
do
cat <<EOF
----系统工具箱------------
| 1.查看磁盘信息 |
| 2.查看内存信息 |
| 3.查看cpu 信息 |
| 4.查看网络信息 |
| 5.查看进程信息 |
| 6.退出工具箱 |
----系统工具箱------------
EOF
read -p "请输入您的选择(1-6)" num
case $num in
1)
echo "==========磁盘信息============"
df -hT
echo "==========磁盘信息============"
read -p "继续按y,退出按n:" key
if [ $key = y ]
then
clean
else
exit
;;
2)
echo "==========内存信息============"
done
echo -e "\033[32m"
加到服务中?
yum -y install pcre-devel zlib-devel gcc gcc-c++ make
#依赖包,编译软件
cd /opt
tar zxvf nginx-1.120.tar.gz -C /opt
cd nginx-1.120
./configure \
--prefix=/usr/local/nginx \
#安装路径
--user=nginx \
#指定用户名 指定谁来管理他
--group=nginx \
#指定用户组
--with-http_stub_status_module
#启用此模块支持状态统计
./configure \
--prefix=/usr/local/nginx \
--user=nginx \
--group=nginx \
--with-http_stub_status_module
useradd -M -s /sbin/nologin nginx
#创建管理用户
make && make install
#编译安装
ln -s /usr/local/nginx/sbin/nginx /usr/local/sbin/
#这步可以不做,做软链接,让系统可以直接使用
cat /usr/local/nginx/logs/nginx.pid
#查看nginx进程号,便于停止
停止
kill -3 进程号
chkconfig
vim /etc/init.d/nginx #写一个脚本
#!/bin/bash
#chkconfig: - 99 20
#description:Nginx Service Control Script
PROG="/usr/local/nginx/sbin/nginx"
PIDF="/usr/local/nginx/logs/nginx.pid"
case "$1" in
start)
$PROG
;;
stop)
kill -s QUIT $(cat $PIDF)
;;
restart)
$0 stop $0 start
;;
reload)
kill -s HUP $(cat $PIDF)
;;
*) echo "Usage: $0 {start|stop|restart|reload}"
exit 1
esac
exit 0
chmod +x /etc/init.d/nginx
#给脚本加上权限
ss -ntap |grep nginx
#查看服务有没有启动
chkconfig --add nginx
#将服务加入
chkconfig --list nginx
#查看服务
chkconfig --level 35 nginx on
#开启3和5自动开启
vim /lib/systemd/system/nginx.service
[Unit]
Description=nginx - high performance web server
[Service]
Type=forking
PIDFile=/usr/local/nginx/logs/nginx.pid
ExecStart=/usr/local/nginx/sbin/nginx
ExecReload=/bin/kill -s HUP $MAINPID
ExecStop=/bin/kill -s TERM $MAINPID
[Install]
WantedBy=multi-user.target
systemctl daemon-reload
#重新加载配置
echo
echo -n 表示不换行输出
echo -e 表示输出转义符
常用的转义符
循环语句
echo 命令
echo -n 表示不换行输出
echo -e 表示输出转义符
常用的转义符
选项 | 作用 |
---|---|
\r | 光标移至行首,并且不换行 |
\s | 当前shell的名称,如bash |
\t | 插入Tab键,制表符 |
\n | 输出换行 |
\f | 换行,但光标仍停留在原处 |
\ | 表示插入"\"本身转义 |
\b | 表示退格 不显示前一个字符 |
\c | 抑制更多的输出或不换行 |
echo 写脚本的时候 对齐 不换行
[root@localhost ky15]#echo -e "12345\b678"
##退格删除前面的字符
1234678
[root@localhost ky15]#echo -e "12345\b\b678"
123678
[root@localhost ky15]#echo -e "12345\b\b\b678"
12678
[root@localhost ky15]#echo -e "12345\b\b\b\b678"
16785
###注意退格键和末尾的字符相关,超过末尾的字符数量 会出bug 了解即可
[root@localhost ky15]#echo -e "12345678\c"
12345678[root@localhost ky15]#echo -e "1234\c5678"
1234[root@localhost ky15]#
###\c 注意 使用在数字中间会把后面内容删除
echo -e "n\n\n\n\n\nw"|fdisk /dev/sdb
#自动硬盘分区
#!/bin/bash
read -p "请输入你要分区的设备:" disk
read -p "请输入你要分区的大小:" num
echo -e "n\n\n\n\n${num}\nw\n " | fdisk ${disk}
[root@localhost data]#rm -rf 123
#是把软连接删除
[root@localhost data]#rm -rr 123/
#把软连接里的文件全删除
date
date查看当前系统时间
-d 你描述的日期,显示指定字符串所描述的时间,而非当前时间
%F 完整日期格式,等价于 %Y-%m-%d
% T 时间(24小时制)(hh:mm:ss)
[root@localhost ~]# date -d '-1 day' +%F
2021-10-21
[root@localhost ~]# date +%F
2021-08-19
[root@localhost ~]# date -d '1 day ' +%F-%T
2021-08-20-23:28:42
[root@localhost mnt]# date -d "-3 day" 前三天
2021年 08月 18日 星期三 11:30:15 CST
[root@localhost mnt]# date -d "+3 day" 后三天
2021年 08月 18日 星期三 11:30:15 CST
[root@localhost data]#date -d '1 day ' +%F' '%T
2021-10-22 00:45:37
日历
[root@localhost data]#cal 2021
#查看日历
[root@localhost data]#cal 9 1752
九月 1752
日 一 二 三 四 五 六
1 2 14 15 16
17 18 19 20 21 22 23
24 25 26 27 28 29 30
***
crontab 里 不能有 % 号
30 2 * * * /bin/cp -a /etc/ /data/etc`date +\%F_\%T`
30 2 * * * /bin/cp -a /etc/ /data/etc`date +‘%F_%T’`
seq
[root@localhost data]#seq 1 2 10
#从1 开始 步长为2 到10 为止
1
3
5
7
9
[root@localhost data]#seq 9 -1 1
9
8
7
6
5
4
3
2
1
循环含义
将某代码段重复运行多次,通常有进入循环的条件和退出循环的条件
重复运行次数
- 循环次数事先已知 for 已知次数情况下
- 循环次数事先未知 while 和 until 是已知条件
常见的循环的命令:for, while, until
for
语法结构
- 列表循环
- 不带列表循环
- 类C风格的for循环
列表循环
语法:
for 变量名 in {list}
do
command
done
花括号的用法
花括号{}和seq在for循环的应用:
for i in {1..50..2} 1-50的奇数
for i in {2..50..2} 1-50的偶数
for i in {10..1} 1-10倒序排列
for i in $(seq 10) 1-10正序排列
for i in $(seq 10 -1 1) 1-10倒序排列
for i in $(seq 1 2 10) 1-10的奇数,中间为步长
不带列表循环
语法:
for 变量名
do
command
done
例子:
例1:打印hello
第一种:
[root@server ~]# vim for2.sh
#!/bin/bash
for i
do
echo hello
done
[root@server ~]# . for2.sh
#没有给脚本传参所以执行了没有结果
[root@server ~]# . for2.sh a
#把a赋值给变量i,i有值了它就开始执行do..done了
hello
类似于C语言风格的for循环
语法:
for ((expr1;expr2;expr3))
do
command
done
expr1:定义变量并赋初值
expr2:决定是否循环
expr3:决定循环变量如何改变,决定循环什么时候退出
sum=1 i2=2
sum+=i 等于 sum=sum+i
#需要使用 let 命令
++ 自身变量+1
-- 自身变量-1
+=5 自身变量+5
-=5 自身变量-5
*=5 自身变量*5
/=5 自身变量/5
%=5 自身变量%5
例子:
[root@server ~]# vim for3.sh
#!/bin/bash
for ((i=1;i<=10;i+=2)) //i=i+2
do
echo $i
done
执行机制:
依次将列表中的元素赋值给“变量名”; 每次赋值后即执行一次循环体; 直到列表中的元素耗尽,循环
结束
如果省略 [in WORDS ... ] ,此时使用位置参数变量 in "$@"
for 已知循环次数
for tlj(变量) 循环次数(取值列表)
do
需要循环的事件
done
1.for循环有次数
2.for循环开始时,会对变量i进行赋值
3.for循环在赋值后,会执行do 和done之间的代码
4.for循环在第一次循环后执行到done,再次赋值第二个
5.for循环在赋值后,会执行do 和done之间的代码
6.for循环在第一次循环后执行到done,再次赋值第三个
7.for循环在赋值后,会执行do 和done之间的代码
for (( 表达式1; 表达式2; 表达式3 )); do 命令; done
for ((expr1;expr2;expr3))
do
command
done
expr1:定义变量并赋初值
expr2:决定是否循环
expr3:决定循环变量如何改变,决定循环什么时候退出
例子:
[root@localhost data]#vim for.sh
for i
do
echo i=$i
done
[root@localhost data]#bash for.sh a b c d
i=a
i=b
i=c
i=d
[root@localhost data]#for i in `seq 100`;do echo i=$i;done
[root@localhost data]#for i in {1..100};do echo i=$i;done
[root@localhost data]#for i in *.sh;do echo i=$i;done
i=99.sh
i=case.sh
i=dm.sh
i=for.sh
[root@localhost ~]# for i in `seq 10`; do echo "hello world"; done
hello world
hello world
hello world
hello world
hello world
hello world
hello world
hello world
hello world
hello world
#!/bin/bash
sum=0
for i in {1..100}
do
let sum+=i
done
echo sum=$sum
[root@localhost ~]# for i in {1..10}
> do
> echo $i
> done
1
2
3
4
5
6
7
8
9
10
1加到10
[root@localhost ~]# for i in `seq 10`; do sum=$[ $i+ $sum ];done
[root@localhost ~]# ./qiuhe.sh
求和结果是1
求和结果是3
求和结果是6
求和结果是10
求和结果是15
求和结果是21
求和结果是28
求和结果是36
求和结果是45
求和结果是55
[root@localhost ~]# seq -s+ 100|bc
5050
[root@localhost ~]# seq -s+ 1 2 10|bc
25
[root@localhost ~]# seq -s+ 1 2 100|bc
2500
奇偶数
[root@localhost ~]# for i in {1..10..2}
#奇数,从1开始隔两个数
> do
> echo $i
> done
1
3
5
7
9
[root@localhost ~]# for i in `seq 0 2 10`; do echo $i; done
0
2
4
6
8
10
[root@localhost ~]# for ((i=1; i<=10; i+=2))
> do
> echo $i
> done
1
3
5
7
9
for ((i=0;i<=10;i++))
do
sum=$[i+sum]
done
echo $sum
九九乘法表
#打印一行*
#!/bin/bash
for i in {1..9}
do
echo -e " * \c"
done
#打印正方形
#!/bin/bash
for j in {1..9}
do
for i in {1..9}
do
echo -e " * \c"
#\c换行
done
echo
#换行
done
#
#!/bin/bash
for j in {1..9}
do
for i in `seq $j`
do
echo -e "${i}x${j}=$[i*j] \t\c"
#\t tab键可以对齐
done
echo
done
#!/bin/bash
for ((i=1;i<=9;i++))
do
for ((j=1;j<=i;j++))
do
echo -e "${j}x${i}=$[i*j] \t\c"
done
echo
done
倒序99乘法表
#!/bin/bash
for j in {1..9}
do
for i in `seq $[10-$j]`
do
echo -ne " ${i}x`echo $[10-j]`=$[(10 -j)*i]\t"
done
echo
done
#!/bin/bash
for j in {9..1..-1}
do
for i in `seq $[10-$j]`
do
echo -ne " ${i}x`echo $[10-j]`=$[(10 -j)*i]\t"
done
echo
done
PPT例子:
批量添加用户
[root@localhost opt]# vim add.sh
#!/bin/bash
ulist=$(cat /opt/user.txt)
for uname in $ulist
do
useradd $uname
echo "123123" |passwd --stdin $uname &>/dev/null
done
[root@localhost ~]# vim ip.txt
192.168.91.1
192.168.91.100
192.168.91.128
[root@localhost ~]# vim test.sh
#!/bin/bash
ip=`cat /root/ip.txt`
for i in $ip
do
ping -c 3 $i &>/dev/null
if
[ $? -eq 0 ]
then
echo "地址$i网络通顺 "
else
echo "地址$i网络不通顺"
fi
done
#!/bin/bash
host="192.168.91."
for i in {1..254}
do
{
ping -c1 -w1 $host$i &>/dev/null && echo $host$i is up || echo $host$i is down
}&
done
wait
#!/bin/bash
ip="192.168.91."
for i in {1..254}
do
{
ping -c1 -W2 ${ip}.{$i} &>/dev/null
if [ $? -eq 0 ]
then
echo "host $i is online"
else
echo "host $i is down"
fi
} &
done
wait
面试题:
批量改后缀名:
DIR=/data/test
cd $DIR || { echo 无法进入 $DIR;exit 1; }
for FILE in *
do
PRE=`echo $FILE|grep -Eo ".*\."`
mv $FILE ${PRE}bak
done
#!/bin/bash
cd /data
for file in *
do
name=`echo $file |cut -d "." -f1`
mv $file ${name}.bak
done
$RANDOM 取值范围:0-32767
[root@test1 ~]# echo $[$RANDOM%50]
37
[root@test1 ~]# echo $[$RANDOM%20]
15
while
相对于for,需要知道循环次数
我们只知道停止条件,不知道次数,就需要使用while
直到达到条件
while循环
1、语法结构
2、死循环
while循环一般用于有条件判断的循环,若判断条件为真,则进入循环,当条件为假就跳出循环
while :
do
done
while
当命令判断为假时停止
while死循环
while [ 1 -eq 1 ] //写一个永远为真的表达式,1等于1这个条件永远为真,所以这个脚本会一直循环下去
do
command
done
while true
do
command
done
while :
do
command
done
######求和###########
#!/bin/bash
i=0
sum=0
while [ $i -le 100 ]
do
let sum+=$i
let i+=2
done
echo $sum
#!/bin/bash
i=1
sum=0
while [ $i -le 100 ]
do
let sum+=$i
let i+=2
done
echo $sum
#!/bin/bash
i=0
sum=0
for i in {1..100}
do
let sum+=$i
done
echo $sum
for ((i=0,sum=0;i<=100;i++))
do
let sum+=$i
done
echo $sum
i=0
sum=0
while [ $i -le 100 ]
do
let sum+=$i
let i++
done
echo $sum
i=0
sum=0
until [ $i -gt 100 ]
do
let sum+=$i
let i++
done
echo $sum
###############批量建立用户##################################
#!/bin/bash
i=0
while [ "${i}" -le 20 ]
do
useradd stu${i}
echo "123456" |passwd --stdin stu${i} &>/dev/null
if [ $? -eq 0 ]
then
echo "用户 stu${i} 被建立"
else
echo "用户 stu${i} 建立失败"
fi
let i++
done
##############猜价格游戏##########################
#!/bin/bash
p=`echo $[RANDOM%1000+1]`
t=0
while true
do
read -p "请输入商品的价格1-1000:" num
let t++
if [ $num -eq $p ]
then
echo "恭喜你猜中了,实际价格是$p"
echo "您一共猜了${t}次"
exit 0
elif [ $num -gt $p ]
then
echo "您猜的价格高了"
else
echo "您猜的价格低了"
fi
done
#!/bin/bash
i=0
sum=0
until [ $i -gt 100 ]
do
let sum+=$i
let i++
done
echo $sum
双重循环及跳出循环
- break跳出单个循环 break n 数字数字是几代表跳出n层循环
- continue终止某次循环中的命令,但是不会完全终止命令
- exit 直接退出脚本
[root@localhost ~]#cat continue.sh
#结束某次循环
#!/bin/bash
for i in {1..10}
do
if [ $i -eq 5 ]
then continue
fi
echo i=$i
done
[root@localhost ~]#cat break.sh
#结束一层循环
#!/bin/bash
for i in {1..10}
do
if [ $i -eq 5 ]
then break
fi
echo i=$i
done
[root@localhost ~]#cat continue.sh
#本层循环
#!/bin/bash
for i in {1..10}
do
if [ $i -eq 5 ]
then continue 2
fi
echo i=$i
done
[root@localhost ~]#cat break.sh
#本层循环
#!/bin/bash
for i in {1..10}
do
if [ $i -eq 5 ]
then break 2
fi
echo i=$i
done
多层跳出
#!/bin/bash
for i in {1..10}
do
for j in {1..10}
do
echo "j=$j"
done
echo ----------------
done
[root@localhost ~]#cat break.sh
#!/bin/bash
for j in {1..9}
do
for i in {1..9}
do
if [ $i -eq 5 ]
then
break
fi
echo i=$i
done
done
#select 菜单选择
[root@localhost ~]#select menu in 配置网卡 配置yum源;do echo $menu;done
1) 配置网卡
2) 配置yum源
#? 1
配置网卡
#? 2
配置yum源
#?
[root@localhost ~]#PS3="请选择功能(1-2):";select menu in 配置网卡 配置yum源;do echo $menu;done
1) 配置网卡
2) 配置yum源
请选择功能(1-2):1
配置网卡
请选择功能(1-2):2
配置yum源
请选择功能(1-2):
until
until 循环与 while 循环类似,while 循环能实现的脚本 until 同样也可以实现,但区别是while 循环在条件为真是继续执行循环,而 until 则是在条件为假时执行循环
until 循环语句的语法结构如下所示。
until 条件测试操作
do
命令序列
done
实例1:求和
#!/bin/bash
sum=0
i=0
until [ $i -gt 100 ]
do
let sum=$i+$sum
let i++
done
echo sum=$sum
实例2:ppt例子
#!/bin/bash
username=$1
if [ $# -lt 1 ]
then
echo "请在脚本后输入 用户名和发送信息"
exit 1
fi
if grep "^$username" /etc/passwd &>/dev/null
then :
else
echo "用户不存在"
exit 1
fi
until who |grep $username &>/dev/null
do
echo "用户不在线"
sleep 5
done
mes=$2
echo $mes |write $username
菜单
[root@localhost data]#help select
select: select NAME [in 词语 ... ;] do 命令; done
从列表中选取词并且执行命令。
WORDS 变量被展开,生成一个词的列表。展开的词集合被打印
在标准错误输出设备上,每个以一个数字做前缀。如果没有 `in WORDS'
则假定使用`in "$@"'。PS3提示符会被显示并且从标准输入读入一行
如果该行由被显示的词对应的数字组成,则 NAME 变量被设定为相应
的词。如果行为空,则 WORDS 变量和提示符被重新显示。如果读取了
文件结束符,则命令完成。读入任何其他的值会导致 NAME 变量被设定
为空。读入的行被存放在变量 REPLY 中。COMMANDS 命令在每次选择
之后执行直到执行一个 break 命令。
退出状态:
返回最后一个执行的命令的状态。
一定要使用$REPLY
[root@localhost data]#select menu in 配置网卡 配置yum源;do echo $REPLY;done
#与for相似
[root@localhost data]#select menu in 配置网卡 配置yum源;do echo $menu;done
PS3="请选择功能(1-2)";select menu in 配置网卡 配置yum源;do echo $menu;done
PS3="请选择功能(1-2):";select menu in 配置网卡 配置yum源;do echo $menu;done
ps2=
[root@localhost ~]#select menu in 配置网卡 配置yum源;do echo $REPLY;done
1) 配置网卡
2) 配置yum源
#? 1
1
#? 2
2
#? ^C
[root@localhost ~]#select menu in 配置网卡 配置yum源;do echo $menu;done
1) 配置网卡
2) 配置yum源
#? 1
配置网卡
#? 2
配置yum源
PS1 提示符
PS2 多行重定向
PS3 菜单选择
#!/bin/bash
sum=0
PS3="请输入(1-6):"
MENU="
宫保鸡丁
酸菜鱼
鱼香肉丝
佛跳墙
水煮肉片
点菜结束
"
select menu in $MENU
do
case $REPLY in
1)
echo $menu 价格是20
let sum+=20
;;
2)
echo $menu 价格是60
let sum+=60
;;
3)
echo $menu 价格是25
let sum+=25
;;
4)
echo $menu 价格是150
let sum+=150
;;
5)
echo $menu 价格是60
let sum+=60
;;
6)
echo "点菜结束"
break
;;
*)
echo "点菜错误,请重新选择"
;;
esac
done
echo "总价是$sum"
cat <<EOF
#!/bin/bash
set_alias(){
cat >>~/.bashrc <<EOF
alias scandisk="echo '- - -'> /sys/class/scsi_host/host0/scan;echo '- - -'> /sys/class/scsi_host/host1/scan;echo '- - -'> /sys/class/scsi_host/host2/scan"
alias myvim="vim /etc/sysconfig/network-scripts/ifcfg-ens33"
EOF
}
disable_selinux(){
sed -ri.bak 's/^(SELINUX=).*/\1disabled/' /etc/selinux/config
}
disable_firewalld(){
systemctl disable --now firewalld &>/dev/null
echo -e "已禁用防火墙"
}
PS3="请选择(1-4):"
select menu in 关闭防火墙 修改别名 关闭selinux 退出
do
case $REPLY in
1)
disable_firewalld
;;
2)
set_alias
source ~/.bashrc
;;
3)
disable_selinux
;;
4)
break
;;
*)
echo "输入错误"
esac
done
[root@localhost data]#bash menu.sh
1) 关闭防火墙
2) 修改别名
3) 关闭selinux
4) 退出
请选择(1-4):2
|
ls | xargs
标准输入