正如在讲解Linux常用命令《Linux入门系列5-新手必知的Linux命令》一文中提到的,Shell终端解释器是人机交互的桥梁,是用户与内核之间的翻译者。 作为用户与Linux系统内部通信的媒介,它为用户提供了一个接口系统级程序,向Linux内核发送请求以运行横向程序。 用户可以通过Shell来启动、暂停和停止程序。
1. Shell 脚本和编程概述
1.1 Shell不仅仅是一个终端解释器
事实上,Shell不仅仅是一个命令行解释器。 除了控制程序的启动、停止、挂起等操作外,它还是一种功能强大、易于编写、易于调试、高度灵活的编程语言。 *Shell是一种解释执行的脚本语言,可以调用Linux系统命令*。
除了支持各种变量和参数之外,Shell还提供了循环、分支等只有高级编程语言才有的控制功能。 要正确使用这些功能,准确发出命令尤为重要。 在讲解具体的编程语法之前,我们先来了解一下如何执行Shell脚本。
1.2 Shell 脚本如何工作
Shell 脚本命令有两种工作方式:*交互式和批处理*。
通过SHELL环境变量,可以查看当前系统默认使用的终端解释器。 默认情况下使用 Bash 解释器。
~~~[root@ ~]# echo $SHELL/bin/bash~~~
1.3 第一个Shell脚本
shell脚本中不仅用到了之前学过的Linux命令、管道字符、数据流重定向等语法规则,而且内部函数还需要进行模块化,通过逻辑语句进行处理,最终形成我们日常看到的shell脚本。
按照惯例,所有编程语言中的第一个程序都是Hello World。 我们使用Shell来编写一个简单的脚本。
~~~[root@test]# .txt test2.txt[root@test]# echo "hello world"hello world[root@test]# vi hello.sh
!/垃圾桶/:
回声“你好世界”~~~
保存并退出。 shell脚本文件可以有任何名称,但为了避免被误认为是普通文件,建议使用后缀.sh来表明它是脚本文件。
ps: 第一行#!/bin/bash是脚本声明,用于告诉系统使用哪个shell解释器来执行脚本。
第二行#:是注释信息,介绍脚本功能,方便以后维护。
第三行echo“hello world”是命令语句,可以是简单的Linux命令,也可以是各种逻辑语句和语法规则组合而成的复杂语句块。
Shell 编程格式就是这么简单。 我将其称为 Shell 编程的“三阶段格式”。 以后就可以按照这个格式来编写编码了。
1.4 执行Shell脚本
Linux中执行脚本有两种方式:*用解释器直接执行和通过脚本路径执行*。
语法:bash 或 sh 脚本名称
案例:执行之前创建的hello.sh脚本文件
~~~[root@test]# bash 你好。 world[root@test]# 你好。 世界~~~
语法:脚本的绝对或相对路径
案例:执行之前创建的hello.sh脚本文件
~~~[root@test]# /root/test/hello.sh-bash: /root/test/hello.sh: [root@test]# ./hello.sh-bash: ./hello.sh: ~ ~~
纳尼? 提示权限不足。 是的,你没看错,*如果通过路径运行,需要修改文件的执行权限*,(默认权限无法执行,数据中按tab键没有完成提示路径)文件权限相关命令将在后续文章中讲解。 这里只需按照以下命令添加脚本的可执行权限即可。
~~~[root@测试]# 12-rw-r--r--。 1 root root 4 Dec 1 09:48 hello.sh[root@ test]# chmod 777 hello.sh[root@ test]# 8 -. 1 root root 53 十二月 1 09:22 hello.sh~~~
再次执行。 这时,输入路径时按tab键,就会提示自动补全。
~~~[root@测试]# ./hello. world[root@test]# /root/test/hello. 世界~~~
2.Shell编程语法
掌握了Shell脚本的运行方式后,我们正式开始学习Shell编程语法。
学习任何语言都没有快速的方法,都离不开大量的练习。 只有打字多了,才能变得更熟练,理解得更深入。
2.1 变量
Linux Shell(这里默认bash)中的变量分为系统变量和用户定义变量。 系统变量包括$HOME、$PWD、$SHELL、$USER等。用户自定义变量是用户根据实际需要自定义的。 变量。
可以通过set命令查看Shell中的所有变量。
~~~[root@test]# =/bin/bash...省略部分内容~~~
下面主要演示自定义变量
2.1.1 定义变量
语法:
*变量名=值*
变量命名规则:
(1) 变量名可以由字母、数字和下划线注册,但不能以数字开头。
(2)等号两边不能有空格
(3)变量名一般采用大写字母
案件:
(1)变量的定义及使用
~~~[root@ test]# SRT=""[root@ test]# echo $[root@ test]# set |grep =[root@ test]# env |grep SRT[root@ test]#~~~
可以看到自定义变量SRT,可以通过set命令查询。
(2) 变量提升为全局环境变量
~~~[root@test]# SRT[root@test]# env |grep =~~~
上例中的自定义变量SRT是通过env命令查看的,但并没有在环境变量中查询。 将自定义变量SRT提升为环境变量后,可以通过env进行查询。
(3)取消变量
~~~[root@test]# 取消设置 SRT[root@test]# echo $SRT
[root@test]# set |grep SRT[root@test]# env |grep SRT~~~
要撤消变量,请使用 unset 命令。 撤消后,该变量将不再存在。
2.2 变量赋值
除了直接赋值之外,还可以将命令执行的结果赋值给变量。
语法:
*变量=`命令`或变量=$(命令)*
阐明:
命令用反引号或$()括起来,先执行命令,然后将命令执行结果赋值给变量。
案件:
~~~[root@test]# .sh test1.txt test2.txt[root@test]# =`ls`[root@test]# echo $.sh test1.txt test2.txt~~~
2.3 位置参数变量
位置参数变量主要用于获取脚本的参数值。 语法如下
案件:
输入2个参数,计算两个数之和并打印输出
~~~[root@test]# vi sum.sh
sum!/bin/bash 分别接收2个参数
num1=$1num2=$2
和
总和=$(($num1+$num2))
打印
回声 $sum~~~
保存退出,执行脚本并输入2个数字即可查看执行结果。
~~~[root@test]# bash sum.sh 1 23~~~
2.4 预定义变量
预定义变量有特殊功能,见下表
案件:
(1)查看当前进程和最后一个后台运行的进程
~~~[root@test]# vi mypid.sh
!/bin/bash 输出当前进程PID,即当前脚本运行时生成的PID。
echo "当前进程 PID=$" echo "最后一个后台进程 PID=$!"~~~
保存退出,执行脚本
~~~[root@test]# bash mypid.sh 当前进程 PID=7810 最后一个后台进程 PID=~~~
可以看到$和$!的区别,$代表当前进程PID,而$! 代表后台运行最多的进程的PID。
(2)输出当前进程PID并查看上一次命令执行结果
~~~[root@测试]# vi pid.sh
!/bin/bash 输出当前进程PID,即当前脚本运行时生成的PID。
echo "当前进程PID=$"
使用ls命令查找不存在的文件。 & 表示让命令在后台执行。
ls -l XXX.txt&echo "最后一个进程PID=$!"echo "最后一个命令执行结果:$?"~~~
保存退出,执行脚本
~~~[root@test]# bash pid.sh 当前进程 PID=7395 最后一个进程 PID=7396 最后命令执行结果: 0[root@test]# ls: XXX.txt: 没有这个文件或
[root@测试]#~~~
可以看到,该命令执行的进程与当前脚本运行的进程不是同一个进程,并且虽然xxx.txt文件不存在,但结果仍然返回0。如果改为搜索现有文件,毫无疑问,返回结果仍然是0。也就是说,无论命令执行成功与否,上面的脚本都会返回0。 原因是使用&让命令在后台执行实际上是打开了一个新进程,而$? 只能获取当前进程最后执行的命令的结果。 因此,判断命令是否执行成功时必须特别小心。
2.2 运算符和表达式
语法:
(1)*$((运算表达式)) 或 $[运算表达式]*
(2) expr m + n *注意expr运算符之间必须有空格*
案件:
(1)使用$(())将两个数字相加
~~~[root@测试]# S=$((2+3))[root@测试]# echo $S5~~~
(2) 使用$[]将两个数字相加
~~~[root@test]# SUM=$[2+3][root@test]# echo $SUM5~~~
(3)使用expr命令将两个数字相加
~~~[root@test]# S1=`expr 2 + 3`[root@test]# echo $S15~~~
注意,使用expr命令时,运算符之间必须有空格,否则不会进行计算,而是进行字符串拼接。 以下示例演示了空格和无空格之间的区别。 另外,需要使用乘号*,因为它与通配符冲突。 逃脱
~~~[root@测试]# expr 2 + 35[root@测试]# expr 2+32+3[root@测试]# expr 2*32*3[root@测试]# expr 2 * 36[root@测试]# expr 2 * 3expr: 错误~~~
(4)使用expr命令计算“2加3乘5的和”
~~~[root@test]# S2=`expr 2 + 3`[root@test]# echo $S25[root@test]# expr $S2 * 525~~~
注意运算符之间的空格。 以上是一步步计算,也可以直接一步计算。 对于多层嵌套,请注意需要转义反引号,如下:
~~~[root@ test]# expr `expr 2 + 3` * 525[root@ test]# echo `expr `expr 2 + 3` * 5`25~~~
2.3 条件判断语句
2.3.1 条件判断的基本使用
语法:[条件]
注意:条件前后必须有空格。 如果不为空,则返回true。 你可以使用 $? 验证(0:真,非0:假)
案件:
(1)分别判断变量存在与不存在,并检查返回值
~~~[root@测试]# [ $HOME ]
[root@测试]# echo $?
0[root@测试]# [ $TEST ]
[root@测试]# echo $?
1~~~
由于$HOME是肯定存在的环境变量,所以返回0,表示满足条件,变量不为空; 而TEST变量由于未定义而不存在,返回非0。
(2)条件判断语句用于逻辑判断
~~~[root@test]# [ $HOME ]&& echo ok || echo [root@test]# [ $TEST ]&& echo ok || 回声诺托克
诺克~~~
与其他语言中的三元运算符类似,如果满足条件,则执行紧随其后的语句,否则不执行。
2.3.2 常用判断条件
(1) 整数比较
~~~[root@test]# [ 1 -gt 2 ][root@test]# echo $?
1~~~
1不大于2,所以输出1,表示false
(2)文件类型判断
~~~[root@ test]# [ -f test1.txt ][root@ test]# echo $?0[root@ test]# [ -f xxxx.txt ]
[root@测试]# echo $?
1~~~
test1.txt文件存在,输出0表示true; xxxx.txt 文件不存在,因此输出 1 表示 false。
(3)文件权限判断
~~~[root@test]# ll-rw-r--r--。 1 root root 9 Nov 30 20:43 test1.txt[root@ test]# [ -x test1.txt ][root@ test] # echo $?1~~~
由于test1.txt没有执行权限,所以返回1,表示false。
2.4 过程控制语句
过程控制结构分为:顺序结构、分支结构、循环结构。 顺序结构按顺序执行语句,分支结构根据条件运行不同的分支,循环结构根据条件决定是否循环或执行。
2.4.1 分支语句
分支语句分为:if判断语句、case语句
语法:
***
if [判断条件]
然后
节目
菲
***
或者在判断条件后面写then,用逗号分隔,相当于上面的语句。
if [判断条件];then
节目
菲
***
if判断也可以多层嵌套,像这样:
if [判断条件1]
然后
程序1
elif【判断条件2】
然后
方案2
别的
程序3
菲
***
注意:条件判断语句中,请注意前面的括号和if之间必须有空格,括号前后必须有空格*
案件:
从键盘输入您的年龄,并根据您的年龄返回不同的描述语言。
~~~[root@test]# vim if.sh
!/bin/bash
read -p "请输入您的年龄:" AGEif [ $AGE -le 18 ]; “未成年”elif [ $AGE -le 30 ]; “年轻有活力”“坏老头”fi~~~
使用vim编辑器编辑内容(这里使用vim是因为vim比vi更适合在编程环境中使用,并且有错误提示等功能,建议编写脚本时使用vim),保存,退出并执行剧本
~~~[root@ test]# bash if.sh 请输入您的年龄:16岁未成年人 [root@ test]# bash if.sh 请输入您的年龄:40岁老人~~~
这里使用read命令读取键盘输入,-p参数表示显示提示内容。
语法:
***
案例$变量在
“值1”)
声明1
;;
“值2”)
声明2
;;
*)
声明
;;
埃萨克
***
案件:
根据脚本传入的参数,输出1、2、3对应的英文。
~~~[root@test]#vim case.sh
!/bin/bash
case $1 in1)回显一;;2)回显二;;3)回显三;;*)回显“错误”;;esac~~~
保存退出并执行
~~~[root@test]# bash case.sh 1one[root@test]# bash case.sh 2two[root@test]# bash case.sh [root@test]# bash case.sh ~~~
2.4.2 循环语句
循环语句分为:for循环、while循环
for循环有两种语法格式,如下:
语法一:
***
对于值 1 值 2 值 3 中的变量...
做
节目
完毕
***
语法2:
***
for ((初始值;循环控制条件;变量变化))
做
节目
完毕
***
案件:
(一)每天打招呼三遍
~~~[root@测试]#vim .sh
!/bin/bash
美好的时光就这样结束了~~~
保存退出,执行脚本并输出语句
~~~[root@测试]# bash . ~~~
(2) 使用for循环求1累加到5的和
~~~[root@测试]# vim .sh
!/bin/bash
总和=0for ((i=0;i