Shell

Shell

Shell概述

1.什么是Shell

Shell是一个命令解释器,它的作用是解释执行用户输入的命令及程序等,用户每输入一条命令,Shell就解释执行一条。这种从键盘一输入命令,就可以立即得到回应的对话方式,称为交互的方式。

2.Shell脚本
当命令或程序语句不在命令行下执行,而是通过一个程序文件来执行时,该程序就被称为Shell脚本。如果在Shell脚本里内置了很多条命令、语句及循环控制,然后将这些命令一次性执行完毕,这种通过文
件执行脚本的方式称为非交互的方式。

3.Shell的分类
Shell脚本语言是弱类型语言(无须定义变量的类型即可使用),在Unix/Linux中主要有两大类Shell:一
类是Bourne shell,另一类是C shell。

4.Shell脚本语言的优势
Shell脚本语言的优势在于处理偏操作系统底层的业务,例如:Linux系统内部的很多应用(有的是应用的一部分)都是使用Shell脚本语言开发的。
对于一些常见的系统脚本,使用Shell开发会更简单、更快速,例如:让软件一键自动化安装、优化,监控报警脚本,软件启动脚本,日志分析脚本等。

5.脚本开头
在执行bash脚本的时候,内核会根据“#! ”后的解释器来确定该用哪个程序解释这个脚本中的内容。

#!/bin/bash

6.Shell脚本的执行
Shell脚本是从上至下依次执行每一行的命令及语句的,即执行完了一个命令后再执行下一个,如果在Shell脚本中遇到子脚本(即脚本嵌套)时,就会先执行子脚本的内容,完成后再返回父脚本继续执行父脚本内后续的命令及语句。
通常情况下,在执行Shell脚本时,会向系统内核请求启动一个新的进程,以便在该进程中执行脚本的命令及子Shell脚本。

Shell脚本的执行通常可以采用以下几种方式。

bash script-name
`bash script-name或sh script-name:这是当脚本文件本身没有可执行权限(即文件权限属性x位
为-号)时常使用的方法,或者脚本文件开头没有指定解释器时需要使用的方法。`


./script-name
`path/script-name或 ./script-name:指在当前路径下执行脚本(脚本需要有执行权限),需要将
脚本文件的权限先改为可执行(即文件权限属性加x位),具体方法为chmod +x script-name。然
后通过脚本绝对路径或相对路径就可以直接执行脚本了。`

source script-name
source script-name或.script-name:这种方法通常是使用source或“.”(点号)读入或加载指定
的Shell脚本文件,然后,依次执行指定的Shell脚本文件san.sh中的所有语句。这些语句将在当前
父Shell脚本father.sh进程中运行(其他几种模式都会启动新的进程执行子脚本)

source或“.”命令的功能是:在当前Shell中执行source或“.”加载并执行的相关脚本文件中的命令及语句,而不是产生一个子Shell来执行文件中的命令。注意“.”和后面的脚本名之间要有空格。因此,使用source或“.”可以将自身脚本中的变量值或函数等的返回值传递到当前父Shell脚本father.sh中使用。这是它和其他几种方法最大的区别


`创建sh文件 `
[root@localhost ~]# cd /opt
[root@localhost opt]# mkdir scripts
[root@localhost opt]# cd scripts/
[root@localhost scripts]# vim hello.sh
#!/bin/bash
echo "hello world!"

`bash hello.sh`
[root@localhost scripts]# bash hello.sh 
hello world!

`./hello.sh`
[root@localhost scripts]# ./hello.sh
-bash: ./hello.sh: 权限不够
[root@localhost scripts]# ls -l
总用量 4
-rw-r--r--. 1 root root 33 7月   5 22:45 hello.sh

`添加执行权限`
[root@localhost scripts]# chmod +x hello.sh 
[root@localhost scripts]# ./hello.sh
hello world!

`直接输入 会被当作命令 命令没有写进文件`
[root@localhost scripts]# hello.sh
-bash: hello.sh: 未找到命令

`source  .  执行脚本`
[root@localhost scripts]# source hello.sh 
hello world!
[root@localhost scripts]# . hello.sh 
hello world!

