shell编程规划与变量

184 阅读16分钟

shell概述

Shell 既是一种命令语言,又是一种程序设计语言。 Shell 是指一种应用程序,这个应用程序提供了一个界面,用户通过这个界面访问操作系统内核的服务。 Ken Thompson 的 sh 是第一种 Unix Shell,Windows Explorer 是一个典型的图形界面 Shell。

概念

  • 将要执行的命令按顺序保存到一个文件
  • 给该文件可执行权限
  • 可结合各种shell控制语句完成更复杂的操作

应用场景

  • 重复性操作
  • 交互性任务
  • 批量事物处理
  • 服务运行状态监控
  • 定时任务执行
如果有人爆破我的机器就可以查看
[root@localhost ~]# vim /var/log/secure 

Aug 17 02:14:23 localhost polkitd[727]: Loading rules from directory /etc/polkit-1/rules.d
Aug 17 02:14:23 localhost polkitd[727]: Loading rules from directory /usr/share/polkit-1/rules.d
Aug 17 02:14:24 localhost polkitd[727]: Finished loading, compiling and executing 8 rules
Aug 17 02:14:24 localhost polkitd[727]: Acquired the name org.freedesktop.PolicyKit1 on the system bus
Aug 17 02:14:27 localhost sshd[1100]: Server listening on 0.0.0.0 port 22.

shell的作用

  1. Shell就是命令行工具的胶水,没有任何语言能像Shell一样方便地将一大堆命令行工具组合起来。原则上来说,Shell做什么都可以,但显然它最适合的是自动化,因为只需要将你原来手动敲的命令都复制到一个文件里面就行了。

  2. Shell跟标准的编程语言区别很大,它基本上是一个面向字符串的编程语言,组合用好awk/sed/grep,偶尔配合eval,有时候会发挥奇效,但也有可能原地爆炸。可以跟Python之类的其他语言配合起来,比如某个复杂的功能使用一个Python脚本来实现,然后在shell中调用这个脚本实现较复杂的功能;或者反过来,在Python脚本中调用外部的Shell脚本来提高自动化的效率,也是可以的。

QQ截图20220823202951.png

  • 用户输入指令以后交给shell处理
  • shell收到指令以后将命令转换成二进制而言交给内核处理
  • 内核收到指令后调用相关的内核交给系统硬件进行处理

Shcll(壳程序)是一个特殊的应用程序,它介于操作系统内核与用户之间,充当了一个"命令解释器""角色,负责接收用户输入的操作指令(命令)并进行解释,将需要执行的操作传递给内核执行,并输出执行结果。

Linux中内置的shell

[root@localhost ~]# vim /etc/shells

/bin/sh       
/bin/bash
/sbin/nologin
/usr/bin/sh
/usr/bin/bash   
/usr/sbin/nologin
/bin/tcsh
/bin/csh
常用的shell
bash   //基于GNU的框架下发展出的shell
csh    //语法类似于c语言的shell
tcsh    //整合了 csh 提供更多的功能
sh   //已经被bash所替换
nologin    //奇怪的shell  这个shell可以让用户无法登陆主机

bash (/bin/bash) 是目前大多数Linux版本采用的默认shell

要查看用户使用哪一个shell可以查看(/etc/passwd)

[root@localhost ~]# vim /etc/passwd

root:x:0:0:root:/root:/bin/bash
bin:x:1:1:bin:/bin:/sbin/nologin
daemon:x:2:2:daemon:/sbin:/sbin/nologin
adm:x:3:4:adm:/var/adm:/sbin/nologin
lp:x:4:7:lp:/var/spool/lpd:/sbin/nologin
sync:x:5:0:sync:/sbin:/bin/sync
shutdown:x:6:0:shutdown:/sbin:/sbin/shutdown
halt:x:7:0:halt:/sbin:/sbin/halt
mail:x:8:12:mail:/var/spool/mail:/sbin/nologin
operator:x:11:0:operator:/root:/sbin/nologin
games:x:12:100:games:/usr/games:/sbin/nologin
ftp:x:14:50:FTP User:/var/ftp:/sbin/nologin
nobody:x:99:99:Nobody:/:/sbin/nologin
systemd-network:x:192:192:systemd Network Management:/:/sbin/nologin
dbus:x:81:81:System message bus:/:/sbin/nologin
polkitd:x:999:997:User for polkitd:/:/sbin/nologin
abrt:x:173:173::/etc/abrt:/sbin/nologin

