GrandOB

脚本大纲

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脚本用途

  • 将简单的命令组合完成复杂的工作,自动化执行命令,提高工作效率
  • 减少手工命令的重复输入,一定程度上避免人为错误
  • 将软件或应用的安装及配置实现标准化
  • 用于实现日常性的,重复性的运维工作,如:文件打包压缩备份,监控系统运行状态并实现告警等

脚本执行逻辑

  1. 顺序执行:程序按从上到下顺序执行

  2. 选择执行:程序执行过程中,根据条件的不同,进行选择不同分支继续执行

  3. 循环执行:程序执行过程中需要重复执行多次某段语句

执行方式

通过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 环境中的配置

脚本错误调试

  1. 命令错误

    命令出错不会影响接下来的命令继续

    hostname
    echo 'finsh'
    
    
  2. 语法错误

    会影响接下来的命令继续

    echo "hello world"
    hstname
    
    cat > /data/kgc.tx <<EOF
    123
    123
    EOF 
    echo "ni hao"
    
  3. 逻辑错误

    只能自己去筛查

查代码的正确

bash -n 脚本名称 (不在当前目录下加绝对路径)     
检查语法错误



bash -x 脚本名称 (不在当前目录下加绝对路径)     逻辑错误
#将脚本的所有语句执行一遍,

总结:脚本错误常见的有三种区别

  1. 语法错误,会导致后续的命令不继续执行,可以用bash -n 检查错误,提示的出错行数不一定是准确的

  2. 命令错误,默认后续的命令还会继续执行,用bash -n 无法检查出来 ,可以使用 bash -x 进行观察

  3. 逻辑错误:只能使用 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. 格式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
[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 环境变量

  1. 由系统提前创建,用来设置用户的工作环境
  2. 可以使用env查看环境变量
  3. 需要记住的常用环境变量
[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)短路与 &&

image-20211020004645408

CMD1 短路与 CMD2      &&   同时满足命令1 和命令2 的要求  才会返回正确


逻辑与
第一一个命令为真,才需要执行第二个命令
全真才为真,一假即为假

第一个命令假了,一定假了    

逻辑或
一真即为真,全假才为假
第一个命令为真,不需要执行第二个命令了,  一定为真了
第一个命令为假,需要执行第二个命令来看 整个式子的结果





全真才为真  一假即为假      
第一个CMD1结果为真 ,第二个CMD2必须要参与运算,才能得到最终的结果 
第一个CMD1结果为假 ,总的结果必定为假,因此不需要执行CMD2

(2)短路或 ||

image-20211020004719848

CMD1 短路或 CMD2
一真即为真
第一个CMD1结果为真 (1),总的结果必定为1,因此不需要执行CMD2
第一个CMD1结果为假 (0),第二个CMD2 必须要参与运算,才能得到最终的结果

image-20220328120025087

[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'
#左轮

image-20211019145952628

image-20211019150018794

image-20211019150043514

image-20211019150114923

#会给你一串密码:比如 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

image-20211210001505637

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    

标准输入

posted on 2024-06-30 11:41  OB书写  阅读(21)  评论(0编辑  收藏  举报

导航