`source  .  执行脚本会在当前shell进程执行 而上面两种会开辟一个子shell进程去执行脚本`

Shell变量

1.变量的基本概念
变量用于存储程序中使用的数据,所存储的数据存在于内存空间中,通过变量的名字就可以取出与变量
对应的数据,变量定义的语法:

变量名称=值

注意”=“的两侧无空格,否则变量名称会被识别为命令,变量的内容一般要加双引号,以防止出错,特别
是当值里的内容之间有空格时。默认情况下,在bash Shell中是不会区分变量类型的,例如:常见的变量类型为整数、字符串、小数等。这和其他强类型语言(例如:Java/C语言)是有区别的。
定义变量,并输入变量的值

a=5
echo $a #通过echo命令加上$即可输出变量的值

2. 子进程Shell与变量的可见性

`查看当前和终端相关的进程信息,可以看到只有一个“-bash”进程,此进程也是目前正在使用的bash 
shell进程。通过执行 bash命令可以基于当前的shell进程再开启一个新的bash shell进程,既子shell进程`
[root@localhost scripts]# ps -f
UID         PID   PPID  C STIME TTY          TIME CMD
root       1375   1371  0 7月05 pts/0   00:00:00 -bash
root       1598   1375  0 00:07 pts/0    00:00:00 ps -f

[root@localhost scripts]# bash

[root@localhost scripts]# ps -f
UID         PID   PPID  C STIME TTY          TIME CMD
root       1375   1371  0 7月05 pts/0   00:00:00 -bash
root       1600   1375  0 00:09 pts/0    00:00:00 bash
root       1612   1600  0 00:09 pts/0    00:00:00 ps -f
`可以看到bash进程的父进程(PPID)是 -bash 1375`

[root@localhost scripts]# exit
exit
[root@localhost scripts]# ps -f
UID         PID   PPID  C STIME TTY          TIME CMD
root       1375   1371  0 7月05 pts/0   00:00:00 -bash
root       1614   1375  0 00:14 pts/0    00:00:00 ps -f

`在子Shell中创建的变量上一级Shell是看不到的(显示空的),反之也一样`
[root@localhost scripts]# a=1
[root@localhost scripts]# echo $a
1
[root@localhost scripts]# bash
[root@localhost scripts]# echo $a

[root@localhost scripts]# b=2
[root@localhost scripts]# echo $b
2
[root@localhost scripts]# exit
exit
[root@localhost scripts]# echo $b

[root@localhost scripts]# 

`上节所述:`
`source  .  执行脚本会在当前shell进程执行 而上面两种会开辟一个子shell进程去执行脚本`

`继续测试`
`默认环境我们定义了变量a,我们再写一个.sh文件 让它直接echo $a 在不同shell环境下执行试试`
[root@localhost scripts]# vim a.sh
#!/bin/bash
echo $a
[root@localhost scripts]# ps -f
UID         PID   PPID  C STIME TTY          TIME CMD
root       1375   1371  0 7月05 pts/0   00:00:00 -bash
root       1654   1375  0 00:26 pts/0    00:00:00 ps -f
[root@localhost scripts]# echo $a
1
[root@localhost scripts]# bash a.sh 

[root@localhost scripts]# chmod +x a.sh 
[root@localhost scripts]# ./a.sh

[root@localhost scripts]# source a.sh 
1
[root@localhost scripts]# . a.sh 
1
[root@localhost scripts]# 

3.变量的类型
变量可分为两类:环境变量(全局变量)和普通变量(局部变量)。
环境变量也可称为全局变量,可以在创建它们的Shell及其派生出来的任意子进程Shell中使用,环境变量又可分为自定义环境变量和bash内置的环境变量。
普通变量也可称为局部变量,只能在创建它们的Shell函数或Shell脚本中使用。普通变量一般由开发者在开发脚本程序时创建。

4.环境变量
如何让局部变量(普通变量)变为环境变量呢?
在前面加export

环境变量一般是指用export内置命令导出的变量,用于定义Shell的运行环境,保证Shell命令的正确执行。
Shell通过环境变量来确定登录用户名、命令路径、终端类型、登录目录等,所有的环境变量都是系统全局变量,可用于所有子进程中,这包括编辑器、Shell脚本和各类应用。

