shell 脚本基础笔记(全)

文章目录

  • bash
    • 脚本的介绍及编写脚本的语法
    • 三种引号的使用
      • 单引号
      • 双引号
      • 反引号
    • 返回值介绍
    • shell的变量:
      • 本地变量:
      • 环境变量:PATH,UID,PS...
      • 位置变量: $0 $1 $2 ... $[10] $# #*
    • 符号,运算符,条件判断
      • 常见的几个符号: > >> ; | &&
      • 常见运算符
      • 常见的条件判断(对比)
        • 连接符
        • 文件属性
        • 数字:
        • 字符串:
  • 返回0 代表 执行成功 与之相反;
      • read(用户交互)
    • 脚本输出上色:
    • 处理海量数据的grep、cut、awk、sed 命令
      • 处理海量数据之grep命令:
      • 处理海量数据之cut命令:
      • 处理海量数据之awk命令:
      • 处理海量数据之sed命令:
    • cat << EOF 使用
    • 循环控制语句if、for、case、while
      • if
      • for循环控制
      • 循环控制语句:break ,continue
      • case循环控制
      • while 循环
        • 普通while循环使用
        • while循环之read使用
        • while循环之死循环妙用
      • until循环
    • 函数/库
      • 函数
      • 调用

bash

脚本的介绍及编写脚本的语法

a脚本调试:
检测脚本中的语法错误: bash -n 文件名
注: 只能检测 语法错误 并不能检测命令语法不存在;
shell 脚本基础笔记(全)_第1张图片
调试执行:bash –x 脚本名 / sh -x 脚本名 ,该方法是通过一行一行执行,有报错的后会提示出来。
shell 脚本基础笔记(全)_第2张图片

解释器是一种命令解释器,主要作用是对命令进行运行和解释,将需要执行的操作传递给操作系统内核并执行,shell 常见的解释器有:
#!/bin/bash (默认)
#!/bin/ksh
#!/bin/bsh
#!/bin/sh

shelll脚本编程:
变成语言的分类:根据运行方式
编译运行:源代码–>编译器(编译)–>程序文件
解释运行:源代码–>运行时启动解释器,由解释器边解释边运行;
编辑模型:过程式编程语言,面向对象的变成语言
程序=指令+数据
过程式:以指令为中心来组织代码,数据是服务于代码
顺序执行
选择执行
循环执行
对象式:以数据为中心来组织代码,围绕数据来组织命令;
类(class):实例化对象,
shell脚本命令的工作方式有两种:交互式和批处理
交互式:用户每输入一条命令就立即执行
批处理:由用户事先编辑好的一个完整的shell脚本,shell会一次性执行脚本中的诸多命令。

查看默认命令行终端解释器:echo $SHELL

配置提示符:username@hostname$ 或root@hostname # 或简单的显示为$/#
$表示普通用户,#表示管理员用户root。
shell 脚本基础笔记(全)_第3张图片
如何写shell脚本:
脚本文件的第一行:给出shebang,解释器路径,用于指明解释器程当前脚本的解释器文件
shell脚本通常以shebang起始:#!/bin/bash
shebang是一个文本行,其实#!位于解释器路径之前,/bin/bashi是Bashi的解释器命令路径。将以#

编写一个简单的shell脚本:
vim ls.sh
#!/bin/bash
#后面跟注释内容,方便以后打开能知道这脚本是干啥的
pwd
ls -al
运行脚本:sh ls.sh
另外一种运行方式 ./ls.sh 但这种需要执行权限 :chomd +x ls.sh 即可
直接写进脚本里的方式:
1) 赋予执行权限,并直接运行次程序文件:

  1. chmod +x /PATH/TO/SCRIPT_FILE
  2. /PATH/TO/SCRIPT_FILE
  1. 直接运行解释器,将脚本以命令行参数 传递给解释器程序
    bash /PATH/TO/SCRIPT_FILE

写一个简单但能接收用户输入参数的shell脚本:
vim ex.sh
#!/bin/bash
echo “当前脚本名称为 0 " e c h o " 总 共 有 0" echo "总共有 0"echo"#个参数,分别是$*。”
echo “第一个参数为$1,第五个参数为$5。”
运行脚本:sh ex.sh one two three four five six serven
运行结果:当前脚本名称为ex.sh
总共有7个参数,分别是one tow three four five six serven
第一个参数为one,第五个参数为five
shell 脚本基础笔记(全)_第4张图片