shell脚本的作用

脚本(script)就是包含一系列命令的一个文本文件。Shell 读取这个文件,依次执行里面的所有命令,就好像这些命令直接输入到[命令行]一样。所有能够在命令行完成的任务,都能够用脚本完成。

脚本的好处是可以重复使用,也可以指定在特定场合自动调用,比如系统启动或关闭时自动执行脚本。

  1. 自动化运维
  2. 批量化重复操作可以编写脚本结合计划任务自动周期性运行
  3. 减轻管理员工作量
  4. 提高处理文本文件的速度
  5. 避免配置出错

扩充了解:

shell + Python

shell 可针对Linux系统做自动化运维和状态监控

Python 可针对通过ARI接口对 应用程序 做数据的收集  统计和分析

编程语言(解释性语言)
强类型
命令:int  string
代表语言:C  C++  JAVA   CO
弱类型
代表语言:shell Python(外置)

shell脚本的构成

  • 脚本申明(申明解释器) :第一行开头 “#!/bin/bash”,表示此行以下的代码语句是通过/bin/bash程序来执行。还有其他类型的解释器,比如 #/usr/bin/python、#!/usr/bin/expect 。

  • 注释信息: 以“#”开头的语句表示为注释信息,被注释的语句在脚本运行时不会被执行。

  • 可执行语句: 如echo命令,用于输出“ ”之间的字符串

Shell  脚本代码  申明解释器 #!/bin/bash  或省略

Python 代码    必须申明解释器 #!/usr/bin/python  或  #!+ python执行文件的其他路径
[root@localhost ~]# vim demol.sh

#!/bin/bash   
#desc: this is a simple shell script <2022823>
echo "hello world"
要执行脚本就要加上权限
[root@localhost data]# chmod +x demol.sh
[root@localhost data]# ll
总用量 4
-rwxr-xr-x. 1 root root 98 823 23:21 demol.sh
执行脚本 ./
[root@localhost data]# ./demol.sh
hello world

*[root@localhost data]# vim demol.sh [root@localhost data]# ls demol.sh *

尾部是.sh的文件都是shell脚本 QQ截图20220823231023.png 写脚本

  1. 将要执行的命令按顺序一一列出,保存到一个文本文件,最后自动执行。
  2. 执行脚本需要x权限,也可以使用绝对路径来执行。
  3. 可结合各种Shell控制语句以完成更复杂的操作。
[root@localhost data]# vim demol.sh

#!/bin/bash
#desc:this si a simple shell script <2022823>
cd /boot         //切换目录
echo "当前所在目录为:"   //输出字符串内容
pwd          //显示当前所在目录的路径
echo"其中以vml开头的文件有:"  //输出字符串内容
ls -lh vml*    //输出以vml开头的文件
~                   

QQ截图20220823233233.png 添加权限

[root@localhost data]# vim demol.sh
[root@localhost data]# rm -rf demlo.sh
[root@localhost data]# ll
总用量 4
-rw-r--r--. 1 root root 98 823 23:21 demol.sh
[root@localhost data]# chmod +x demol.sh
[root@localhost data]# ll
总用量 4
-rwxr-xr-x. 1 root root 98 823 23:21 demol.sh

QQ截图20220823234047.png 执行命令

执行命令可以用两种方式去执行

绝对路径:/data/demol.sh 相对路径:./demol.sh

[root@localhost data]# pwd
/data
[root@localhost data]# /data/demol.sh  //绝对路径执行
当前所在目录为:
/boot
-rwxr-xr-x. 1 root root 5.7M 817 02:12 vmlinuz-0-rescue-a0b3252dfe4f4ab4b25084b31120b5e4
-rwxr-xr-x. 1 root root 5.7M 823 2017 vmlinuz-3.10.0-693.el7.x86_64
/data/demol.sh:行8: /root: 是一个目录
[root@localhost data]# /root/data/demol.sh
-bash: /root/data/demol.sh: 没有那个文件或目录
[root@localhost data]# ./demol.sh   //相对路径执行
当前所在目录为:
/boot
-rwxr-xr-x. 1 root root 5.7M 817 02:12 vmlinuz-0-rescue-a0b3252dfe4f4ab4b25084b31120b5e4
-rwxr-xr-x. 1 root root 5.7M 823 2017 vmlinuz-3.10.0-693.el7.x86_64
./demol.sh:行8: /root: 是一个目录