5.系统环境变量

环境变量可以在命令行中设置和创建,但用户退出命令行时这些变量值就会丢失,因此,如果希望永久保存环境变量,可在以下位置配置:

  • 用户家目录下的.bash_profile或.bashrc(非用户登录模式特有,例如远程SSH)文件中
  • 全局配置/etc/bashrc(非用户登录模式特有,例如远程SSH)或/etc/profile文件中定义

在将环境变量放入上述的文件中后,每次用户登录时这些变量都将被初始化。
按照系统规范,所有环境变量的名字均采用大写形式。在将环境变量应用于用户进程程序之前,都应该用export命令导出定义,例如:正确的环境变量定义方法为

export FLAG=1

测试:

[root@localhost scripts]# ps -f
UID         PID   PPID  C STIME TTY          TIME CMD
root       1375   1371  0 7月05 pts/0   00:00:00 -bash
root       1776   1375  0 01:17 pts/0    00:00:00 ps -f
[root@localhost scripts]# export A=300
[root@localhost scripts]# echo $A
300
[root@localhost scripts]# bash
[root@localhost scripts]# echo $A
300

`查看环境变量`
[root@localhost ~]# env
XDG_SESSION_ID=2
HOSTNAME=localhost.localdomain
SELINUX_ROLE_REQUESTED=
TERM=xterm-256color
SHELL=/bin/bash
HISTSIZE=1000
SSH_CLIENT=192.168.70.1 60151 22
SELINUX_USE_CURRENT_RANGE=
SSH_TTY=/dev/pts/0
USER=root

`显示当前Shell中所有变量`
[root@localhost ~]# set

`如果想要设置环境变量,就要在给变量赋值之后或在设置变量时使用export命令,此处不要在变量名前面加$`
export A=100

A=100
export A

对于用户的环境变量设置,比较常见的是用户家目录下的.bashrc和.bash_profile。
全局环境变量的配置文件,一般放在/etc/bashrc,/etc/profile中

6.显示与取消环境变量

`通过echo打印环境变量,常见系统环境变量:`
	$HOME:用户登录时进入的目录。
	$UID:当前用户的UID(用户标识)
	$PWD:当前工作目录的绝对路径名
	$SHELL:当前SHELL。
	USER:当前用户
	
[root@localhost ~]# echo $HOME
/root

`用unset消除本地变量和环境变量`
echo $USER
unset USER #可以看到变量的内容显示为空。

7.普通变量

为普通变量的定义赋值,一般有以下3种写法:
 变量=value
 变量='value
 变量="value"
 
变量的内容可以用单引号或双引号引起来,也可不加引号,但是这三者的含义是不同的,运行如下脚本
#!/bin/bash
a=192.168.1.10-$a
b='192.168.1.10-$a'
c="192.168.1.10-$a"
echo "a=$a"
echo "b=$b"
echo "c=${c}"

[root@localhost scripts]# vim test.sh
`复制上面脚本内容`
[root@localhost scripts]# source test.sh 
a=192.168.1.10-
b=192.168.1.10-$a
c=192.168.1.10-192.168.1.10-

`我们可以发现`
不加引号时,值里有变量的会被解析后再输出
单引号,单引号里是什么就输出什么
双引号,输出变量内容时引号里的变量及命令会经过解析后再输出内容
==通常,数字内容的变量定义可以不加引号,其他没有特别要求的字符串等定义最好都加上双引号==

Shell变量进阶

1.将命令结果赋值给变量

变量=`ls`
变量=$(ls)

[root@localhost scripts]# a=`hostname`
[root@localhost scripts]# echo $a
localhost.localdomain

[root@localhost scripts]# a=$(pwd)
[root@localhost scripts]# echo $a
/opt/scripts

`在变量名前加$可以取得该变量的值,使用echo命令可以显示变量的值,$A和${A}的写法不同,但效果是一样的`
==当变量后面连接有其他字符的时候,必须给变量加上大括号{}==

[root@localhost scripts]# a='zhangsan'
[root@localhost scripts]# echo $a_xiaozhang