bash的配置文件;
两类:
profile类:为交互式登陆的shell进程提供配置
bashrc类:为非交互式登陆的shell进程提供配置
登陆类型:
交互式登陆shell进程:
直接通过某终端输入账号和密码后打开的shell进程;
使用su命令:su - USERNAME,或者使用su -| USERNAME执行的登陆切换
非交互式登陆shell进程:
su USERNAME执行的登陆切换
图形界面下打开的终端
运行脚本
profile类:
全局:对所有用户都生效
/etc/profile
/etc/profile.d/*.sh
用户个人:仅对当前用户有效:
~/.bash_profile
功能:
1:用于定义环境变量
2:用于命令或脚本
bashrc类:
全局:
/etc/bashrc
用户个人:
~/.bashrc
功能:
1:定义本地变量
2:定义命令别名
注意:仅管理员可修改全局配置文件

交互式登陆shell进程;
	/etc/profile --> /etc/porfile.d/* .sh--> ~/.bashrc --> /etc/bashrc
非交互式登陆shell进程:
	~/.bashrc --> /etc/bashrc --> /etc/profile.d/*.sh

命令行中定义的特性,例如变量和别名作用域为当前shell进程的生命周期;
配置文件定义的特性,只对随后新启动的shell进程有效。
如:添加一个仅对当前用户有效的bash命令:
vim .bashrc
alias cls=‘clear’
不会立即生效 需要 . .bashrc 后才会生效
在这里插入图片描述
当前用户 执行cls命令 即clear命令
如:让所有用户登陆的时候会收到一个自定义提示和当前时间:

  	vim /etc/profile.d/tishi.sh
  		echo "hello  times: `date` "
	 ![在这里插入图片描述](https://img-blog.csdnimg.cn/20200313213648980.png)

如:定义一个java变量:
vim /etc/profile.d/java.sh
export JAVA_HOME=/user 注:export是定义变量的命令
重读一下 . /etc/profile.d/java.sh 生效
export 查看
shell 脚本基础笔记(全)_第5张图片

让通过配置文件定义的特性立即生效:
1) 通过命令行重复定义一次;
2) 让shell进程重读配置文件;
2. source /PATH/FROM/CONF_FILE
2. ./PATH/FROM/CONF_FILE
shell 脚本基础笔记(全)_第6张图片

提取ip:

ifconfig | egrp -o "'\<(([0-9] | [1-9] [0-9] | 1[0-9] [0-9] | 2[0-4] [0-9] | 25[0-5])\.) {3} ([0-9] | [1-9] [0-9] | 1[0-9] [0-9] | 2[0-4] [0-9] | 25[0-5])\>"

查看 脚本运行路径: hash
删除其中一个路径: hash -d 名称
删除全部路径: hash -r
shell 脚本基础笔记(全)_第7张图片

三种引号的使用

单引号

‘’ :单引号将其中的内容都作为了字符串来,忽略所有的命令和特殊字符,类似于一个字符串的用法

shell 脚本基础笔记(全)_第8张图片

双引号

“” :双引号与单引号的区别在于其可以包含特殊字符(单引号直接输出内部字符串,不解析特殊字符;双引号内则会解析特殊字符),包括’, ", $, ,如果要忽略特殊字符,就可以利用\来转义,忽略特殊字符,作为普通字符输出:
shell 脚本基础笔记(全)_第9张图片

反引号

`` :反引号用来包含一个命令字符串的,其中的命令会先执行,得到的结果会返回到层命令再执行:
shell 脚本基础笔记(全)_第10张图片

返回值介绍

正确的话,返回值是0
不正确的话返回值有很多类型 但为非0 即为不正确
返回值纪录在$? 里(使用方法,先执行一个命令,然后执行echo $?返回值是0则正确0则不正确)
shell 脚本基础笔记(全)_第11张图片
返回值$?仅纪录上一条执行是否成功,不仅输入错误会返回非0值,逻辑错误也会返回非0值,逻辑错误有很多,未查询到结果,ping一个ip不同也属于逻辑错误。。。
shell 脚本基础笔记(全)_第12张图片
在编写shell脚本的时候我们要querString上一条命令有没有执行成功,可以通过 ? 返 回 值 判 断 。 再 比 如 : 现 在 查 看 g r u p 密 码 是 否 设 置 了 , 可 以 通 过 ?返回值判断。 再比如:现在查看grup密码是否设置了,可以通过 ?grup?来判断,如下

#! /bin/bash
grup_pwd=`cat /etc/grub.conf | grep -v ^# | grep password 2> /dev/null`

if [ $? -eq 0 ];then  #返回值是否等于0
   echo "  [ √ ] 已设置grub密码,符合要求"  #等于0
else
   echo "  [ X ] 没有设置grub密码,不符合要求,建议设置grub密码"   #不等于0
fi 

写一个简单的脚本测试,如:写一个只有root用户才能执行的脚本,其他用户则提示指定内容后exit退出当前脚本
shell 脚本基础笔记(全)_第13张图片

shell的变量:

变量是可变的值

本地变量:

变量名=值
变量名可以包含_,数字,大小写字母,但绝对不可以数字开头
=两边不能有空格
值,如果含有空格的话,要使用’ ’ 或者 " " 引起来
定义变量的时候,变量名前是不需要加$的。
shell 脚本基础笔记(全)_第14张图片
特点:只能影响当前的shell ,不能影响子shell,关系图如下 (在子进程中定义永久变量(export) 只会影响子进程,不会影响父进程(bash进子进程,子进程中再bash便是子进程的子进程了)
echo $$查看当前进程id ,父进程id和 子进程id不一样
shell 脚本基础笔记(全)_第15张图片
关于不同执行方式,执行环境也不同,可能是在父进程执行,也可能是在子进程执行,如
shell 脚本基础笔记(全)_第16张图片
bash定义变量是不会影响 子进程,但export定义变量会影响子进程(也可以说 同步到子进程)如:
shell 脚本基础笔记(全)_第17张图片
如:脚本中需要多次使用到一个较长的值,可以定义为变量,后面直接调用变量即可
shell 脚本基础笔记(全)_第18张图片

  • env查看所有环境变量

环境变量:PATH,UID,PS…

变量引用:
shell 脚本基础笔记(全)_第19张图片

查看环境变量:echo $PATH , export 或 declare -x
查看已定义的所有变量:set
删除变量:unset name
查看系统自带配置文件:cat /etc/profile

echo $UID - 查看当前用户uid
echo $USER - 查看当前用户
echo $HOME - 查看当前用户家目录
echo $PS1(数字1) - 查看提示符(如:[root@control ~]# ) 详细参考:https://blog.csdn.net/cuichongxin/article/details/103949335
echo $PS2 - 换行提示符
echo $PATH (很重要)- 当我们执行命令的时候,一定要指定这个命令的路径,如果没有写路径,则会到PATH里 所规定的的路径里 进行查询。详细参考:https://blog.csdn.net/cuichongxin/article/details/103950519
在字符界面登陆终端的时候,首先会运行家目录下面的一个隐藏文件: .bash_profile 位置变量。
预定义变量:双引号—> 是能够解析双引号里特殊字符的 单引号—>忽略单引号里所有的特殊字符 ``—>相当于$0

位置变量: $0 $1 $2 … $[10] $# #*

位置变量 主要是向脚本中传递数据。
set命令作用主要是显示系统中已经存在的shell变量,以及设置shell变量的新变量值。set命令不能够定义新的shell变量。如果要定义新的变量,可以使用declare命令以变量名=值的格式进行定义即可。

  • $? 判断上一个命令执行成功返回0 否则返回1
  • $n 调用参数,前提是得先定义参数n
  • $0 代表命令本身, 1 − 9 代 表 接 受 的 第 1 − 9 个 参 数 , 10 以 上 需 要 用 括 起 来 , 括 号 中 的 就 是 变 量 , 比 如 1-9代表接受的第1-9个参数,10以上需要用{}括起来,括号中的就是变量,比如 191910{10}代表接收的第10个参数,如果不加{},会以为是$1+后面的参数
  • $* 代表接收所有的参数,将所有参数看作一个整体
  • $@ 代表接收的所有参数,将每个参数区别对待
  • $# 代表接收的参数个数

测试,10以上需要用{}括起来,比如${10}代表接收的第10个参数,如果不加{},会以为是$1+后面的参数
shell 脚本基础笔记(全)_第20张图片
比如说,我定义一个aa为book,花了10美元($10),这时不加{}的效果和加{}的效果如下
shell 脚本基础笔记(全)_第21张图片

更加直观的看出 {} 的区别,现在定义一个dir为/root/目录,然后再次使用dir

shell 脚本基础笔记(全)_第22张图片

@ 与 @与 @#的区别在于,比如有4个值,使用#@会循环4次,如果使用$#只循环一次(会将所有参数看作一个整体),如下

#!/bin/bash

echo "\s* 效果为 : "
for i in "$*"
        do
                echo $i
        done

echo "\s@ 效果为 : "
for j in "$@"
        do
                echo $j
        done

shell 脚本基础笔记(全)_第23张图片

说一下位置路径中的 basename 和 dirname的使用
在这里插入图片描述
basename可以用于,脚本中读取 $0的文件名称,因为$0 也是脚本名称 加上basename后便看不到路径了 : basename $0 即可

  • 测试1,位置变量的使用规则测试
#!/bin/bash

echo "脚本的名字是 `basename $0`"
echo "输入的第一个参数是 $1"
echo "输入的第二个参数是 $2"
echo "输入的第三个参数是 $3"
echo "一共输入了 $# 个参数,分别为 $*"

shell 脚本基础笔记(全)_第24张图片

  • 测试2,写一个自定义用户 查询当前系统中是否存在
#!/bin/bash

if [ $# -eq 0 ] ; then
        echo "请加上需要查询的用户名参数"
        exit 1
fi

grep -q $1 /etc/passwd

if [ $? -eq 0 ] ; then
        echo "$1 用户是存在的"
else
        echo "$1 用户不存在"
fi
 

shell 脚本基础笔记(全)_第25张图片

测试:
shell 脚本基础笔记(全)_第26张图片

符号,运算符,条件判断

常见的几个符号: > >> ; | &&

||  
> 重定向
>> 不会覆盖原有内容 的重定向
;  一行 执行多条命令分隔符
| 管道符
&& 与: 前面的命令执行成功,后面的命令才会执行
|| 非:前面的命令执行失败,后面的命令才会执行
2> /dev/null 错误输出到 指定文件
1> /dev null  正确输出到 指定文件

常见运算符

秒变计算器的运算符 expr 仅支持整数
shell 脚本基础笔记(全)_第27张图片
加:expr 12 + 12
减:expr 12 - 12
乘:expr 12 * 12
除:expr 12 / 12
求余:expr 12 % 12
平方:expr 12 ** 12
shell 脚本基础笔记(全)_第28张图片
科学计算器: bc 注:如果没安装bc命令,可直接用yum安装: yum install -y bc
bc计算器保留多少位小数可以通过scale定义,但是scale只对除法、取余数、乘幂 有效;其他可用除1方法来实现scale功能; 如保留2位数 scale=2;
在这里插入图片描述
方法一: 直接输入命令bc 进入计算器模式
shell 脚本基础笔记(全)_第29张图片
方法二: 使用echo 定义参数 用管道符 来输出结果:
在这里插入图片描述

常见的条件判断(对比)

连接符

&&(与)   ||(或)
连接符一般需要判断2个条件,1:整体上是真还是假   2:当判断1完成后,是否要进行判断2
判断1  &&()  判断2 :两边为真则真 ($?返回值是0),如果判断1为真,执行判断2 判断2为假 则整体为假 ,如果判断1为假,则不执行判断2 
判断1  ||()  判断2 :一边为真则整体为真,如果判断1为真 则不执行判断2   ,如果判断1为假($?返回值不为0)则执行判断2,判断2为假 则整体为假 

shell 脚本基础笔记(全)_第30张图片

文件属性

  • 表达式
    文件(夹)或者路径;
    -e 目标是否存在(exist)
    -d 是否为路径(directory)
    -f 是否为文件 (file)
    -r 是否有读取权限(read)
    -w 是否有写入权限(write)
    -x 是否有执行权限 (excute)
    -l 是否有软连接
    -e 是否有block
    shell 脚本基础笔记(全)_第31张图片

数字:

-eq 等于 (equal)
-ne 不等于(not equal)
-gt 大于(greater than)
-lt 小于 (lesser than)
-ge 大于或者等于(greater or equal)
-le 小于或者等于(lesser or equal)
shell 脚本基础笔记(全)_第32张图片

小数(浮点型):Bash中常用的let、expr仅支持整数运算,不支持浮点数计算。要实现浮点数计算,可以使用bc或awk。
shell 脚本基础笔记(全)_第33张图片

字符串:

字符串(字母)比较其实是自动转换为ASCII码的,虽然比较的是字母,其实系统看到的也是其字母对应的ASCII码而已,如a的ASCII码是97,b就是98

=  相等
!=  不相等
> 大于
>= 大于等于
< 小于
<= 小于等于
[] 是 不识别通配符的,[[]]识别通配符 
注: 如果是等于需要使用正则,建议使用: =~  而非 ==
	 

shell 脚本基础笔记(全)_第34张图片

一个简单的判断数值相等与否的shell:

#! /bin/bash
#判断用户输入的两个数是否相等
#ccx
if [ $1 -eq $2 ]then
echo "$1 等于 $2"
else
echo :$1 不等于 $2"
fi

 

shell 脚本基础笔记(全)_第35张图片
创建用户输入的名称 文件:

#! /bin/bash
#创建用户输入的名称 文件
touch $1
if [ $? -eq 0 ] ; then
# 返回0 代表 执行成功 与之相反;
echo "$1 创建成功"
fi
echo "请输入需要创建的文件名称"

在这里插入图片描述
换行:echo -e “\n”

返回0 代表 执行成功 与之相反;

read(用户交互)

顾名思义 read 就是需要用户输入值 比如用于输入密码之类的
原理:read 默认有一个值 $REPLY ,即使单独单独输入read不调用值回车 也会让你输入值
shell 脚本基础笔记(全)_第36张图片
read命令: 先后顺序 t、n、s、p
语法 :read -p “请您输入密码:”
-p:给出提示符,默认不支持“\n”换行 需要echo -e “\n” 实现
-s:隐藏输入的内容
-t:给出等待时间
-n:限制读取字符的个数,触发到临界值会自动执行;
shell 脚本基础笔记(全)_第37张图片

如:现在写一个 根据你输入的年龄判断 该年龄属于什么阶段,并且输入非数字时会提示你输入数字
shell 脚本基础笔记(全)_第38张图片

#!/bin/bash

#echo -n "请输入一个年龄"
#read age

read -p "请输入一个年龄:" age

[[ $age =~ ^[0-9]+$ ]]
if [ $? -ne 0 ]  ; then
        echo "请输入一个数字"
        exit 1
fi

if [ $age -gt 120 ] || [ $age -lt 0 ] ; then
        echo "请输入一个合法的年龄"
elif [ $age -ge 60 ] && [ $age -lt 120 ] ; then
        echo "该年龄为老年人"
elif [ $age -ge 18 ] && [ $age -lt 60 ] ; then
        echo "该年龄为成年人"
else
        echo "未成年"
fi

脚本输出上色:

语法:echo -e “\033[字背景颜色;字体颜色;特效m字符串\033[关闭属性”
注:一下中文字部分 可以替换任何内容
#字体色差范围:30-37

echo -e "\033[30m 黑色字 \033[0m"
echo -e "\033[31m 红色字 \033[0m"
echo -e "\033[32m 绿色字 \033[0m"
echo -e "\033[33m 黄色字 \033[0m"
echo -e "\033[34m 蓝色字 \033[0m"
echo -e "\033[35m 紫色字 \033[0m"
echo -e "\033[36m 天蓝字 \033[0m"
echo -e "\033[37m 白色字 \033[0m"

#字背景颜色范围:40-47

echo -e "\033[40;37m 黑底白字 \033[0m"
echo -e "\033[41;30m 红底黑字 \033[0m"
echo -e "\033[42;34m 绿底蓝字 \033[0m"
echo -e "\033[43;34m 黄底蓝字 \033[0m"
echo -e "\033[44;30m 蓝底黑字 \033[0m"
echo -e "\033[45;30m 紫底黑字 \033[0m"
echo -e "\033[46;30m 天蓝底黑字 \033[0m"
echo -e "\033[47;34m 白底蓝字 \033[0m"

#特效范围: 如果“ [ ”后面的0m 加上了特效 那么后面这特效会一直执行 需要手动改回0m后特效才会停止;

echo -e "\033[0m 无任何特效 \033[0m"
echo -e "\033[1m 高亮度 \033[0m"
echo -e "\033[4m 下划线 \033[0m"
echo -e "\033[5m 闪烁 \033[0m"

注:混合使用需要使用 `` 扩起来:

read -t 5 -n 5 -s -p "`echo -e "\033[32;5m 请输入您的密码: \033[5m"`"  pass

这样就会闪烁了 否则会失效:

处理海量数据的grep、cut、awk、sed 命令

简介:grep、cut、awk、sed 常常应用在查找日志、数据、输出结果等等,并对我们想要的数据进行提取,通常grep,sed命令是对行(hang)进行提取,cut和awk是对列进行提取

处理海量数据之grep命令:

grep应用场景: 通常对数据进行 行的提取
语法:grep [选项] …[内容]…[file]
-v #对内容进行取反提取
-n #对提取的内容显示行号
-w #精确匹配
-i #忽略大小写
^ #匹配开头行首
-E #正则匹配
在这里插入图片描述

处理海量数据之cut命令:

cut应用场景:通常地数据进行列的提取
语法:cut [选项]…[file]

-d  #指定分隔符 
eg:以‘:’为分隔符,截取出/etc/passwd的第一列跟第三列
cut -d ':' -f 1,3 /etc/passwd   #表示通过:截取 1和3列
cut -d ':' -f 1-3 /etc/passwd   #表示通过:截取 1到3列
cut -d ':' -f 2- /etc/passwd   #表示通过:截取 第二列到最后一列

shell 脚本基础笔记(全)_第39张图片
-f #指定截取区域

cut -d ':' -f 1,3 /etc/passwd  注:不加-d 默认我制表符 文件必须+ -d 指明分隔符
 

shell 脚本基础笔记(全)_第40张图片
本身为表的不需要加 -d
shell 脚本基础笔记(全)_第41张图片
-c #以字符为单位进行分割
eg:截取/etc/passwd 文件第二个字符到第九个字符:
cut -c 2-9 /etc/passwdshell 脚本基础笔记(全)_第42张图片
注:不加-d选项,默认为制表符,不是空格
eg:截取linux上面所有可登陆用户:
grep '/bin/bash' /etc/passwd在这里插入图片描述
只提取用户并且除去root用户:

grep '/bin/bash' /etc/passwd | cut -d ':' -f 1 | grep -v root 

在这里插入图片描述

处理海量数据之awk命令:

awk简介:其实一门编程语言,支持条件判断,数组,循环等功能,与grep,sed被称为linux三剑客,之所以叫awk是因为取其三位创始人的 family name 首字符
awk的应用场景:通常对数据进行列的提取;
语法:

awk '条件{执行 动作}' 文件名
awk '条件1{执行动作}条件2{执行动作}... ' 文件名
awk [选项] '条件1{执行动作}条件2{执行动作}... ' 文件名
特殊要点举例说明:
printf 不换行:格式printf("", ) 其中括号可省略,其中格式化字符串包括两部分内容: 
一部分是正常字符, 这些字符将按原样输出 printf("", ); 另一部分是格式化规定字符,
 以"%"开始printf("%.", ), 后跟一个或几个规定字符,用来确定输出内容格式。
 (%ns:字符串型,n代表有多少个字符;%ni:整型,n代表输出几个数字;
 %.nf:浮点型,n代表的是小数点后有多少个小数)

如:printf '%s\t%s\t%s\t%s\t%s\t%s\t\n' 1 2 3 4 5 6
在这里插入图片描述
print #打印出内容,默认会自动换行
\t #制表符
\n #换行符

eg:df -h | grep /dev/sda1|awk '{printf "/dev/sda1的使用率是:"} {print $5} '      

提取df -h 命令 中 /dev/sda1中的使用率
shell 脚本基础笔记(全)_第43张图片
小数:echo "scale=2; 0.13+0.1" | bc | awk '{printf "%.2f\n",$0}'
scale定义保留2位小数,通过bc计算,但bc如果首位是0则不会显示0. 这时候通过printf 来显示0,2f代表后面保留2位小数 ,$0表示输出一整列;科学计算中print格式:(printf “%.”, )
在这里插入图片描述
$0 #代表第一列
$1 #代表第二列
$2 #代表第三列

eg:df -h | grep /dev/sda1| awk '{print $5}' 

在这里插入图片描述
-F #指定分隔符

eg : cat /etc/passwd | awk -F":" '{print $1}'

使用:为分隔符,取passwd中的第一行
shell 脚本基础笔记(全)_第44张图片
BEGIN #在读取所有行内容前就开始执行,常常被用于修改内置变量的值
FS #BEGIN时定义分隔符

eg:cat /etc/passwd |awk 'BEGIN {FS=":"} {print $1}' 

在这里插入图片描述
END #结束的时候 执行
NR #行号

eg:df -h |awk 'NR==2 {print $5}'

显示多行内容:df -h |awk 'NR>=1 && NR<=3 {print $1,$2}'
shell 脚本基础笔记(全)_第45张图片

eg:awk '(NR>=20 && NR<=30) {print $1} ' /etc/passwd
shell 脚本基础笔记(全)_第46张图片

处理海量数据之sed命令:

   sed的应用场景:主要对数据进行处理(选取,新增,替换,删除,搜索)

sed语法:sed [选项] [动作] 文件名
常见的选项与参数:
-n #吧匹配到的行输出打印到屏幕
p #以行为单位进行查询,通常与-n一起使用
如:df -h | sed -n '2p'
shell 脚本基础笔记(全)_第47张图片
d #删除
如:df -h |sed '2d'注:这种只删除内容 并不对源文件做改变,更改源文件需在sed后加 -i
shell 脚本基础笔记(全)_第48张图片
a #在行的下面插入新的内容
如:在第二行下面插入新的内容:sed '2a test yes !!!' df .txt,注:这操作并不对源文件做出改变,更改源文件需在sed后加 -i
shell 脚本基础笔记(全)_第49张图片
i #在行的上面插入新的内容
如:在第二行上面插入新的内容:sed '2a test yes !!!' df .txt,注:这操作并不对源文件做出改变,更改源文件需在sed后加 -i
在这里插入图片描述
c #替换
如:把第二行的内容替换为 test yes!!!:sed '2c test yes!!!' df.txt注:这操作并不对源文件做出改变 ,更改源文件需在sed后加 -i
shell 脚本基础笔记(全)_第50张图片
s/ 要被取代的内容/新的字符串/g #指定内容进行替换
如:吧df.txt文件中的0%替换为100%: sed 's/0%/100%/g' df.txt注:该操作不会对原文件作出改变,更改源文件需在sed后加 -i
shell 脚本基础笔记(全)_第51张图片
-i #对源文件进行修改 高危操作:修改前对原文件备份
如:吧df.txt文件中的0%替换为100%: sed -i 's/0%/100%/g' df.txt
shell 脚本基础笔记(全)_第52张图片
搜索:在文件中搜索内容
如:查找df.txt文件里100%的条目 -n 显示 ,p 查询:2种表达方式
shell 脚本基础笔记(全)_第53张图片
-e #表示可以执行多条动作
sed -i -e '1a #你说一切都是没想好' df.txt -i -e '3a #得到得和想要的对不上号' df.txt -i -e 's/100%/0%/g' df.txt注:每一次-e 前面的都会重新跑一遍;
shell 脚本基础笔记(全)_第54张图片

cat << EOF 使用

这个其实就是一个可以自定义的注释信息,简单来说 就是 用于脚本开头解释
语法:cat << EOF
其中EOF可以替换为任意字符,但开头和结尾必须一致
这儿就可以自定义 信息了 这儿定义什么 屏幕上就会打印什么
EOF
shell 脚本基础笔记(全)_第55张图片
这个单独用于打印屏幕上 没什么意义,但可以用于写入 文本中和在脚本中使用,如写入文本:
shell 脚本基础笔记(全)_第56张图片

以脚本为例:这就是一个手动执行的脚本,如下图,如果想了解该脚本,参考:https://blog.csdn.net/cuichongxin/article/details/101759690
shell 脚本基础笔记(全)_第57张图片
看看执行效果,因为我加了while ,所以每一次操作都会显示该内容
shell 脚本基础笔记(全)_第58张图片

循环控制语句if、for、case、while

if

if循环控制(单分支与多分支):
单分支1:
if [条件判断];then
执行动作
fi

单分支2:条件成立执行动作1,否则执行动作2
if [条件判断];then
执行动作1
else
执行动作2
fi
如:判断111.txt文件是否存在,不存在则创建,并写入内容

!#/bin/bash
#。。。。
#ccx
if [ -e 111.txt ]; then
        echo '111.txt存在'
else
        echo '111.txt不存在,现已为您创建111.txt文本'
        touch 111.txt
        echo '并且该内容写入进了111.txt文本中'
        echo '并且该内容写入进了111.txt文本中' > 111.txt
        cat 111.txt
fi

shell 脚本基础笔记(全)_第59张图片

也可以改成用户输入文件判断并创建: 注:if [ -e $1 ] 是想对路径 可写成绝对路径 如 /etc/$1

!#/bin/bash

if [ -e $1 ];
        then 
        echo $1'存在'
else
        echo $1'不存在,现已为您创建'$1
        touch $1
        echo '并且该内容写入进了'$1'文本中'
        echo '并且该内容写入进了'$1'文本中' > $1
        cat $1
fi
 

shell 脚本基础笔记(全)_第60张图片
多个判断(多分支循环);
if [条件判断];
then
执行动作
elif [条件判断];then
执行动作
elif [条件判断];then
执行动作

fi
shell 脚本基础笔记(全)_第61张图片

for循环控制

(1) for 变量名 in 值1 值2 值3
do
执行动作
命令1,$变量名
….
done
如:每隔1秒打印一次1-10的循环条件 sleep睡眠命令
shell 脚本基础笔记(全)_第62张图片
(2) for 变量名 in 命令
do
执行动作
done
如:每隔1秒打印一次1-10的循环条件 sleep睡眠命令
seq –w(补0) 直接 seq –w 1 10 即可
shell 脚本基础笔记(全)_第63张图片
其实可以利用利用该方法来批量建用户之类的
shell 脚本基础笔记(全)_第64张图片
也可以使用正则,如列出某目录下所有以.d结尾的文件
shell 脚本基础笔记(全)_第65张图片

(3) for ((条件))
do
执行动作
done
如:每隔1秒打印一次1-10的循环条件 sleep睡眠命令
shell 脚本基础笔记(全)_第66张图片

循环控制语句:break ,continue

break是满足条件跳出循环
continue 提前结束本次循环而开始进行下一轮(跳出满足条件的条件)

做一个break的测试(命令要放在break之前,也就是先执行后判断)
shell 脚本基础笔记(全)_第67张图片
做一个continue的测试(命令要放在continue之后,也就是先判断后执行)
shell 脚本基础笔记(全)_第68张图片
来一个多次循环嵌套的说明一下(这是正常的循环)
shell 脚本基础笔记(全)_第69张图片
加一个brack试试
shell 脚本基础笔记(全)_第70张图片
shell 脚本基础笔记(全)_第71张图片

case循环控制

应用场景:case循环常用语多重分支,与if不同的是,if可以判断多个条件,case只能判断一种条件
语法结构:

case 变量 in
'值1')
执行动作
;;

'值2')
执行动作
;;

'值3')
执行动作
;;

...
esac

如:现在写一个 连接光盘的脚本
shell 脚本基础笔记(全)_第72张图片

	#!/bin/bash

cat << !!
********************************************
*  这是一个询问脚本                        *
********************************************
!!

read -p "请问是否已经吧光盘连接起来了?(y/n):" say
case $say in
        y|Y)
                ;;
        n|N)
                echo "请先吧光盘连接上去"
                exit 1
                ;;
        *)
                echo "只能输入y/n!!!"
                exit 1
esac

echo ‘下面是正常的操作’
#该处放输入y以后需要执行的命令
#如 mount …

while 循环

普通while循环使用

应用场景:while 循环是条件循环也是不定循环,只要条件判断式成立,循环就会一直进行着,直到判断式不成立 或者 选择跳出循环 才会结束;也就是说 每次执行完do和done之间的语句,会再次到while后面的条件进行对比,如果城里,再次执行do和done之间的语句。
while [ 条件判断式 ]
do
执行动作
done
shell 脚本基础笔记(全)_第73张图片
写一个遍历1-10的数 自动跳过第4个
shell 脚本基础笔记(全)_第74张图片

while循环之read使用

语法: while read 变量名 ; do
执行动作
done < 读取文件

说一下执行读取读取文件的操作
遍历之前先来说一下,read,这个平常是用来接收用户输入的值的,当然也可以读取文件中的值,只是 单独使用read读取某文件的值 只能读取第一行
在这里插入图片描述
如果用read纪录/etc/passwd全部文件,就需要用到while
shell 脚本基础笔记(全)_第75张图片

while也可以用来读取某个某个文件的值 而做下一步操作,比如 把一堆ip写在一个文件中(注意 必须一行一个ip) 批量ping 或者啥的, 也或者 把 一堆用户名写在一个文件里 批量建用户, 现在测试批量建用户
shell 脚本基础笔记(全)_第76张图片

实现wc –l 这个功能,后面必须跟上一个文本本间,来统计这个文件的行数
declare
declare或typeset内建命令(它们是完全相同的)可以用来限定变量的属性.这是在某些编程语言中使用的定义类型不严格的方式。命令declare是bash版本2之后才有的。命令typeset也可以在ksh脚本中运行。 -i 整数
shell 脚本基础笔记(全)_第77张图片

#!/bin/bash

if [ $# -eq 0 ] ; then
        echo "请输入一个参数"
        exit 1
fi

declare -i num=0

while read aa ;do 
        let num=$num+1
done < $1
echo "${num}$1"

while循环之死循环妙用

死循环 顾名思义 就是循环一直存在 直到手动取消
语法有3种:
1、 while true ; do
执行语句
done
2、 while ((1)) ; do
执行语句
done
3、 while : ; do
执行语句
done

有时候需要while一直循环下去(死循环)
比如说 某个服务 有时候会自动停止,我们不知道,但如果使用while语句一直检测,某服务,如果检测停止后 就自动 start 启动, 先说明一下,如果查看服务是启动的 返回值是0 如果不是启动的 返回结果则非0
shell 脚本基础笔记(全)_第78张图片
现在以http 服务 为例,写一个脚本自动检测 该服务是否是active,如果不是 则自动start启动该服务,运行时 sh 脚本名称 > /dev/null & 最下面有说明 为什么这么执行以及执行后如果停止。
shell 脚本基础笔记(全)_第79张图片

#!/bin/bash

while true ; do
        systemctl is-active httpd

        if [ $? -ne 0 ] ; then
                systemctl start httpd
        fi
done

如果不吧输出结果 放到/dev/null 和放在后台执行后结果
shell 脚本基础笔记(全)_第80张图片

放到后台以后,jobs 查看 后台进程 kill -9 %1 杀死该进程
shell 脚本基础笔记(全)_第81张图片

until循环

until循环和 while循环 相反,while是满足条件条件后执行 ,rntil是不满足条件后执行
语法:
untile 条件 ; do
执行命令
done

如:
let 命令是 BASH 中用于计算的工具,用于执行一个或多个表达式,变量计算中不需要加上 $ 来表示变量。如果表达式中包含了空格或其他特殊字符,则必须引起来。
deckare 是定义变量类型,-i 是整数
shell 脚本基础笔记(全)_第82张图片
对until这种反人类语法 感兴趣的就自己去深究一下

函数/库

函数

就是一个功能模块,调用这个函数的时候,就可以直接调用这个功能了,不需要再次重复写代码。
函数不引用是不执行的,并且只能再同一个脚本里重复引用,其他脚本里不能引用该函数
语法有3种:
1、 function函数名 (){
…….执行命令
}
2、function 函数名{
……执行命令
}
来一个简单的使用规则
shell 脚本基础笔记(全)_第83张图片
#!/bin/bash

function x1 () {
date
}

x1
x1
x1

稍微复杂一点的
shell 脚本基础笔记(全)_第84张图片

#!/bin/bash

function x1 () {
        declare -i num=0
        while read aa ; do
                let num=$num+1
        done < $1
        echo "${num}$1"

}

函数是只能在自己脚本中使用,如果想在其他脚本中使用,就得使用库。
语法:
库名 (){
….执行命令
}
另外一个文件 直接 . 库名 即可调用

shell 脚本基础笔记(全)_第85张图片

调用

调用死参数意义不大,但可以这么实现,死参数可以替换为灵活的,比如用户输入的 $1 $2 等等。了解就行,一般脚本用到的几率不高!
shell 脚本基础笔记(全)_第86张图片

你可能感兴趣的:(shell,shell基础笔记)