QQ截图20220823234304.png 如果没有执行权限是无法执行脚本的

[root@localhost data]# chmod -x demol.sh
[root@localhost data]# ./demol.sh
-bash: ./demol.sh: 权限不够
[root@localhost data]# ll
总用量 4
-rw-r--r--. 1 root root 176 823 23:36 demol.sh

QQ截图20220823235210.png 创建shell脚本

#!/bin/bash   申明解释器
#xxxxx       坐脚本的注释信息
xxxxxx       运行代码

运行脚本
1.会在脚本的子shell环境中执行脚本的代码
使用绝对路径或者相对路径指定脚本的路径运行,要求脚本必须要有执行权限  X
指定shell程序来执行解释运行脚本
bash 脚本文件
sh

2.会在当前的shell环境中执行脚本里的代码操作,也就是脚本中的代码或者命令会影响当前shell
source 脚本文件环境

重定向与管道操作

管道操作  
将管道符号*|"左侧的命令输出的结果,作为右侧命令的输入(处理对象),同一行命令中可以使用多个管道。

Ps aux |wc -l     
[root@localhost ~]# ps aux |wc -l   //统计进程数量\
154

ss -ntap | grep 22   //查看22端口是否开启

echo "abc123"|passwd --stdin lisi   //非交互式设置用户密码

如果管道符号右边是一定需要执行对象的命令,管道符号后面要有  xaegs  命令来传递执行参数

交互式硬件设备

标准输入:从该设备接收用户输入的数据
标准输出:通过该设备向用户输出数据
标准错误:通过该设备报告执行出错信息
类型设备文件文件描述编号默认设备
标准输入/dev/stbin0键盘
标准输出/dev/stdout1显示器
标准错误输出/dev/stdrr2显示器

输入重定向

符号作用
命令 < 文件从指定的文件读取文件,而不是从键盘输入
命令 << 分界符从标准输入中读入,直到遇见分界符才停止
命令 < 文件1 > 文件2将文件1 作为命令的标准输入并将标准输出到文件2

输出重定向

符号作用
命令 > 文件将标准输出结果保存到指定的文件中(覆盖原有内容)
命令 >> 文件将标准输出结果追加到指定的文件尾部
命令 2> 文件将错误输出信息保存到指定文件中(覆盖原有内容)
命令 2>> 文件将错误输出信息追加到指定文件尾部
命令 > 文件 2>&1混合输出,将标准输出与错误输出保存到文同一个文件中
命令 2> 文件 1>&2混合输出,将标准输出与错误输出保存到文同一个文件中
命令 &> 文件混合输出,将标准输出与错误输出保存到文同一个文件中
命令 >& 文件混合输出,将标准输出与错误输出保存到文同一个文件中

&表示混合,&> 和 >& 都表示将标准输出和错误输出重定向到同一个文件。

shell变量的作用

变量的作用

  • 用来存放系统和用户需要使用的特定参数(值)
  • 变量名:使用固定的名称,由系统预设或用户定义
  • 变量值:能够根据用户设置、系统环境的变化而变化

变量的类型

  • 自定义变量:由用户自己定义、修改和使用
  • 特殊变量:环境变量,只读变量,位置变量,预定义变量

定义一个新的变量

  • 变量名以字母或者下划线开头,区分大小写,建议全大写

格式 : 变量名=变量值

$引用变量名输出变量值

[root@localhost ~]# a=1
[root@localhost ~]# A=2
[root@localhost ~]# echo $a
1
[root@localhost ~]# echo $A
2
[root@localhost ~]# abc123=123
[root@localhost ~]# 123=12  //必须用字母或者下划线开头
bash: 123=12: 未找到命令...

变量的值会取它最后一个赋予的值

=号代表赋值

[root@localhost ~]# a=1 
[root@localhost ~]# a=2
[root@localhost ~]# a=3
[root@localhost ~]# echo $a
3
[root@localhost ~]# name=wl
[root@localhost ~]# class=10
[root@localhost ~]# echo $name $class  //同时输出
wl 10
[root@localhost ~]# echo $name$class   //合并输出
wl10