[root@localhost scripts]# echo ${a}_xiaozhang
zhangsan_xiaozhang

2.特殊变量

在Shell中存在一些特殊且重要的变量,例如:$0、$1、$#,我们称之为特殊位置参数变量。

$n

`要从命令行、函数或脚本执行等处传递参数时,就需要在Shell脚本中使用位置参数变量。`
[root@localhost scripts]# vim p.sh
[root@localhost scripts]# cat p.sh 
#!/bin/bash
echo $1
[root@localhost scripts]# bash p.sh 

[root@localhost scripts]# bash p.sh xuxu
xuxu

[root@localhost scripts]# vim p.sh 
[root@localhost scripts]# cat p.sh 
#!/bin/bash
echo $1 $2
[root@localhost scripts]# bash p.sh xuxu xuxuxu
xuxu xuxuxu

`在脚本中快速生成多个变量`
echo \${1..15} #相当于 echo $1 ... $15
	
[root@localhost scripts]# echo \${1..15}
$1 $2 $3 $4 $5 $6 $7 $8 $9 $10 $11 $12 $13 $14 $15
[root@localhost scripts]# echo \${1..15} > x.sh
[root@localhost scripts]# vim x.sh 
[root@localhost scripts]# cat x.sh 
echo $1 $2 $3 $4 $5 $6 $7 $8 $9 $10 $11 $12 $13 $14 $15
[root@localhost scripts]# bash x.sh zhangsan lisi wangwu
zhangsan lisi wangwu zhangsan0 zhangsan1 zhangsan2 zhangsan3 zhangsan4 zhangsan5
`当位置参数数字大于9时,需要用大括号将数字括起来,如:${10},否则会出现异常`

$0

$0的作用为取出执行脚本的名称(包括路径)

root@localhost scripts]# vim n.sh
[root@localhost /]# cat /opt/scripts/n.sh 
echo $0
[root@localhost scripts]# bash n.sh 
n.sh
[root@localhost scripts]# cd /
[root@localhost /]# bash /opt/scripts/n.sh 
/opt/scripts/n.sh

时如果希望单独获取名称或路径,则可用dirname及basename命令

dirname /opt/server/a.txt
basename /opt/server/a.txt

利用$0和上述命令(dirname、basename)分别取出脚本名称和脚本路径。

[root@localhost scripts]# vim n.sh 
[root@localhost /]# cat /opt/scripts/n.sh 
dirname $0
basename $0
[root@localhost scripts]# cd /
[root@localhost /]# bash /opt/scripts/n.sh 
/opt/scripts
n.sh

$#

通过$#获取脚本传参的个数

[root@localhost scripts]# vim q.sh 
[root@localhost scripts]# cat q.sh 
echo $1 $2 $3 $4 $5 $6 $7 $8 $9
echo $#
[root@localhost scripts]# bash q.sh {a..z}
a b c d e f g h i
26
`可以看到$#输出的26 因为传递的是a-z 26字母 打印的是前9个`

$* $@

利用set设置位置参数

表示清除所有的参数变量,重新设置后面的参数变量

[root@localhost scripts]# set -- zhangsan lisi wangwu
[root@localhost scripts]# echo $1
zhangsan
[root@localhost scripts]# echo $3
wangwu

[root@localhost scripts]# echo $*
zhangsan lisi wangwu
[root@localhost scripts]# echo $@
zhangsan lisi wangwu

测试$ *和$ @,注意,此时带有双引号:

[root@localhost scripts]# echo "$*"
zhangsan lisi wangwu
[root@localhost scripts]# echo "$@"
zhangsan lisi wangwu

`主要区别 $*会把所有参数当作一个整体`
[root@localhost scripts]# for i in "$*";do echo $i;done
zhangsan lisi wangwu
[root@localhost scripts]# for i in "$@";do echo $i;done
zhangsan
lisi
wangwu

$?

$?用于获取执行上一个指令的执行状态返回值,0表示成功,非0表示失败

[root@localhost scripts]# 
[root@localhost scripts]# pwd
/opt/scripts
[root@localhost scripts]# echo $?
0

