Linux learning-Shell script

1. Basic concepts

机器语言:二进制的0和1的序列,称为机器指令
- 汇编语言:用一些符号来代替机器语言
- 计算机:只能运行二进制指令
- 机器代码文件:由0和1组成的二进制文件
- 编译:将编写好的程序文件通过一个工具(编译器)变成机器代码文件,然后在变成可执行文件。
#编译的特点:效率高
- 解释:将编写好的程序文件中的代码一行一行按顺序通过一个工具(解释器)解释为二进制指令。
#解释的特点:需要把源代码交给使用者
- 编程语言分类:低级语言和高级语言
#高级语言需要经过解释或编译才能转化为计算机能识别的语言
- 编程风格:面向对象和面向过程

静态语言和动态语言
- 静态语言使用变量前需要先定义变量的类型
- 动态语言不用定义变量的类型

强类型和弱类型语言:
- 强类型语言不同类型的数据运算需要经过强制转换
- 弱类型语言:会做隐式转换
shell属于弱类型、动态语言。所以shell变量申明的时候不需要指定变量类型,且不同类型格式进行计算的时候不需要进行强制转换。

2. Introduction to Shell Script

2.1 What is a shell script

1.当命令不在命令行中执行,而是从一个文件中执行时,该文件就是shell脚本。
	shell脚本是普通的文本文件,由流程控制逻辑(if   for  while等)和命令构成。
	shell脚本通常以.sh作为后缀名,但不是必须的。
2.Shell是一种解释型编程语言,不需要编译,执行时也是按行执行。
3.Shell脚本是由解释器解释执行的,常见的解释器有:
   bash dash ash  ksh  sh等
   注意,每种Shell解释器对shell的语法解释并不完全相同(sh和bash解析器对ll的解释就不同),但基本相同。
4. 脚本就是命令的堆砌
5. 脚本可以接受参数,也可以有变量,也可以有流程控制甚至还有函数 

2.2 Compilation, execution and debugging of shell scripts

1. Compilation: Use text editor vi or vim
2. Execution: Executable permission must be added to the script file before execution.
By adding execution permission, use the bash command to execute (support standard input and output)

chmod u+x script-file
bash script-file   或者  ./script-file

3. Debugging

bash -x -n -v script-file
  -n :只读取shell脚本,但不会去执行它,常用来测试脚本语法错误
  -x :进入跟踪模式,显示所执行的每一行命令,常用来调试脚本逻辑
  -v :   在执行script之前,先将script的内容输出到屏幕上

Example: Back up and clear the
log Back up the log directory under the variable file storage directory /var, delete the original file after the backup is successful

vim   backup-1.sh 
#声明使用的解析器
#!/bin/bash
#打包压缩/var/log1文件
tar -czvf  log1.tar.gz  /var/log1
#删除原文件
rm -rf /var/log1     
chmod u+x backup-1.sh
./backup-1.sh
ls    查看本目录 有压缩包
ls   /var/     发现没有log1

There are many disadvantages in this script:
1. The backup content cannot be dynamically specified
. 2. The name after backup cannot be specified arbitrarily
. 3. Even if the backup fails, the source file will be deleted

2.3 Variables in the shell

分类:
	自定义变量:
	内置变量:比如PATHHOSTNAMEPS1
shell变量按生效范围等标准划分:
	普通变量:生效范围只是当前的shell
	环境变量:当前shell以及shell的子进程
	本地变量:函数中
shell中变量的数据类型:
	字符型
	整型、浮点型
shell变量的定义规则:
	区分大小写
	内置变量和保留字不能用
	数字字母下划线(数字不能用作开头)(定义主机名的时候不能使用‘-’)
shell定义变量:
	变量名='值'(等号两边不能有空格) #如果值是字符串最好用引号括起来
#变量临时生效,推出shell后,变量自动删除。
#在Shell中所有的变量默认都是字符串型。也就是说,如果不手工指定变量的类型,那么所有的数值都是不能进行运算的	
shell查看和取消变量:
	查看所有变量: set命令
	取消指定的变量: unset 变量名
shell引用变量:
	$变量名或${变量名}
单引号、双引号、反引号的区别:
	双引号:属于弱引用,里面的变量会替换成对应的值
	单引号:强引用,里面是什么,显示的就是什么
	反引号:命令替换,将反引号内的Linux命令先执行	
shell中的位置变量:
位置变量是bash内置的变量,通过命令行将参数传递给shell脚本的对应参数
	$n       #表示指定位置的参数,比如$1表示的就是shell脚本第一个位置的参数值
	$0       #表示脚本文件的名称
	$*       #表示shell脚本所有的参数
	$#       #表示shell脚本参数的个数