[root@localhost ~]# echo $name10  
系统会把name10当做一个变量名,没有定义所以输出什么都没有

[root@localhost ~]# echo $name"10"  //可以用""号单独扩出来
wl10
[root@localhost ~]# echo ${name}10   //使用{}括号括起来也是可以实现
wl10
想在变量后面加上空格那么一定要加""号来实现
否则无法实现
[root@localhost ~]# name=wangwu
[root@localhost ~]# echo $name
wangwu
[root@localhost ~]# name=wang wu
bash: wu: 未找到命令...
[root@localhost ~]# name="wang wu"
[root@localhost ~]# echo $name
wang wu

如果在没有$符号的情况下'' "" 两个符号是没有区别的

如果有$符号的情况下'' "" 两个符号是有去别的

''只会把$符号当做一个普通的符号去使用

""会应用后面的字符串当做一个量变,应用变量的值

[root@localhost ~]# a='$name'
[root@localhost ~]# echo $a
$name
[root@localhost ~]# a="$name"
[root@localhost ~]# echo $a
wang wu

想给read有提示信息有两种方式

[root@localhost ~]# vim 1.sh
#!/bin/bash    //申明解释器

read -p "提示信息" ab   
echo "ab变量的值为:"
echo $ab

[root@localhost ~]# sh 1.sh
提示信息123
ab变量的值为:
123

[root@localhost ~]# vim 1.sh
#!/bin/bash

echo -n "请输入变量值"
read  ab
echo "ab变量的值为:"
echo $ab
[root@localhost ~]# sh 1.sh
请输入变量值123132
ab变量的值为:
123132

赋值时使用引号

  • 双引号:允许通过$符号引用其他变量值
  • 单引号:禁止引用其他变量值,$视为普通字符
  • 反撇号:命令替换,提取命令执行后的输出结果

整数变量的运算

格式

