Shell 脚本的编写总结

Posted 码农飞哥

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了Shell 脚本的编写总结相关的知识,希望对你有一定的参考价值。

您好,我是码农飞哥,感谢您阅读本文,欢迎一键三连哦
💪🏻 1. Python基础专栏,基础知识一网打尽,9.9元买不了吃亏,买不了上当。 Python从入门到精通
❤️ 2. Python爬虫专栏,系统性的学习爬虫的知识点。9.9元买不了吃亏,买不了上当 。python爬虫入门进阶
❤️ 3. Ceph实战,从原理到实战应有尽有。 Ceph实战
❤️ 4. Java高并发编程入门,打卡学习Java高并发。 Java高并发编程入门
😁 5. 社区逛一逛,周周有福利,周周有惊喜。码农飞哥社区,飞跃计划

文章目录

1. 简介

这篇文章主要是为了记录一下Shell脚本的使用语法,前几天写了一个shell脚本,其中,也遇到了一些语法不清楚的情况,在此记录一下已备后续使用。

2. 什么是Shell脚本

Shell脚本(英语:Shell script)是一种电脑程序与文本文件,内容由一连串的shell命令组成,经由Unix Shell直译其内容后运作。被当成是一种脚本语言来设计,其运作方式与直译语言相当,由Uninx shell扮演命令行解释器的角色,在读取shell script之后,依次运行其中的shell命令,之后输出结果。利用Shell script可以进行系统管理、文件操作等。

2.1. 来个实例

创建一个名为demo1.sh的shell脚本文件,在该shell脚本中添加如下内容:

#!/bin/sh
cd ~
mkdir shell_tut
cd shell_tut
for((i=0;i<3;i++));do
  touch test_$i.txt
done

点击保存之后,在通过命令sh demo1.sh 来执行该脚本。即可达到我们预期的效果。

实例解析:

  1. 第1行:指定脚本解析器,这里是用/bin/sh 做解析器的。
  2. 第2行:切换到当前用户的home目录,因为我是用root用户登录的,所以我这边的用户目录是/root
  3. 第3行:创建一个目录shell_tut
  4. 第4行:切换到shell_tut目录
  5. 第5行:循环条件,一共循环10次
  6. 第6行:创建一个test_1....2.txt文件
  7. 第7行:循环体结束
    cd, mkdir, touch都是系统自带的程序,一般在/bin或者/usr/bin目录下。for, do, done是sh脚本语言的关键字。

3. 环境

shell编程跟java、php编程一样,只要有一个能编写代码的文本编辑器和一个能解释执行的脚本解释器就可以了。当前主流的操作系统都支持shell编程,本文所述的shell编程是指Linux下的shell,讲的基本都是POSIX标准下的功能,所以,也适用于Unix及BSD(如Mac OS)。

系统说明
LinuxLinux默认安装就带了shell解释器。
Mac OSMac OS 不仅带了sh、bash这两个最基础的解释器,还内置了ksh、csh、zsh等不常用的解释器
Windowswindows出厂时没有内置shell解释器,需要自行安装,为了同时能用grep, awk, curl等工具,最好装一个cygwin或者mingw来模拟linux环境。

4.脚本解释器

4.1. sh

即Bourne shell,POSIX(Portable Operating System Interface)标准的shell解释器,它的二进制文件路径通常是/bin/sh,由Bell Labs开发。

4.2. bash

Bash是Bourne shell,属GNU Project,二进制文件路径通常是/bin/bash。业界通常混用bash、sh、和shell

5. 第一个shell脚本

5.1. 编写

打开文件编辑器,新建一个文件,扩展名为sh(sh代表shell),在脚本前面一般会加上#!/bin/bash 或者#!/bin/sh 用于指定解释器。
输入一些代码,第一行一般是这样的:

#!/bin/sh
#!/bin/bash

#!是一个约定的标记,它告诉系统这个脚本需要什么解释器来执行。
需要注意的是编码格式是需要是Unix(LF) 下的UTF-8格式。

5.2. 运行

运行Shell脚本有两种方法:

  1. 第一种方法,sh 【shell脚本名称】
sh demo1.sh
  1. 第二种方法./【shell脚本名称】
chmod +x demo1.sh
./demo1.sh

需要注意的是,一定要写成./demo1.sh,而不是demo1.sh,运行其他二进制的程序也一样,直接写demo1.sh,Linux系统会去PATH里寻找有没有叫demo1.sh的,而只有/bin,/sbin,/usr/bin,/usr/sbin等在PATH里。你的当前目录通常不在PATH里,所以写成demo1.sh是会找不到命令的,要用./demo1.sh告诉系统说,就在当前目录找。

6. shell变量

6.1.定义变量

定义变量时,变量名不加美元符合,如:

project_path=/data/server/demo_project