shell脚本安全防范:
	set -e:如果其中一个命令错误,就中断执行
	#有时候会产生误杀,比如执行一条命令返回的状态码是非0
	set -u: 当一个变量没有定义的时候就退出。避免变量不存在出现的问题	

2.4 shell status code

Exit status code
After the process is executed, $? will be used to save the status code of the process. The value range of the status code is: 0–255

0 # means the execution is successful:
1-255 # means the execution failed (because there are many possibilities for execution failure, such as syntax error, command not found, etc., so the status code is different.)

custom exit status code

定义方法: exit [num]
#脚本中一旦遇到exit命令,脚本会立即终止;终止退出状态取决于exit命令后面的数字
#如果exit后面无数字,终止退出状态取决于exit命令前面命令执行结果
#如果没有exit命令,整个脚本的退出状态码取决于脚本中执行的最后一条命令的状态码

2.5 Shell scripts implement arithmetic and logical operations

2.5.1 Arithmetic operations in shell scripts

A method for implementing arithmetic operations in shell scripts;

let tool
bc tool (supports decimal operations)
expr tool
operation syntax

The operation syntax of the shell:

$[arithmetic expression]
$((arithmetic expression))

The use of shell arithmetic operation tools:

let工具:
let用于执行一个或多个表达式,变量计算中不需要加 $来表示变量
注意:这种方法需要借助一个变量,将计算后的值赋值给这个变量后进行输出
let a=1+1

The bc tool
supports standard input and output

echo 1+1 | bc

expr tool

expr 1 + 1 
#数值与运算符号之间需要用空格隔开
#使用expr命令进行乘法运算时,需要将”乘号”转义

Operation syntax

#$[算数表达式]:
echo $[10+1]
#$((算数表达式))
echo $((1+1))

Declare variables as integers for calculations

#直接将变量声明为”整数”,然后即可直接进行整数运算
declare -i a
a=1+1
echo $a

2.5.2 Logical operation of shell script

operator

with: &
or : |
not: !
Exclusive or: ^ (caret)
short circuit and &&: the front is true to execute the following
short circuit or ||: the front is true and the latter will not be executed

Result of a logical operation
The result of a logical operation is a Boolean value. true or false

true: 1 (binary), true
false: 0 (binary), false
Note: $? (exit status code) is 0, which means true, and non-zero means false

2.6 Shell's conditional test statement

2.6.1 test command

It is used to check whether a certain condition is true. It can test the value, character and file in three aspects.
The format of the test command

格式一:test 表达式
格式二: [ 表达式 ] (中括号的两边要有空格作为间隔)
格式三: [[ 表达式 ]] (且支持扩展正则表达式和通配符)