expr 变量1 运算符 变量2 [运算符 变量3

常用的运算符

加法运算+
减法运算-
乘法运算\ *
除法运算/
求模(取余)运算%
[root@localhost ~]# expr 5 / 2
2
[root@localhost ~]# expr 5 % 5
0

[root@localhost ~]# echo $((2+5))
7
[root@localhost ~]# echo $((5-1))
4
[root@localhost ~]# echo $[ 5+2]
7
[root@localhost ~]# echo $[5/5]
1
[root@localhost ~]# echo $[5%2]
1
[root@localhost ~]# let i=5\*2
[root@localhost ~]# echo $i
10
[root@localhost ~]# let i++
[root@localhost ~]# echo $i
11
[root@localhost ~]# let i--
[root@localhost ~]# echo $i
10
[root@localhost ~]# let i+=2
[root@localhost ~]# echo $i
12
[root@localhost ~]# let i-=2
[root@localhost ~]# echo $i
10
[root@localhost ~]# echo "1.1+1.2" | bc
2.3
想指定输出多少为小数
[root@localhost ~]# echo "scale=2;5.1/2.1" | bc
2.42
[root@localhost ~]# echo "scale=3;5.1/2.1" | bc
2.428

混合运算
[root@localhost ~]# echo "scale=2;3/(5.8+1.5)*5" | bc
2.05

awk运算
[root@localhost ~]# awk 'BEGIN{print 4.1+1.1}'
5.2

总结运算方法:

常用的运算表达式:

i=$(expr 12 \ * 5 )

i=$((1 * 5 ))

i=$[12 *1]

let i=1*5

i++ 相当于 i=[[i+1]

i-- 相当于 i=[[i-1]

i+=2 相当于 i=[[i+2]

四种整数运算

expr  数值或者变量    运算符  数值或者变量
$(( 数值  运算符  数值 ))
$[数值  运算符  数值]
let变量=<数值>运算符<数值>
两种浮点运算

echo "浮点运算表达式" | bc
awk  'BEGIN {print 浮点运算表达式}'

变量

环境变量

环境变量由系统提前创建,用于设置用户的工作环境

常用的环境变量
[root@localhost ~]# env
HOSTNAME=localhost.localdomain    //获取当前主机的主机名
SHELL=/bin/bash   //可以查看当前的shell环境
HISTSIZE=1000    //当前的历史条目数
USER=root   //当前的用户名
PATH=/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/root/bin    //想要系统能识别命令就要放到这些路径中
PWD=/root   //变量  也能活得当前所在的目录
LANG=zh_CN.UTF-8   //当前使用的语言以及字符集
命令作用
echo$PATH查看当前搜索路径
PATH="$PATH:/root"将/root目录添加到搜索路径
export PATH="$PATH:/root"输出为全局环境变量
环境变量的全局配置文件为/etc/profile   
在此文件中定义的变量作用于所有用户
每个用户还有自己的独立配置文件
(~/.bash_profile)可以用来长期变更或者设置某个环境变量
[root@localhost ~]# vim /root/.bash_profile
export HISTSIZE=200
修改root用户的历史命令记录条数

echo $HISTSIZE
aource /root/.bash_profile
读取并执行文件中的设置
echo $H工STSIZE

readonly命令设置只读变量
product-beTet
readonly product   //设置为只读变最
echo $product
product-accp  //只读变量不可以被电新赋值
unset product    //只读变量不可以被删除,unset命令用于删除变量

位置变量

当执行命令行操作时,第一个字段表示命令名或脚本程序名,其余的字符串参数按照从左到右的顺序依次赋值给位置变量。 n:n为数字,s0代表命令本身,n: n为数字,s0代表命令本身,1-9代表带一个到第九个参数,十以上的参数需要使用大括号表示,比如第十个参数为9代表带一个到第九个参数,十以上的参数需要使用大括号表示,比如第十个参数为{10}

#!/bin/bash

read -p "请输入第一个参数:" num1
read -p "请输入第二个参数:" num2

sum=$[num1 + num2]
echo "sum的值为 $sum"

[root@localhost ~]# sh 2.3.sh
请输入第一个参数:20
请输入第二个参数:50
sum的值为 70
#!/bin/bash

echo "第一个位置变量的值为:$1 "
echo "第二个位置变量的值为:$2 "
echo "第三个位置变量的值为:$3 "
echo "第四个位置变量的值为:$4 "
echo "第五个位置变量的值为:$5 "
echo "第六个位置变量的值为:$6 "
echo "第七个位置变量的值为:$7 "
echo "第八个位置变量的值为:$8 "
echo "第九个位置变量的值为:$9 "
echo "第十个位置变量的值为:${10} "
echo "第十一个位置变量的值为:${11} "
echo "第十二位置变量的值为:${12} "

[root@localhost ~]# sh 2.1.sh 10  20  30  40  50  60  70  80  90  100   110  120
第一个位置变量的值为:10
第二个位置变量的值为:20
第三个位置变量的值为:30
第四个位置变量的值为:40
第五个位置变量的值为:50
第六个位置变量的值为:60
第七个位置变量的值为:70
第八个位置变量的值为:80
第九个位置变量的值为:90
第十个位置变量的值为:100
第十一个位置变量的值为:110
第十二位置变量的值为:120

预定义变量

$*``$@ 代表命令或脚本要出的参数

"$*":把所有参数看成以空格分隔的一个字符串整体(单字符串)返回,代表"11 2 $3".....

"$@":把各个参数加上双引号分割成N份参数列表,每个参数作为一个人字符串返回,代表"1""1" "2" "$3"....

#!/bin/bash

echo "未加双引号时....."
echo $*
echo $@
~

[root@localhost ~]# sh 3.1.sh   10  20  30
未加双引号时.....
10 20 30
10 20 30
#!/bin/bash

echo "未加双引号时....."
echo " $*"
echo  "$@"

echo "加双引号时....."
echo '$* 为'
for i in "$*"
do
 echo $i
done

echo '$@ 为'
for j in "$@"
do
 echo $j
done
[root@localhost ~]# sh 3.1.sh   10  20  30  40  50  60
未加双引号时.....
 10 20 30 40 50 60
10 20 30 40 50 60
加双引号时.....
$*10 20 30 40 50 60
$@10
20
30
40
50
60
$0:表示当前执行的脚本或命令的名称
$#:表示命令或脚本要处理的参数个数
#?:表示前一条命令或脚本执行后的返回状态码
返回值为0表示执行正确
返回值非0值为表示执行初夏异常
也常被用于shell脚本中retutn退出函数并返回的退出值

列子:

[root@localhost ~]# echo $?  //返回值为0表示执行正确
0
[root@localhost ~]# ls a111
ls: 无法访问a111: 没有那个文件或目录
[root@localhost ~]# echo $?   //返回值非0表示执行错误
2

总结

$0  脚本本身
$#  脚本后面根的所有参数个数
$*  $@   脚本后面跟的所有参数
"$*"  会把脚本后面跟的所有参数当做一个整体看待
"$@"  会把脚本后面跟的所有参数看作多个以空格分隔的个体

$? 返回上一条Linux命令或者脚本执行的结果,0位执行正常,非0值为执行异常
[root@localhost ~]# date
2022年 08月 28日 星期日 18:58:56 CST
[root@localhost ~]# date --help


[root@localhost ~]# date
2022年 08月 28日 星期日 19:04:49 CST
[root@localhost ~]# date +"%y/%m/%d"
22/08/28

给定的格式FORMAT 控制着输出,解释序列如下:

  %%    一个文字的 %
  %a    当前locale 的星期名缩写(例如: 日,代表星期日)
  %A    当前locale 的星期名全称 (如:星期日)
  %b    当前locale 的月名缩写 (如:一,代表一月)
  %B    当前locale 的月名全称 (如:一月)
  %c    当前locale 的日期和时间 (如:200533日 星期四 23:05:25)
  %C    世纪;比如 %Y,通常为省略当前年份的后两位数字(例如:20)
  %d    按月计的日期(例如:01)
  %D    按月计的日期;等于%m/%d/%y
  %e    按月计的日期,添加空格,等于%_d
  %F    完整日期格式,等价于 %Y-%m-%d
  %g    ISO-8601 格式年份的最后两位 (参见%G)
  %G    ISO-8601 格式年份 (参见%V),一般只和 %V 结合使用
  %h    等于%b
  %H    小时(00-23)
  %I    小时(00-12)
  %j    按年计的日期(001-366)
  %k   hour, space padded ( 0..23); same as %_H
  %l   hour, space padded ( 1..12); same as %_I
  %m   month (01..12)
  %M   minute (00..59)
  %n    换行
  %N    纳秒(000000000-999999999)
  %p    当前locale 下的"上午"或者"下午",未知时输出为空
  %P    与%p 类似,但是输出小写字母
  %r    当前locale 下的 12 小时时钟时间 (如:11:11:04 下午)
  %R    24 小时时间的时和分,等价于 %H:%M
  %s    自UTC 时间 1970-01-01 00:00:00 以来所经过的秒数
  %S    秒(00-60)
  %t    输出制表符 Tab
  %T    时间,等于%H:%M:%S
  %u    星期,1 代表星期一
  %U    一年中的第几周,以周日为每星期第一天(00-53)
  %V    ISO-8601 格式规范下的一年中第几周,以周一为每星期第一天(01-53)
  %w    一星期中的第几日(0-6),0 代表周一
  %W    一年中的第几周,以周一为每星期第一天(00-53)
  %x    当前locale 下的日期描述 (如:12/31/99)
  %X    当前locale 下的时间描述 (如:23:13:48)
  %y    年份最后两位数位 (00-99)
  %Y    年份
  %z +hhmm              数字时区(例如,-0400)
  %:z +hh:mm            数字时区(例如,-04:00)
  %::z +hh:mm:ss        数字时区(例如,-04:00:00)
  %:::z                 数字时区带有必要的精度 (例如,-04,+05:30)
  %Z                    按字母表排序的时区缩写 (例如,EDT)

[root@localhost ~]# date +"%y%m%d"
220828

前一天
[root@localhost ~]# date -d "-1 day"    +"%y%m%d"
220827

后一天
[root@localhost ~]# date -d "+1 day"    +"%y%m%d"
220829

下个月一号
[root@localhost ~]# date -d "next-month"    +"%y%m01"
220901

上个月一号
[root@localhost ~]# date -d "last- month"    +"%Y%m01"
20220701
[root@localhost ~]# date -d "-1 month"    +"%Y%m01"
20220701

一个星期后的日期
[root@localhost ~]# date -d "+1 week"    +"%Y%m%d"
20220904

两个星期以后的日期
[root@localhost ~]# date -d "+2 week"    +"%Y%m%d"
20220911