文章目录
- Shell概述
- 脚本的常用执行方式
- Linux中的sh解释器
- Linux中的/etc
- 编写sh脚本
- 第一个sh脚本
- 变量
- 1. 系统预定义变量
- 2. 自定义变量
- 3. 变量定义规则
- 单引号和双引号的区别
- 4. 特殊变量
- 运算符
- 命令替换
- 条件判断
- 常用判断语句
- 流程控制
- if语句
- case语句
- while循环
- read读取控制台输入
- 函数
- 系统函数
- 1. basename
- 2. dirname
- 自定义函数
- Shell示例
Shell概述
Shell是一个命令行解释器,它接收应用程序/用户命令,然后调用操作系统内核。也就是说,它起到的是一个翻译的作用。
Shell还是一个功能强大的编程语言,易编写、调试,灵活性强。
脚本的常用执行方式
-
sh + 脚本路径
sh 脚本路径
-
bash + 脚本路径
bash 脚本路径
-
直接使用脚本的路径
脚本路径
但是这样可能会遇到一些问题:
终端显示:没有权限执行。我们详细看看这个脚本的权限:
根据我们的Linux基础知识可以发现,这个文件是没有”x“权限的,而”x“权限就是程序运行权限,因此,我们只需给这个文件加上运行权限即可:
chmod +x 脚本路径
注意事项:上面的1、2、3种执行Shell的方式,本质上都是打开了一个子Bash执行,当前的Bash不会受影响,除了source启动:
source 脚本路径
source是Bash内置的一个命令,效果等同于”.“。
Linux中的sh解释器
在一个Linux中有多个sh解释器,它们的名字存储在etc下的shells文件中,我们可以使用命令查看:
cat /etc/shells
我们可以看到类似以下的打印内容:
这其中的每一个都是一个解释器。
Linux中的/etc
在Linux系统中,/etc文件夹用于存储系统的配置文件和目录,它包含了多个应用程序和系统组件的配置文件,用于定义系统和软件的行为:
这个目录中的东西我们是不能随意修改的。
编写sh脚本
第一个sh脚本
按照惯例,我们每一门编程语言的第一个程序都是输出一行”hello world“,这里也不例外:
#!/bin/bash
echo hello world
看着这个代码,我们会发现并不陌生,因为代码的执行主体就是我们的echo命令,这是因为Linux的大部分命令(小部分命令可以直接与Linux系统内核进行沟通)本就是通过sh解释器进行了“翻译”之后才能够正常执行的。而我们的Shell编程也是使用sh解释器进行解释,即:Shell 编程是通过将多个 Linux 命令组合在一起来创建脚本或程序的过程。
除了echo指令外,还有一行代码:
#!/bin/bash
在Shell中,“#”是用作注释的符号,但这里是”#!“,它是hashbang或shebang的符号,用于指定脚本执行时使用的解释器。
在本例中,我们指定需要/bin/bash作为本脚本的解释器。这行代码不是必须的,如果我们没有使用hashbang来指定解释器,系统就会使用默认的sh解释器来解释该脚本。
变量
Shell中的变量可以分为两类:系统预定义变量和自定义变量。
Shell中的变量也有全局变量和局部变量之分。全局变量在所有Bash进程中都有效,局部变量仅在当前Bash进程中有效。
在子Bash中,对变量做任何更改都不会影响父Bash。
1. 系统预定义变量
- 常用系统变量:$HOME、$PWD、$SHELL、$USER等等。
- 使用set可以显示当前Shell中的所有变量,包括全局变量和局部变量
2. 自定义变量
- 基本语法:
注意:“=”前后不能有空格!变量名=值
- 撤销变量:
unset 变量名
- 声明静态变量(只读变量):
注意:静态变量不能unsetreadonly 变量名
- 将自定义变量导出为环境变量:
export 变量名
3. 变量定义规则
- 变量名称可以由字母、数字和下划线组成,但是不能能以数字开头,环境变量名建议大写
- 等号两侧不能有空格
- 在Bash中,变量默认类型都是字符串类型,无法直接进行数值运算
- 变量的值如果有空格,需要使用双引号或单引号包裹起来
单引号和双引号的区别
在Shell中,单引号和双引号有着不同的作用
- 双引号(“”):
- 双引号允许在字符串中使用变量,并会对变量进行扩展。比如,$var会被展开为对应变量的值
- 双引号内部可以使用转义字符,比如\n表示换行符,\"表示双引号本身
- 双引号内部的特殊字符会被解释和展开,比如命令替换($(command)或 `command)、参数替换($((expression))或$[expression]、$variable等)
- 双引号不会对特殊字符作为字面量值进行转义
- 单引号(‘’):
- 单引号将字符串视为字面量,不会对其中的内容作任何扩展或解释。内容会被原样输出
- 单引号适用于在字符串中包含特殊字符或避免变量扩展的场景
4. 特殊变量
- $n:n为数字,代表参数名称,$0为运行脚本时使用的脚本路径,0~99为运行脚本时传入的参数
- $#:获取输入参数的个数,常用于循环,判断参数的个数是否正确以及加强脚本的健壮性
- $*:它代表命令行中的所有参数,将所有的参数看作一个整体
- $@:也代表命令行中的所有参数,不同的是,它会将参数区分对待
- $?:表示最后一次执行的命令的返回状态,如果这个变量的值为0,证明上一个命令正确执行;如果这个变量非0(具体是哪个数,由执行的命令确定),则证明上一个命令执行不正确
运算符
在Shell中,我们不能直接进行数学运算:
# 计算1+2的值
echo $((1+2))
echo $[1+2]
这两种表达方式都是一样的,在Shell中,所有的数学计算都是这样,只需要注意包裹一下就好了,其他的跟别的语言没什么区别。
若是我们想使用运算对变量赋值,就不一样了,需要使用双引号包裹起来:
temp="$((1*5))"
echo $temp
命令替换
在Shell中,还有命令替换,跟上面说过的运算符有点像:
$()
其实命令替换运算符有很多种,这个只是其中一种,它更简洁、常用。
条件判断
条件判断就是一般编程语言中的if语句
test condition
[ condition ]
后者需要注意:condition前后需要有空格,并且条件非空即为true。
常用判断语句
-
两个整数之间的比较:
-eq 等于(equal) -ne 不等于(not equal) -lt 小于(less than) -le 小于等于(less equal) -gt 大于(greater than) -ge 大于等于(greater equal)
-
按照文件权限进行判断:
-r 有读权限(read) -w 有写权限(write) -x 有执行权限(execute)
-
按照文件类型进行判断:
-e 文件存在(existence) -f 文件存在并且是一个常规的文件(file) -d 文件存在并且是一个目录(directory)
流程控制
if语句
在Shell中,每种括号都是有用的,因此,Shell中不使用花括号包裹执行程序:
- 单分支:
if [ ] then 执行程序 fi
- 多分支:
if [ ] then 执行程序 elif then 执行程序 fi
需要注意:除了else,其他的语句之后都需要使用then。
case语句
跟其它编程语言一样,它是用于处理多分支语句的:
case $变量名 in
"值1")
如果符合这个,则执行这段程序
;; # 必须以两个分号结尾
"值2")
如果符合这个,则执行这段程序
;;
...
*)
如果都不符合,就执行这个
;;
esac
while循环
while [ condition ]
do
执行程序
done
read读取控制台输入
read是Linux内置的命令,而不是Shell提供的:
read (选项) (参数)
- 选项,这里我们讲两个最常用的选项:
- -p(prompt):指定读取值时的提示符
- -t(time):指定读取值时等待的时间(秒),若是不加-t,则会一直等待
- 参数:
- 变量:指定读取值的变量名
函数
函数也一样分为两种:系统函数和自定义函数。
系统函数
以下两个函数都是属于Linux系统提供的函数,在某些类Unix系统中可能也能使用。这两个函数本质上都是做的字符串操作。
1. basename
basename [string/pathname] suffix]
这个函数会删除所有前缀包括最后一个”/",然后将字符串显示出来;suffix是后缀,如果suffix被指定了,basename会将pathname或string中的suffix去掉。
2. dirname
dirname 文件绝对路径
会从给定的包含绝对路径的文件名中去除文件名(非目录部分),然后返回剩下的路径(目录部分)。
自定义函数
[ function ] funcname[()]
{
执行程序
[return int;]
}
调用这个函数的时候”()“中的参数列表可有可无,调用参数采用$1,$2等。
函数的返回值只能通过$?进行获取,return也是可有可无的,若是没有,将会以最后一条语句的执行情况作为返回值,return的数字也有要求:0~255。
Shell示例
接下来给出一个示例,涵盖了Shell编程中的所有知识点:
#! /bin/bash
# if语句
if [ $1="input" ]
then
echo "Hello Shell"
elif [ $1!="output" ]
then
echo exit
else
echo "Good bye"
fi
# while循环
temp=$2
while [ $temp -lt 10 ]
do
echo "whileing"
temp=$(($temp+1))
done
# case的使用
case $temp in
"10")
echo "while正常执行"
;;
*)
echo "while执行异常,temp=$temp"
;;
esac
# 使用read进行终端读取
read -p "请随便输入:" input
echo "input=$input"
# 当前文件名为
echo "当前文件名为:$(basename $0)"
# 更改文件后缀
echo "文件名更换为txt:$(basename $0 .sh).txt"
# 当前文件的路径为
echo "当前文件的路径为:$(dirname $0)"
# 编写一个函数
func(){
echo "函数func正在被调用"
echo "传入func的参数为:$1,即文件路径"
return 1;
}
# 调用这个函数
func "$0"
echo "函数的返回值为$?"