#注意:test和中括号等价
[root@centos8 ~]#help [
[: [ arg... ]
   Evaluate conditional expression.   
   This is a synonym for the "test" builtin, but the last argument must
   be a literal `]', to match the opening `['.

Use test to determine the permissions of the file

-r:是否存在读权限
-x:是否存在执行权限
-w:是否存在写权限
范例:判断一个文件是否存在读权限
test -r aa; echo $?[ -r aa ];echo $?
#若存在,退出状态码为0

file type judgment

-f:是否为文本文件
-d:是否为目录文件

File Status Judgment

-e:文件是否存在
-a:文件是否存在

String judgment:

-z STRING: 字符串是否为空,没定义或空为真,不空为假
= != > <:连个字符串是否相同、不同等。(这些符号两边要有空格)

compare numbers

-eq: equal,相等
-ne: not-equal,不等
-gt: greater-than,大于
-lt:less-than,小于

[[ expression ]] Usage

使用通配符的时候: ==!=
会把右侧的认为是通配符

使用正则表达式的时候: =~
会把右侧的认为是正则表达式(扩展正则表达式)

Combination condition test

将两个条件通过并且、或者连接起来
并且: -a
或者: -o

example:

#如果当前用户非root且该文件不存在就创建这个文件
[ $(whoami) != 'root' -a ! -e /data/dir ] && sudo mkdir /data/dir

2.6.2 read command

Accepts keyboard input and assigns it to a specified variable.

#若没有指定变量来接受read得到的数据,则默认赋值给内置的变量REPLY
#判断用户输入的是否为YES
#!/bin/bash
read -p 'continute?yes or no:'  ANSWER
[[ $ANSWER  =~  ^([yY][eE][sS])$ ]]  && echo "let's continue" || echo "stop"
#检查主机的网络状态

#!/bin/bash
read -p "please input IP:" IP
[[ "$IP" =~  ^[0-9]{
    
    1,3}\.[0-9]{
    
    1,3}\.[0-9]{
    
    1,3}\.[0-9]{
    
    1,3}$  ]] && echo "$IP is availabe"
ping -c 4 $IP > /dev/null && echo "$IP is Up " || echo "$IP is unreachable"
选项;
-p:指定提示的信息

2.6.3 () and {}

Function: Combine multiple commands together and execute them in batches
Format: (cmd; cmd2...) or { cmd, cmd2...} -- there must be a space on the left of the brackets

The difference between #() and {} batch execution commands:
use parentheses (), the commands executed inside will start the subprocess, and the braces will not
. Example:

#打印X的值
echo hello | read X; echo $X 
#输出的结果为空,因为使用管道的时候会在管道的两边开启子进程。而echo $x是在父进程执行的,子进程的X和父进程的X不是同一个东西

#解决方法: 确保read和echo在一个进程里面进行
echo hell | {
    
      read X; echo $X;}或echo hell | ( read X; echo $X;) #括号左边空格,最末尾的命令要加上分号。
#判断网络的状态
IP="x.x.x.x" #赋值的时候等号两边不能有空格   -c:指定ping的次数
ping -c 4 $IP &> /dev/null  && echo "$IP is up"  || echo "$IP is unreachable";
echo "scripts is finished"
exit
#磁盘空间的判断,判断某块磁盘的使用空间是否达到临界值

WARING=80 #设置一个临界值
SPACE_USE=`df|grep '^/dev/sd'|tr -s ' ' %|cut -d% -f5|sort -nr|head -1`
[ "$SPACE_USED" -ge $WARNING ] && echo "disk used is $SPACE_USED,will be full"

2.6.4 tr command

Role: character conversion and deletion

选项:
-d:delete
-s:squeeze-repeats
#范例:
转换:tr '123' 'abc' #把132转换成abc -- 一 一对应 1--a 2--b
删除: tr -d '需要删除的内容'
将多个连续的字符压缩或转换成一个指定字符:tr -s '' #把多个连续的空格压缩成一个空格(-s:把相同连续的字符合成一个)

2.6.5 cut command

Role: extract columns

选项:
-d -- 指定分隔符
-f -- 指定提取哪些列

2.6.6 head command

Function: display the first few lines of the file

选项:
-n:指定获取前x行

2.7 Flow control statement of shell script

Conditional selection
Conditional judgment
Loop statement

2.7.1 Shell's conditional selection statement

Single branch
Dual branch
Multi branch

single-branch format

if 判断条件;then
   执行的操作
fi

double-branch format

if 判断条件;then
   执行的操作
else
   执行的操作
fi

multi-branch

if 判断条件;then
   执行的操作
elif
   执行的操作
   ......
else
   执行的操作
fi

example:

#根据命令的退出状态来执行命令
#/bin/bash
read IP
if ping -c 2 $IP &> /dev/null;then
 	echo "$IP is up"
else
	echo "$IP is unreachable"
fi

2.7.2 Shell's conditional judgment statement

case 变量引用 in 
PAT1)
	执行相关操作
	;;
PAT2)
	执行相关操作
	;;
*)
	执行相关操作
	;;
esac

#case语句支持通配符
* 任意长度任意字符
? 任意单个字符
[] 指定范围内的任意单个字符
| 或者,如: a|b

example:

#判断输入的是yes还是no

#!/bin/bash
read -p 'do you agree(yes|no): ' input

case $input in
y|yes)
	echo 'You input is yes'
	;;
n|no)
	echo 'you input is no'
	;;
*)
	echo 'you input is other'
	;;
esac
#范例2

#!/bin/bash
cat <<EOF
请选择:
1)备份数据库
2)清理日志
3)软件升级
4)软件回滚
5)删库跑路
EOF

read -p '请输入上面的数字进行选择: ' NUM

case $NUM in 
1)
	echo '备份数据库'
	;;
2)
	echo '清理日志'
	;;
3)
	echo '软件升级'
	;;
4)
	echo '软件回滚'
	;;
5)
	echo '删库跑路'
	;;
*)
	echo '以上所有'
	;;
esac

2.7.3 Shell loop statement

for
while
until(不常用)

for loop format
Format 1:

for 变量 in 列表
do
	要做的操作
done
for列表的生成方式
	直接给出列表:1 2 3 4 5 ...
	整数列表:{
    
    start..end}$(seq [start [step]] end)
	通过$()命令替换得到列表

Format two:

for((表达式一;表达式二;表达式三));do
	要做的操作
done

example:

#使用for循环语句实现1+100
#!/bin/bash
sum=0
for num in `seq 100`;do   #列表1-100的表示方法; {1..100} seq 100
    let sum=$sum+$num  #let
