Hexo

点滴积累 豁达处之

0%

shell 脚本知识

Shell脚本有点像早期的批处理文件,将一些命令汇总起来一次执行,但Shell有更强大的功能,可以类似于程序的编写,不需要编译就能执行,使用起来很方便,可以简化我们日常的管理工作

1 什么是shell

首先shell的英文含义是“壳”;

它是相对于内核来说的,因为它是建立在内核的基础上,面向于用户的一种表现形式,比如我们看到一个球,见到的是它的壳,而非核。

Linux中的shell,是指一个面向用户的命令接口,表现形式就是一个可以由用户录入的界面,这个界面也可以反馈运行信息;

形象的说Shell就是用户控制硬件的一种语言工具。

2 shell 脚本运行和调试

1 执行方式

  1. ./ 脚本名

     这是文件执行,需要有执行权限
  2. /bin/bash 脚本名

    如果shell脚本中第一行加入#!解释器,则自动忽略,仍然以bash作为shell,这是运用解释器处理文件,所以不需要给文件加执行权限

总之,上述的两种方法中真正执行永远的都是shell(默认为bash)

2 脚本调试

bash -n 脚本路径 语法检测

bash -vx 脚本路径 调试执行,把执行成功的结果显示,不成功的报错

3 shell 变量

1 局部变量

生效为仅为当前shell(即使子shell也不能)

1
2
3
4
A=123             B=$USER                C=$(hostname)
echo $A echo $B echo $C
echo "$A"456
echo ${A}456

set 命令查看所有局部变量

unset + 变量名 取消指定局部变量和环境变量

示例:

显示当前主机系统信息,包括主机名,IPv4地址,操作系统版本,内核版本,CPU型号,内存大小,硬 盘大小

1
2
3
4
5
6
7
#!/bin/bash
echo ipv4地址:$(ifconfig eth0 |tr "\n" " " |tr -s " " $ |cut -d$ -f7 |cut -d: -f2)
echo 系统版本:$(cat /etc/redhat-release)
echo 内核版本:$(uname -r)
echo 内存大小:$(cat /proc/meminfo |tr "\n" $ |cut -d$ -f1 |grep -o "[0-9]*") KB
echo 硬盘大小:$(fdisk -l |grep "sda\>" |cut -d: -f2 |cut -d, -f1)
echo CPU型号:$(cat /proc/cpuinfo |grep "name" |sort -u |cut -d: -f2)

编写脚本/root/bin/backup.sh,可实现将/etc/目录备份到/root/etcYYYY-mm-dd中(date +%F 以年-月-日显示日期)

1
2
#!/bin/bash
cp -r /etc/ /root/etc$(date +%F)

2 环境变量

当前shell和子shell生效

环境变量的声明:

1
2
export + 变量名       
declare -x 变量名

查看所有环境变量:

1
export , declare -x , env ,printenv

只读变量:

1
2
readonly 变量名  声明只读变量
readonly -p 查看所有只读变量

位置变量:

1
2
$1,$2,...  对应的1等,2等参数
set -- 清空所有位置变量

3 预定义变量

1
2
3
4
5
6
$?   上个命令的退出状态
$0 当前脚本的文件名
$* 传递给脚本或函数的所有参数(当做一个整体的字符)
$@ 传递给脚本或函数的所有参数(每个参数作为一个独立的字符)
$# 传递给脚本或函数的参数个数
$$ 当前Shell进程ID

示例:

1
2
3
4
5
6
vim test.sh        
echo $1
echo $2
echo $3
echo $#
/bin/bash ./test.sh 4 5 6 7

结果显示:4 5 6 4(7多余;共输入了4个参数)

4 $*$@的区别

都表示传递给函数或脚本的所有参数,但是当它们被双引号(“ “)包含时,$*会将所有的参数作为一个整体;$@会将各个参数分开

示例:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
写两个脚本实验$*,$@的区别:
vim b.sh
#!/bin/bash
echo '$@是' $1

vim a.sh
#!/bin/bash
echo '$*是' $*
/app/b.sh $@

chmod +x a.sh b.sh
./a.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

4 运算\判断

+、-、 *、 /、 %(取余)、 **(乘方)

实现算数运算方法:

名称 语法 范例
算术扩展 ((算术式)) 𝑟=((算术式))r=((1+2*3))
使用外部程序expr expr 算术式 r=expr 1+2\*3
使用[] [算术式] r=$[1+2]
使用内置命令 declare -i 变量=算术式 declare -i r=1+2*3
使用内置命令let let 算术式 let r=1+2

1 算术扩展(())

算术扩展的语法是:((表达式)),如果表达式中有变量,该变量之前最好不要加((表达式)),如果表达式中有变量,该变量之前最好不要加这个符号,以免变量不存在造成语法错误,例:

1
2
unset i
echo ((2+i))

双小括号”(())”数值运算实践

1
2
3
4
5
[root@shell-yankerp sh]# echo $((1+1)) #计算1+1后输出 
2 #那么结果就是等于2

[root@shell-yankerp sh]# echo $((6-3)) #计算6-3等于多少
3 #结果为3

综合算术运算

1
2
[root@shell-yankerp sh]# b=$((1+2**3-4%3)) #在这里b是一个变量 将变量名的计算结果赋值给b 
[root@shell-yankerp sh]# echo $b #输出如下:

特殊运算符号的运算实例