注意,变量名和等号之间不能有空格,变量的命令需要遵循如下原则:

  1. 命名只能使用英文字母,数字和下划线,首个字符不能以数字开头。
  2. 中间不能有空格,可以使用下划线_。
  3. 不能使用标点符号。
  4. 不能使用bash里的关键字

6.2. 使用变量

使用定义的变量,只需要在变量名前面加美元符号即可,如:

project_path=/data/server/demo_project
echo $project_path
echo $project_path

变量名外面的花括号是可选的,加不加都行,加花括号是为了帮助解释器识别变量的边界,比如下面这种情况:

7. Shell 字符串

字符串是shell编程中最常用最有用的数据类型(除了数字和字符串,也没啥其它类型好用了),字符串可以用单引号,也可以用双引号,也可以不用引号。

7.1. 单引号

str='这是一个单纯的字符串'
echo $str

7.2. 双引号

name="码农飞哥"
echo "我的名字是$name"


双引号与单引号的区别在于,双引号里面可以有变量,而单引号里面添加变量无效,它只会原样输出单引号里的内容。

7.3. 获取字符串长度

string="abcd"
echo $#string   # 输出 4

提取子字符串
以下实例从字符串第 2 个字符开始截取 4 个字符:

7.4. 定义数组

在 Shell 中,用括号来表示数组,数组元素用"空格"符号分割开。定义数组的一般形式为:数组名=(值1 值2 ... 值n)

例如:

array_name=(
 "张三",
"李四",
"王五",
)
echo $array_name[1]

8. 运算符

8.1. 算术运算符