done
echo $sum

#使用seq命令结合bc工具实现:
seq -s+ 100 | bc
-s:指定分隔符,默认分隔符是\n(换行)

#使用tr命令结合bc工具实现:
echo {
    
    1..100}|tr ' ' +|bc
#99乘法表的实现
#!/bin/bash

for i in {
    
    1..9};do
    for j in {
    
    1..9};do
	 if [ $i -ge $j ];then
 	   echo -e "$i * $j = $[i*j]\t\c"  #\c很关键
         fi
    done
    echo
done

#\t:一个制表位,实现对齐的功能 \n:换行符 \c:有了-e参数,我们也可以使用转义字符\c来强制 echo 命令不换行
#将指定目录下文件的所有后缀改名为 bak 后缀
#将/data/下面的所有文件该有bak后缀
#!/bin/bash
DIR="/data/"
cd $DIR  || {
    
     echo "cannot inner this dir";exit; }
for FILE in * ;do #找到/data目录里面的文件列表   *是通配符:表示所有
    PRE=`echo ${
     
     FILE} | grep -Eo ".*\."`  #去掉文件的后缀,如果没有后缀则不会匹配到
    sudo  mv ${FILE}  ${PRE}bakup #给去掉后缀的文件名加上后缀
done
#将目录YYYY-MM-DD/中所有文件,移动到YYYY-MM/DD/下  每天都会生成一个以当天日期为名字目录,里面存放一些文件。

# 1. 创建模拟的实验环境
#!/bin/bash
PDIR=/data/test
for i in {
    
    1..365};do 
 DIR=`date -d "-$i day" +%F` #-d:指定日期 -num:表示当前的前一天
 					#date -d "-1 year" +%F 表示以%F这种格式来显示当前日期的前一天 
 mkdir -pv $PDIR/$DIR #创建指定的文件
 cd $PDIR/$DIR
 for j in {
    
    1..10};do
 touch $RANDOM.log  #随机创建十个文件
 done
done

#将上面的目录移动到YYYY-MM/DD/下
#!/bin/bash
DIR=/data/test #总目录
cd $DIR || {
    
      echo "无法进入 $DIR";exit; }
for subdir in * ; do  #*表示总目录下面的每一个子目录的名称
	YYYY_MM=`echo $subdir | cut -d"-" -f1,2` #取年月
	DD=`echo $subdir | cut -d"-" -f3`  #取日
	[ -d $YYYY_MM/$DD ] || mkdir -p $YYYY_MM/$DD &> /dev/null #判断文件是否存在,不存在就创建一个
	mv $subdir/* $YYYY_MM/$DD #移动文件到新的文件夹下面去
done
rm -rf $/DIR/*-*-* #删除掉旧的文件

-----------------------------------------------------------------------
#date命令的使用
作用:显示和设置系统时间
选项:
-d <字符串> 显示字符串所指的日期与时间,比如:"-1 day" 表示当前日期的前一天,必须要加双引号
-s <字符串> 设置当前的时间和日期
#时间日期格式:
%T:time,显示时分秒,24小时制(hh:mm:ss)
%F:full date,显示年月日,%Y-%m-%d

#范例:
使用date设置年月日:
date -s "20220710"或date -s "YYYY-MM-DD" #时间设置成2022年7月10日0时0分
只设置时间,不改年月日
date -s "hh:mm:ss"
设置全部时间
date -s "YYYY-YY-DD HH:mm:ss"

hwclock命令实现时间校对
-s, --hctosys #以硬件时钟为准,校正系统时钟
-w, --systohc #以系统时钟为准,校正硬件时钟

while loop format

while 判断条件;do
      所作的操作
done

#循环控制条件;进入循环之前,先做一次判断;每一次循环之后会再次做判断;
#条件为“true”,则执行一次循环;直到条件测试状态为“false”终止循环
#while循环实现1+...100
#!/bin/bash
sum=0
i=1
while [ $i -le 100 ] ;do
  let sum=$sum+$i
  let i+=1
done
echo $sum
#分区利用率的监控
#!/bin/bash
WARING=80
while true ; do  #``:命令运行结果赋值给变量,不加``则把他作为字符串。$()可以直接嵌套
	USE=`df | sed -nr '/^\/dev\/sd/s#.* ([0-9]+)%.*#\1#p'` #使用sed获取分区利用率
	if [ $WARING -lt $USE ];then
	    echo "disk is will be full from `hostname -I`"
	else
	    echo "disk is so big from `hostname -I`" #主机ip地址
	fi
	sleep 2
done

Guess you like

Origin blog.csdn.net/weixin_44834205/article/details/128292018