1
2
3
4
5
6
7
[root@shell-yankerp sh]# a=8    #首先a变量名 = 变量值 等于8 那么a就是8 
[root@shell-yankerp sh]# echo $((a=a+2)) #原来a=8 那么现在a+2 结果为10
10
[root@shell-yankerp sh]# echo $((a+=1)) #当结果为10 这一行代表 a=a+1那么就等于11
11
[root@shell-yankerp sh]# echo $((a**2)) #目前a=11 那么a**2 a的二次方 那么等于11x11=121 输出如下:
121

利用(())双括号,进行比较判断

1
2
3
4
5
6
[root@shell-yankerp sh]# echo $((2>1)) #当条件2>1正确后输出了1表示真 
1
[root@shell-yankerp sh]# echo $((2>3)) #当条件2>3错误后输出0
0
[root@shell-yankerp sh]# echo $((6==6)) #6==6 那么就输出1
1

2 expr

外部程序expr本来的作用,是在“标准输出”显示表达式的值。这个是外部程序,和Shell没有关系,所以移植性非常好,如果注重跨平台,那么可以在脚本本使用expr代替其他算术表达式。

expr 3 + 4

它会在屏幕上显示7,注意”+”两边有空格。

在使用expr时,要特别”表达式”中是否包含shell的特殊字符,如*、|、<、>、!、&、(、),要使用”"来转义。

r=expr 参数1 \|参数2

|代表”或”之意.如果”参数1“存在、非空、不是0,则传回”参数1“的值,否则传回”参数2”的值。

1
2
r=`expr 3 \| 0` r的值为3
r=`expr 0 \| 2` r的值为2

r=expr 参数1 \&参数2

如果”参数1”和”参数2”都存在、非空、不是0,则传回”参数1”的值,否则传回0.

1
r=`expr 3 \& 0` r的值为0

比较

1
2
r=`expr 1 \< 2`      是        1 
r=`expr 3 \<= 2` 否 0

加\减\乘\除\求余**

1
2
3
4
5
r=`expr 4 + 5` r的值为9
r=`expr 3 - 5` r的值为-2
r=`expr 3 \* 5` r的值为15
r=`expr 32 / 5` r的值为6(余数无条件舍去)
r=`expr 32 % 5` r的值为2

计算字符串长度

1
r=`expr length "hello"`  r的值为5

3 $[]做算术运算

使用[]做算术运算和[]做算术运算和(())类似

1
2
3
加:r=[4+5]𝑟的值为9减:𝑟=[4-5]    r的值为-1
乘:r=[4∗5]𝑟的值为20除:𝑟=[5/2] r的值为2
余数:r=[5[2**3] r的值为8

4 declare、let做算术运算

expr使用实例

1
2
3
4
5
6
7
8
[root@shell-yankerp sh]# i=5  #这里设置了一个变量 i=5 
[root@shell-yankerp sh]# expr $i + 6 &>/dev/null #那么我们使用expr命令 $i + 6 这里的6是一个整数
[root@shell-yankerp sh]# echo $? #执行完成后我们使用特殊变量 $?来判断以上命令
0 ---返回结果为0
[root@shell-yankerp sh]# expr $i + zhangsan &>/dev/null #同时这里又设置了一个变量 在这里的zhangsan是字符串
[root@shell-yankerp sh]# echo $? #使用特殊变量判断
2 #结果为2
[root@shell-yankerp sh]#

通过参数判断输出内容是否为整数

1
2
3
4
5
6
7
8
#!/bin/bash 
expr $1 + 1 &>/dev/null #这里是一个命令 使用了expr 也使用了特殊的位置变量
if [ "$?" -eq 0 ] #如果以上命令执行结果为0
then #那么
echo "输入的是整数~" #输出一条 输入的是整数
else #否则
echo "/bin/sh $# 请输入一个整数" 这里也使用了特殊的位置变量
fi

5 let做算术运算

1
2
3
4
5
6
7
8
9
[root@shell-yankerp ~]# a=2   
[root@shell-yankerp ~]# a=a+8 #没有用let
[root@shell-yankerp ~]# echo $a
a+8 #输出结果
[root@shell-yankerp ~]# unset a #清除变量
[root@shell-yankerp ~]# a=2
[root@shell-yankerp ~]# let a=a+8 使用let
[root@shell-yankerp ~]# echo $a
10

也可使用空格符让表达式可读性高一点,但这时必须使用引号包括表达式才行。
let “i = i + 5”

5 test和[ expression ]判断

1 test + expression

1
2
3
4
5
6
7
8
9
10
!=    判断两个字符不相等
> 判断两个字符大于
< 判断两个字符大于(按照ASCII码大小)
=~ 判断两个字符是否匹配 (常用于[[ ]]中,支持扩展正则表达式,两个字符最好用""括起来)
-eq 判断两个数值是否相等(equal)
-ne 判断两个数值不等(not equal)
-gt 判断两个数值大于(greater than)
-ge 判断两个数值大于等于(greater equal)
-lt 判断两个数值小于(less than)
-le 判断两个数值小于等于(less equal)

2 [ expression ]

注意:[ 后边的空格和 ] 前面的空格,必须要有

其实 [ 是一个命令,位于/usr/bin/目录下

1
2
3
4
5
-f    判断是否是普通文件
-d 判断是否是目录
-x 判断是否有执行权限
-z 判断字符是否为空
-n 判断字符是否为不空