原生bash不支持简单的数学运算,但是可以通过其他命令来实现,例如 awk和expr,expr最常用,expr是一款表达式计算工具,使用它能完成表达式的求值操作。
例如,两个树相加(注意使用的是反引号**`,而不是单引号’**)
例如:

#!/bin/bash

val=`expr 2 + 2`
echo "两数之和为 : $val"

执行脚本,输出结果是:两数之和为 : 4
PS:需要注意的是:

  1. 表达式和运算符之间要用空格,例如2+2是不对的,必须写成 2 + 2,
    下表列出常用的算术运算符,假定变量a为10,变量b为10;
运算符说明举例
+加法val=expr $a + $b 结果为30
-减法val=expr $a - $b 结果为0
*乘法expr $a \\* $b 结果为 100
/除法expr $b / $a 结果为 1
%取余expr $b % $a 结果为 0
=赋值a=$b 把变量 b 的值赋给 a
==相等。用于比较两个数字,相同则返回 true。[ $a == $b ] 返回 true
!=不相等。用于比较两个数字,不相同则返回 true[ $a != $b ] 返回 false

注意:条件表达式要放在方括号之间,并且要有空格,例如: [ a = = a== a==b] 是错误的,必须写成 [ $a == $b ]。
实例:

#!/bin/bash
#author:码农飞哥
#url:https://feige.blog.csdn.net/
a=10
b=10

val=`expr $a + $b`
echo "a + b : $val"

val=`expr $a - $b`
echo "a - b : $val"

val=`expr $a \\* $b`
echo "a * b : $val"

val=`expr $b / $a`
echo "b / a : $val"

val=`expr $b % $a`
echo "b % a : $val"

if [ $a == $b ]
then
   echo "a 等于 b"
fi
if [ $a != $b ]
then
   echo "a 不等于 b"
fi

8.2 关系运算符

关系运算符只支持数字,不支持字符串,除非字符串的值是数字,下表 列出了常用的关系运算符,假定变量a为10,变量b为10

运算符说明举例
-eq检测两个数是否相等,相等返回true[ $a -eq $b ] 返回 true
-ne检测两个数是否不相等,不相等返回 true。$a -eq $b ] 返回 false
-gt检测左边的数是否大于右边的,如果是,则返回true[ $a -gt $b ] 返回 false
-lt检测左边的数是否小于右边,如果是,则返回true[ $a -gt $b ] 返回 false
-ge检测左边的数是否大于等于右边的,如果是,则返回 true。[ $a -ge $b ] 返回 true
-le检测左边的数是否小于等于右边的,如果是,则返回 true。[ $a -le $b ] 返回 true
实例:
#!/bin/bash
#author:码农飞哥
#url:https://feige.blog.csdn.net/
a=10
b=10

if [ $a -eq $b ]
then
 echo "$a -eq $b":"a 等于 b"
else
 echo "$a -eq $b":"a 不等于 b"
fi
if [ $a -ne $b  ]
then
 echo "$a -ne $b: a 不等于b"
else
 echo "$a -ne $b a 等于 b"
fi
if [ $a -gt $b ]
then
 echo "$a -gt $b: a 大于 b"
else
 echo "$a -gt $b: a 不大于 b"
fi
if [ $a -lt $b ]
then
   echo "$a -lt $b: a 小于 b"
else
   echo "$a -lt $b: a 不小于 b"
fi
if [ $a -ge $b ]
then
   echo "$a -ge $b: a 大于或等于 b"
else
   echo "$a -ge $b: a 小于 b"
fi
if [ $a -le $b ]
then
   echo "$a -le $b: a 小于或等于 b"
else
   echo "$a -le $b: a 大于 b"
fi

8.3 逻辑运算符

假设变量a为10,变量b为15;

运算符说明举例
&&逻辑的AND[[ $a -lt 100 && $b -gt 100 ]] 返回 false

实例:

a=10
b=15

if [[ $a -lt 100 && $b -gt 100 ]]
then
   echo "返回 true"
else
   echo "返回 false"
fi

if [[ $a -lt 100 || $b -gt 100 ]]
then
   echo "返回 true"
else
   echo "返回 false"
fi

8.4 字符串运算符

下表列出了常用的字符串运算符,假定变量a为"abc",变量b为"efg":

运算符说明举例
=检测两个字符串是否相等,相等返回true[ $a = $b ] 返回 false
!=检测两个字符串是否不相等,不相等返回 true[ $a != $b ] 返回 true
-z检测字符串长度是否为0,为0返回 true[ -z $a ] 返回 false
-n检测字符串长度是否不为 0,不为 0 返回 true。[ -n “$a” ] 返回 true。
$检测字符串是否不为空,不为空返回 true。[ $a ] 返回 true。
实例:
a="abc"
b="efg"

if [ $a = $b ]
then
   echo "$a = $b : a 等于 b"
else
   echo "$a = $b: a 不等于 b"
fi
if [ $a != $b ]
then
   echo "$a != $b : a 不等于 b"
else
   echo "$a != $b: a 等于 b"
fi
if [ -z $a ]
then
   echo "-z $a : 字符串长度为 0"
else
   echo "-z $a : 字符串长度不为 0"
fi
if [ -n "$a" ]
then
   echo "-n $a : 字符串长度不为 0"
else
   echo "-n $a : 字符串长度为 0"
fi
if [ $a ]
then
   echo "$a : 字符串不为空"
else
   echo "$a : 字符串为空"
fi

8.5 文件测试运算符

文件测试运算符用于检测 Unix 文件的各种属性。这里指定file为 /data/server/xiang/script/testscript/demo.sh

操作符说明举例
-d file检测文件是否是目录,如果是,则返回true[ -d $file ] 返回false
-f file检测文件是否是普通文件(既不是目录,也不是设备文件),如果是,则返回true[ -f $file ] 返 true
-r file检测文件是否可读,如果是,则返回true。[ -r $file ] 返回 true
-w file检测文件是否可写,如果是,则返回 true。[ -w $file ] 返回 true。
-s file检测文件是否为空(文件大小是否大于0),不为空返回 true。[ -s $file ] 返回 true
-e file检测文件(包括目录)是否存在,如果是,则返回 true。[ -e $file ] 返回 true
实例:
#!/bin/bash
file="/data/server/xiang/script/testscript/demo.sh"
ile="/var/www/runoob/test.sh"
if [ -r $file ]
then
   echo "文件可读"
else
   echo "文件不可读"
fi
if [ -w $file ]
then
   echo "文件可写"
else
   echo "文件不可写"
fi
if [ -f $file ]
then
   echo "文件为普通文件"
else
   echo "文件为特殊文件"
fi
if [ -d $file ]
then
   echo "文件是个目录"
else
   echo "文件不是个目录"
fi
if [ -s $file ]
then
   echo "文件不为空"
else
   echo "文件为空"
fi
if [ -e $file ]
then
   echo "文件存在"
else
   echo "文件不存在"
fi

9. shell echo命令

9.1. 显示普通字符

echo "这是一个普通字符"

9.2. 显示转义字符

echo "\\"这是一个转义字符 \\""

9.3. 显示变量

name="张三三"
echo "我的名字是$name"

9.4. 显示结果定向至文件

echo "我是一个测试文本">myfile

10. Shell流程控制

10.1 if fi

if 语句语法格式:

if condition
then
  command1
  ....
  commandN
fi

写成一行

if [ $(ps -ef|grep -c "nginx") -gt 1 ];then echo "true";fi

10.2 if else fi

if else fi 语法格式:

if condition
then
    command1 
    command2
    ...
    commandN
else
    command
fi

实例:

a=10
b=10

if [ $a -eq $b ]
then
 echo "$a -eq $b":"a 等于 b"
else
 echo "$a -eq $b":"a 不等于 b"
fi

10.3 if elif fi

if elif fi的语法结构是:

a=10
b=20
if [ $a -gt $b ]
then
 echo "a大于b"
elif [ $a -eq $b ]
then
  echo "a等于b"
elif [ $a -lt $b ]
then
  echo "a小于b"
else
  echo "没有符合的条件"
fi

11. for 循环

Shell支持for循环
for循环一般格式为:

for var in item1 item2 ... itemN
do
  command1
  command2
  ...
  commandN
done

写成一行

for var in item1 item2 ...  itemN; do command1;command2...done;

当变量值在列表里,for循环即执行一次所有命令,使用变量名获取列表中的当前取值。命令可为任何有效的shell命令和语句。in列表可以包含替换、字符串和文件名。
in列表示可选的,如果不用它,for循环使用命令行的位置参数。

for str in 我是 码农飞哥, 做一个 堂堂正正的中国人
do
   echo $str
done     


通过空格区分每一个item。

12. while循环

while循环用于不断执行一系列命令,也用于从输入文件中读取数据。其语法格式为;

while condition
do
   command
done

如果a小于等于6,a从1开始,每次循环都对a加1,运行上述脚本,返回数字1到6,然后终止。

a=1
while (( $a<=6 ))
do
  echo $a
  let "a++"
done

这里的判断条件需要用(()),运行脚本,输出:

break 命令
break 命令允许跳出所有循环(终止执行后面的所有循环)。

13. 获取服务器IP地址

如果通过shell命令获取服务器的IP地址呢?
我们都知道通过 ifconfig 来获取服务器的网络配置情况,但是当有多个网卡的情况下,如果获取某个网卡的IP地址呢?如下图所示:如何获取网卡eth0的IP地址呢?

命令有点点小复杂,如下所示:

current_ip=$(ifconfig eth0|grep inet|grep -v inet6|awk 'print $2')


命令解释:

  1. ifconfig eth0 用于查询eth0网卡
  2. grep inet 用于模糊查询inet开头的网络地址
  3. grep -v inet6 用于剔除掉inet6
  4. awk 'print $2' 用于打印第二个参数。

14. 交互式的命令

shell同样支持交互式命令,shell脚本可以接收我们控制台输入的文本。

echo -n "input 文件名 :"
read
echo "输入的文件名是:$REPLY"

15. 查看文件中是否存在某内容

查找文件中是否存在某内容,可以通过cat 命令进行查找,其中/dev/null 通常被用于丢弃不需要的输出流,或作为用于输入流的空文件,这些操作通常由重定向完成,任何你想丢弃的数据都可以写入其中
丢弃标准输出
在写shell脚本的时候,只想通过命令的结果执行后面的逻辑,而不想命令执行过程中有一大堆中间结果输出,这时候可以把命令执行过程中的输入全部写入 /dev/null

if cat name.txt|grep 李三三 >/dev/null
then
  echo "文本已经存在不再添加"
else
  echo "文本不存在进行添加"
sed -i '$a\\李三三' name.txt
fi

16. 对jar包进行解压&压缩

jar包是Java中一种可以直接运行的程序包,如果我们需要修改jar包中的某个文件的话,可以执行先执行解压命令

16.1 jar包解压

jar -xvf [jar包名称] [需要解压的文件的在jar中的相对路径]

比如需要修改app.jar包中的 application.yml 文件

jar -xvf  app.jar BOOT-INF/classes/application-prod.yml

这里的BOOT-INF/classes/application-prod.yml 是application.yml 文件在jar包中路径,注意不要写成绝对路径

16.2 将修改后的文件压缩进jar包中

可以通过sed命令对application.yml 进行修改,然后通过jar命令将修改后的application.yml 文件打进压缩包中

jar -uf [jar包名称] [需要打进压缩包中的文件]

还是以上面的app.jar包为例

jar -uf  app.jar BOOT-INF/classes/application-prod.yml

17. 判断文件或者目录是否存在

判断文件或者目录是否存在,不存在则创建,比如首先判断/data/server/train 目录是否存在,不存在则创建

if [ -e /data/server/train ];then
  echo '目录已经存在'
else
  echo '目录不存在'
  mkdir -p /data/server/train
fi

18. war包的解压与压缩

18.1 解压war包

unzip train.war -d train

将train.war的内容解压到train目录中

18.2 压缩war包

压缩war包需要注意的是需要进入到目标目录的里面,然后对里面的文件进行压缩,不要在目标目录压缩,不然在war中就会多一层目录。

cd train
jar -cvf coep-train.war *

总结

本文详细介绍了Shell脚本的一些基础命令,下文将主要介绍sed命令

以上是关于Shell 脚本的编写总结的主要内容,如果未能解决你的问题,请参考以下文章

计算机基础-shell操作总结

shell脚本学习总结

if 条件判断 和 判断总结---shell脚本

Shell脚本语言学习总结

系统管理中 bash shell 脚本常用方法总结

Linux下高效编写shell脚本的10个建议