3.内置变量命令

bash Shell包含一些内置命令。这些内置命令在目录列表里是看不见的,它们由Shell本身提供。常用的内部命令有:echo、eval、exec、export、read、shift。下面简单介绍几个最常用的内置命令的格式和功能。

eval

eval,当Shell程序执行到eval语句时,Shell读入参数args,并将它们组合成一个新的命令,然后执行

[root@localhost scripts]# vim noeval.sh
[root@localhost scripts]# cat noeval.sh 
echo \$$#
[root@localhost scripts]# bash noeval.sh a1 a2
$2
[root@localhost scripts]# vim noeval.sh 
[root@localhost scripts]# cat noeval.sh 
eval echo \$$#
[root@localhost scripts]# bash noeval.sh a1 a2
a2
`相当于echo $2`

Shell运算符与条件测试

1.算术运算符

算术运算符号均适用于常见的运算命令,常见算术运算命令如下

”(())”****数值运算

双小括号“(())”的作用是进行数值运算与数值比较

利用“(())”进行简单的数值计算

[root@localhost scripts]# a=1+1
[root@localhost scripts]# echo $a
1+1
[root@localhost scripts]# echo $((a))
2
[root@localhost scripts]# echo $((1+1))
2

利用“(())”双括号进行比较及判断

[root@localhost scripts]# echo $((1>2))
0
[root@localhost scripts]# echo $((1<2))
1

\((())可以用\)[]替代

[root@localhost scripts]# echo $((1+1))
2
[root@localhost scripts]# echo $[1+1]
2

let运算命令

[root@localhost scripts]# i=2
[root@localhost scripts]# i=i+8
[root@localhost scripts]# echo $i
i+8
[root@localhost scripts]# i=2
[root@localhost scripts]# let i=i+8
[root@localhost scripts]# echo $i
10

expr运算命令

[root@localhost scripts]# expr 2 + 2
4
[root@localhost scripts]# expr 2+2
2+2
[root@localhost scripts]# name=zhangsan
[root@localhost scripts]# expr length $name
8

awk实现计算

[root@localhost scripts]# echo "7.5 2.5" | awk '{print ($1-$2)}'
5

2.条件测试

通常,在bash的各种条件结构和流程控制结构中都要进行各种测试,然后根据测试结果执行不同的操作,有时也会与if等条件语句相结合,来完成测试判断,以减少程序运行的错误。

在bash编程里,条件测试常用的语法形式见表:

语法1中的test命令和语法2中的[]是等价的。语法3中的[[]]为扩展的test命令,语法4中的(())常用于计算
在[[]](双中括号)中可以使用通配符等进行模式匹配,这是其区别于其他几种语法格式的地方。
&&、||、>、<等操作符可以应用于[[]]中,但不能应用于[]中在[]中一般用-a、-o、-gt(用于整数)、-lt(用于整数)代替上述操作符
对于整数的关系运算,也可以使用Shell的算术运算符(())

test条件测试

test条件测试的语法格式为:

test <测试表达式>

[root@localhost ~]# test -f /tmp/xx.txt && echo 1 || echo 0
0
[root@localhost ~]#  [ -f /tmp/xx.txt ] && echo 1 || echo 0
0

&&、||、>、<等操作符可以应用于[[]]中,但不能应用于[]中

[root@localhost ~]# [[ 2 > 1 && 3 > 2 ]] && echo 1 || echo 0
1

在[]中一般用-a、-o、-gt(用于整数)、-lt(用于整数)代替上述操作符

[root@localhost ~]# [ 2 > 1 -a 3 > 2 ] && echo 1 || echo 0
1
[root@localhost ~]# [ 2 > 1 && 3 > 2 ] && echo 1 || echo 0
-bash: [: 缺少 `]'
0
[root@localhost ~]# [ 2 -gt 1 && 3 -lt^C ] && echo 1 || echo 2

文件测试表达式

这些操作符号对于[[]]、[]、test的测试表达式是通用的

字符串测试操作符

字符串测试操作符的作用包括:比较两个字符串是否相同、测试字符串的长度是否为零、字符串是否为NULL等

对于字符串的测试,一定要将字符串加双引号之后再进行比较
比较符号(例如=和!=)的两端一定要有空格

[root@localhost ~]# name=zhangsan
[root@localhost ~]# [ -n "$name" ] && echo 1 || echo 0
1
[root@localhost ~]# [ "abc" = "ab" ] && echo 1 || echo 0
0
[root@localhost ~]# [ "abc" == "ab" ] && echo 1 || echo 0
0

整数二元比较操作符

在书写测试表达式时,可以使用表中的整数二元比较操作符。

=”和“! =”也可在[]中做比较使用,但在[]中使用包含“>”和“<”的符号时,需要用反斜线转义,有时不转义虽然语法不会报错,但是结果可能会不对。
也可以在[[]]中使用包含“-gt”和“-lt”的符号,但是不建议这样使用。

[root@localhost ~]# [ 2 < 1 ] && echo 1 || echo 2
1
[root@localhost ~]# [ 2 -lt 1 ] && echo 1 || echo 2
2

二元数字在(())中的比较

[root@localhost ~]# ((2>1)) && echo 1 || echo 0
1
[root@localhost ~]# ((2==1)) && echo 1 || echo 0
0

逻辑操作符

测试表达式test、[]、[[]]、(())的区别总结

选择语句

1.if语句基本用法

单分支结构

[root@localhost scripts]# vim if-test.sh
#!/bin/bash
if [ "$1" -gt 10 ];then
        echo 1
else
        echo 0
fi
[root@localhost scripts]# bash if-test.sh 20
1

双分支结构

[root@localhost scripts]# vim if-test2.sh
if [ "$1" -gt 60 ];then
        echo 1
else
        echo 2
fi
[root@localhost scripts]# bash if-test2.sh 10
2
[root@localhost scripts]# bash if-test2.sh 100
1

多分支结构

[root@localhost scripts]# vim if-test3.sh
#!/bin/bash
if [ "$1" -gt 60 ];then
        echo 1
elif [ $1 -gt 35 ];then
        echo 2
elif [ $1 -gt 18 ];then
        echo 3
else
        echo 4
fi
[root@localhost scripts]# bash if-test3.sh 80
1
[root@localhost scripts]# bash if-test3.sh 40
2
[root@localhost scripts]# bash if-test3.sh 20
3
[root@localhost scripts]# bash if-test3.sh 10
4

2.read命令

Shell变量除了可以直接赋值或脚本传参外,还可以使用read命令从标准输入中获得

-p prompt:设置提示信息。

-t timeout:设置输入等待的时间,单位默认为秒。

[root@localhost scripts]# read -t 10 -p "enter a number" num
enter a number10
[root@localhost scripts]# echo $num
10
[root@localhost scripts]# bash if-test4.sh
input two number:10 20
10 < 20

3.case语句

支持正则

[root@localhost scripts]# vim case-test.sh
#!/bin/bash
read -p "input a number:" num
case "$num" in
        1)
                echo "the num is 1"
                ;;
        2)
                echo "the num is 2"
                ;;
        [3-9])
                echo "the num is $num"
                ;;
        *)
                echo "error"
esac
[root@localhost scripts]# bash case-test.sh 
input a number:5
the num is 5
[root@localhost scripts]# bash case-test.sh 
input a number:9
the num is 9
[root@localhost scripts]# bash case-test.sh 
input a number:10
error

循环语句

1.while循环语句

[root@localhost scripts]# vim while-test.sh
while true
do
        uptime
        sleep 3
done
[root@localhost scripts]# bash while-test.sh 
 17:44:12 up  2:10,  2 users,  load average: 0.00, 0.01, 0.05
 17:44:15 up  2:10,  2 users,  load average: 0.00, 0.01, 0.05

2.until循环语句

[root@localhost scripts]# vim until-test.sh 
#!/bin/bash
read -p "input a num:" a
until (( $a > 10 ))
do
        echo "num is $a"
        (( a++ ))
done
[root@localhost scripts]# bash until-test.sh 
input a num:8
num is 8
num is 9
num is 10

3.脚本后台运行

通过在脚本的结尾使用&符号来在后台运行脚本:

[root@localhost scripts]# vim while-test2.sh 
#!/bin/bash
while true
do
        uptime >> /tmp/log.txt
        sleep 3
done
[root@localhost scripts]# bash while-test2.sh &
[root@localhost scripts]# tail -f /tmp/log.txt 
 19:56:32 up  3:08,  2 users,  load average: 0.05, 0.03, 0.05
 19:56:35 up  3:08,  2 users,  load average: 0.05, 0.03, 0.05
 19:56:38 up  3:08,  2 users,  load average: 0.05, 0.03, 0.05

`调到前台`
[root@localhost scripts]# fg 1
bash while-test2.sh
^C
[root@localhost scripts]# fg 1
bash while-test2.sh
^Z
[1]+  已停止               bash while-test2.sh
`调到后台`
[root@localhost scripts]# bg 1
[1]+ bash while-test2.sh &
[root@localhost scripts]# jobs
[1]+  运行中               bash while-test2.sh &

4.for循环

第一种方式:
[root@localhost scripts]# vim for-test.sh
#!/bin/bash
for i in 1 2 3
do
        echo $i
done
[root@localhost scripts]# bash for-test.sh
1
2
3

第二种方式(C语言型for循环):
[root@localhost scripts]# vim for-test2.sh
#!/bin/bash
for (( i=1;i<=3;i++ ))
do
        echo $i
done
[root@localhost scripts]# bash for-test2.sh
1
2
3

Shell函数

1.Shell函数的概念

函数的作用就是将程序里多次被调用的相同代码组合起来(函数体),并为其取一个名字(即函数名),其他所有想重复调用这部分代码的地方都只需要调用这个名字就可以了。当需要修改这部分重复代码时,只需要改变函数体内的一份代码即可实现对所有调用的修改,也可以把函数独立地写到文件里,当需要调用函数时,再加载进来使用。inux系统里的近2000个命令可以说都是Shell的函数。

优势:
把相同的程序段定义成函数,可以减少整个程序的代码量,提升开发效率。
增加程序的可读性、易读性,提升管理效率。
可以实现程序功能模块化,使得程序具备通用性(可移植性)

function 函数名() {
 指令
 return n
}

`简化写法1:`
function 函数名 {
 指令
 return n
}

`简化写法2:`
函数名 {
 指令
 return n
}

2.执行与调用

Shell的函数分为最基本的函数和可以传参的函数两种,其执行方式分别说明如下。1)执行不带参数的函数时,直接输入函数名即可(注意不带小括号)。

执行Shell函数时,函数名前的function和函数后的小括号都不要带。
函数的定义必须在要执行的程序前面定义或加载。
Shell执行系统中各种程序的执行顺序为:系统别名→函数→系统命令→可执行文件。
函数执行时,会和调用它的脚本共用变量,也可以为函数设定局部变量及特殊位置参数。在Shell函数里面,return命令的功能与exit类似,return的作用是退出函数,而exit是退出脚本文件。return语句会返回一个退出值(即返回值)给调用函数的当前程序,而exit会返回一个退出值(即返回值)给执行程序的当前Shell。
如果将函数存放在独立的文件中,被脚本加载使用时,需要使用source或“.”来加载。
在函数内一般使用local定义局部变量,这些变量离开函数后就会消失。

[root@localhost scripts]# vim function-test.sh
function demo(){
        echo "hello world!"
}
demo
[root@localhost scripts]# bash function-test.sh 
hello world!
	
[root@localhost scripts]# vim function-test.sh
function demo(){
        echo "hello world!"
        return 100
}
demo
echo $?
[root@localhost scripts]# bash function-test.sh 
hello world!
100

`带参数的函数执行方法`
[root@localhost scripts]# vim function-test.sh
function demo(){
        echo "hello world!"
        echo $1 $2
}
demo zhangsan lisi
[root@localhost scripts]# bash function-test.sh 
hello world!
zhangsan lisi

[root@localhost scripts]# vim function-test.sh
function demo(){
        echo "hello world!"
        echo $1 $2
}
demo $1 $2
[root@localhost scripts]# bash function-test.sh zhangsan lisi
hello world!
zhangsan lisi

在一个function文件中调用另一个function

[root@localhost scripts]# vim function-test.sh
function demo(){
        echo "hello world!"
}
[root@localhost scripts]# vim function-test2.sh 
. ./function-test.sh
demo
[root@localhost scripts]# bash function-test2.sh 
hello world!

`可以在上述文件中加入一个文件是否存在判断`
[root@localhost scripts]# vim function-test2.sh 
if [ /opt/scripts/function-test.sh ];then
        . /opt/scripts/function-test.sh
        demo
fi
[root@localhost scripts]# bash function-test2.sh 
hello world!

`$?`
[root@localhost scripts]# vim function-test3.sh 
echo hello
exit 100
[root@localhost scripts]# bash function-test3.sh 
hello
[root@localhost scripts]# echo $?
100

[root@localhost scripts]# vim function-test3.sh 
function f1(){
        echo "f1"
        return 100
}
f1
echo $?
exit 200
[root@localhost scripts]# bash function-test3.sh 
f1
100
[root@localhost scripts]# echo $?
200

3.break、continue、exit、return的区别

break、continue在条件语句及循环语句(for、while等)中用于控制程序的走向;
exit则用于终止所有语句并退出当前脚本,除此之外,exit还可以返回上一次程序或命令的执行状态值给当前Shell;
return类似于exit,只不过return仅用于在函数内部返回函数执行的状态值。

监控Web和数据库的运行状态

1.概述

使用if条件语句针对Nginx Web服务或MySQL数据库服务是否正常进行检测,如果服务未启动,则启动相应的服务。监控Web服务和MySQL数据库服务是否异常的方法如下:

2.监测MySQL数据库异常

1.MySQL数据库环境准备

yum install mariadb-service mariadb -y
systemctl start mariadb

2.通过命令行检测数据库服务是否正常

netstat -tunlp | grep mysql | wc -l
yum install nmap -y

[root@localhost ~]# nmap 127.0.0.1 -p 3306 | grep open
3306/tcp open  mysql

3.开发监控MySQL数据库的脚本

[root@localhost ~]# systemctl stop mariadb
[root@localhost ~]# cd /opt/scripts
[root@localhost scripts]# vim mysql-test.sh
if [ `netstat -lntup|grep mysqld|wc -l` -gt 0 ]; then
 echo "MySQL is Running"
else
 echo "MySQL is Stopped"
 `systemctl start mariadb`
fi

[root@localhost scripts]# bash mysql-test.sh 
MySQL is stopped
[root@localhost scripts]# bash mysql-test.sh 
MySQL is running
[root@localhost scripts]# nmap 127.0.0.1 -p 3306 | grep open
3306/tcp open  mysql

3.监控Nginx Web服务异常

1.Nginx web服务环境准备

yum install nginx -y
systemctl start nginx

2.通过命令行检测Nginx服务是否正常,采用端口监控的方式

[root@localhost scripts]# netstat -tunlp | grep nginx
tcp        0      0 0.0.0.0:80              0.0.0.0:*               LISTEN      1948/nginx: master  
tcp6       0      0 :::80                   :::*                    LISTEN      1948/nginx: master  

在远端监控服务器本地端口

[root@localhost scripts]# nmap 127.0.0.1 -p 80 | grep open
80/tcp open  http

3.开发监控Nginx Web服务的脚本

[root@localhost scripts]# vim nginx-test.sh
if [ `netstat -tunlp | grep nginx | wc -l` -gt 0 ];then
        echo "Nginx is running"
else
        echo "Nginx is stopped"
        `systemctl start nginx`
fi
[root@localhost scripts]# bash nginx-test.sh 
Nginx is running
[root@localhost scripts]# systemctl stop nginx
[root@localhost scripts]# bash nginx-test.sh 
Nginx is stopped
[root@localhost scripts]# nmap 127.0.0.1 -p 80 | grep open
80/tcp open  http

文件内容主要参考:b站 刘老师教编程:5.Shell概述_哔哩哔哩_bilibili

posted @ 2023-07-06 23:49  FouroFour  阅读(168)  评论(0编辑  收藏  举报