文章目录
- Shell 快速入门笔记
- 1、Shell概述
- 2、Shell初体验
- 4、注释
- 5、变量
- 6、数据类型
- 6.1 字符串
- 6.2 数组
- 7、参数传递
- 8、运算符
- 9、常用命令
- 9.1 echo命令
- 9.2 printf命令
- 9.3 test命令
- 10、流程控制
- 10.1 条件判断
- 10.2 循环
- 11、函数
- 12、输入/输出重定向
- 12.0 前置知识
- 12.1 输出重定向
- 12.2 输入重定向
- 13、文件包含
Shell 快速入门笔记
1、Shell概述
-
Shell是什么?
在Linux中,Shell是一种命令行界面(CLI),用于与操作系统交互和运行各种命令和程序。Linux操作系统支持多种不同的Shell,每种Shell都有自己的特点和功能。
个人理解:在Linux中,Shell是一种C语言编写的程序,类似于其它编程语言,它是解释执行的,是连接用户和操作系统的桥梁
-
Shell在计算机中所处的位置:
-
Shell能干什么?
Shell是一种脚本语言,所以一般讨论Shell的作用,都是说Shell编写的程序,即Shell脚本的作用
- 自动化任务:Shell脚本可以用于执行一系列操作和命令,从而自动化一些任务。例如,你可以编写一个Shell脚本来备份你的文件系统,定时运行这个脚本,以确保你的数据得到保护。
- 批量处理数据:Shell脚本可以用于处理大量的数据。例如,你可以编写一个Shell脚本来查找一个文件夹中所有的文本文件,并将它们转换为另一种格式。
- 系统管理:Shell脚本可以用于管理系统的各个方面,例如安装软件包、创建用户和设置权限等。
- 任务调度:Shell脚本可以用于创建和管理计划任务,例如定期执行系统备份或日志清理等。
- 监控和管理进程:Shell脚本可以用于监控和管理进程,例如启动、停止或重启进程,或者检查进程是否在运行等。
-
Linux中Shell有哪些?
- Bourne Shell(/bin/sh):最早的Unix shell,由Stephen Bourne开发,也称为sh。它是现代Unix shell的基础,可以在几乎所有的Unix和Linux系统上找到。
- C Shell(/bin/csh):由Bill Joy开发,也称为csh。它是一种基于C语言的shell,具有交互式命令行编辑和命令历史记录等特性。在许多Linux系统中,可以通过安装csh软件包来使用它。
- Korn Shell(/bin/ksh):由David Korn开发,也称为ksh。它是Bourne Shell的扩展,提供了更多的功能和命令,如命令行编辑、作业控制、数组等。它在Solaris和AIX等Unix系统中广泛使用。
- Bourne-Again Shell(/bin/bash):由Brian Fox和Chet Ramey开发,也称为bash。它是Bourne Shell的扩展,添加了许多新特性,如命令行编辑、自动补全、历史命令等。它是Linux系统默认的shell。
- Z Shell(/bin/zsh):由Paul Falstad开发,也称为zsh。它是一种功能强大的shell,具有高级的命令行编辑和自动补全、路径展开等特性。它通常在Mac OS X和一些Linux系统中使用。
除了上述这些主要的shell,还有其他一些不太常用的shell,如fish(Friendly Interactive Shell)、rc shell、es shell等
-
Shell脚本是什么?
Shell 脚本(shell script),是一种为 shell 编写的脚本程序。
备注:业界所说的 shell 通常都是指 shell 脚本,但读者朋友要知道,shell 和 shell script 是两个不同的概念。
2、Shell初体验
按照惯例😄,我们在学习一门新的语言时,都先学会如何打印"Hello World!",现在就让我们来学习如何使用Shell打印一个”Hello World!“吧(●’◡’●)
-
Shell脚本运行所需要的东西:
shell编辑器+shell解释器
shell编辑器一般用的是vi\vim,shell解释器一般用的是bash解释器。
-
运行一个Shell脚本的主要步骤:
-
Step1:编写Shell
1)创建一个新的文本文件,通常使用
.sh
作为文件扩展名# 在当前目录创建一个名为 hello.sh的文件 vim hello.sh
2)编码
#!/bin/bash echo "Hello World !"
第一行:指定一个Shell解释器,这里使用的是bash解释器
第二行:使用Shell提供的指令,编写一个Shell程序
3)保存退出:按下
ESC
,从输入模式进入命令模式,然后按下:
进入编辑模式,然后输入wq
回车 -
Step2:运行Shell,运行Shell脚本的方式有很多种,这里演示一些常见的方式
前面我们shell脚本的路径是:/home/ghp/hello.sh
-
方式一:
绝对路径/相对路径
绝对路径:
chmod +x hello.sh ./home/ghp/hello.sh
相对路径:
chmod +x hello.sh ./hello.sh
备注:新建的文件默认是没有执行(
x
)权限的,需要赋值 -
方式二:
sh/bash
# sh方式 sh hello.sh # bash方式 bash hello.sh
这种方式的特点:使用这种方式不需要给文件设置执行权限,但是会导致shell脚本可能不是由我们指定的shell解释器执行,
比如,我们使用
#!
指定的是 bash 解释器,但是我们使用sh hello.sh
运行,此时执行该脚本的shell解释器就不是我们指定的 bash 解释器,而变成了 sh 解释器。所以使用这种方式,在编写Shell脚本时可以直接不指定 shell 解释器sh和bash的区别和联系:
/bin/sh
是早期版本,是一种便携方式的解释性脚本语言,自带有posix便携式功能,以该方式声明的脚本,脚本中间发生错误会终止脚本的运行,不再运行下面的代码。/bin/bash
,是/bin/sh的升级版,默认没有开启posix便携模式,所以以 /bin/bash 声明的脚本,中间即使发生错误,依然会继续向下运行。可以简单的理解:
/bin/sh
等价于/bin/bash --posix
注意:现在Linux(2.6.18)中,sh已经被bash整合了,我们使用的 sh 其实是 bash 的软链接,sh 就是 bash --posix,可以使用
man sh
和man bash
测试当前系统 sh 是否已经被bash整合了 -
方式三:
./source
# . 方式 . hello.sh # source 方式 source hello.sh
备注:需要给文件赋予执行(x)权限。./source 都是继承 /bin/bash 的权限,和 bash 方式不同的是,它不会开启一个子shell线程,而是直接在当前shell进程下执行的,因为他们是内建命令,所以脚本中赋值的本地变量也会影响当前shell的,用的时候一定要注意(尽量使用前面的3种方式),一般方式三都是用于执行配置文件
总结:
- 方式一需要Shell脚本有可执行权限,方式二和方式三不需要
- 方式一和方式二在脚本执行时,会开启一个子shell环境,在子shell执行完成后,子shell环境随即关闭,然后又回到当前shell中;而方式三不会开启子shell,而是直接在当前shell线程中进行执行脚本
-
-
4、注释
-
注释的定义:注释是在Shell脚本中用来标识代码的解释或说明的一种特殊文本。在执行Shell脚本时,注释会被忽略,不会对程序的执行造成任何影响。
注意:shell脚本的第一行的
#!
注释是有作用的,它指定了使用哪一个shell解释器去执行这个脚本(但如何使用bash/sh去执行脚本就不一定就是这个解释器去执行) -
注释的作用:
- 提高代码的可读性和可维护性。通过注释,程序员可以更加清晰地了解代码的意图和实现方法,从而更方便地进行代码的修改和调试。
- 方便代码的协作和共享。注释可以帮助其他程序员更好地理解和使用自己的代码,减少因为代码不明确而导致的沟通障碍和误解。
-
注释的分类:
- 行注释(Line Comments):行注释是在一行代码的末尾加上一段注释,通常使用“
#
”符号来表示。行注释只对当前行有效,不会影响后续代码的执行。 - 块注释(Block Comments):块注释是在多行代码中间加上一段注释,通常使用“
:<<
”和“:
”符号来表示。块注释可以跨越多行,但必须以“:
”符号结束。 - 文档注释(Document Comments):文档注释是用来描述代码整体的一种注释,通常放置在代码的开头。文档注释可以使用特定的标记和格式,如“
/**
”和“*/
”符号,以方便生成文档或注释。
示例:
行注释: # 注释内容 块注释(下面的EOF可以替换称其它字符,比如END、!、?...) :<<EOF 注释内容 注释内容 注释内容 EOF
文档注释: #!/bin/bash # # Script name: backup.sh # # Description: # This script is used to backup files from a source directory to a destination directory. # # Usage: # ./backup.sh <source directory> <destination directory> # # Options: # -v : verbose output # # Return values: # 0 : success # 1 : error # # Examples: # ./backup.sh /home/user /mnt/backup # ./backup.sh -v /home/user /mnt/backup # # Script code goes here...
- 行注释(Line Comments):行注释是在一行代码的末尾加上一段注释,通常使用“
-
注释应当遵循以下规范
- 注释应该简洁明了,不要过度注释,也不要遗漏重要的注释信息。注释应该突出代码中最重要、最难理解、最易出错的部分,对这些部分进行详细的解释和说明。
- 注释应该使用简单、易懂的语言,避免使用专业术语和难懂的缩写。注释应该能够被任何人理解,包括不具备编程背景的人。
- 注释应该与代码保持一致,注释应该与代码在格式、缩进、注释位置等方面保持一致。注释应该尽量放在代码的上方或右侧,而不是在代码中间或下方。
- 注释应该避免错误和歧义,注释应该准确地反映代码的意图和行为,避免产生歧义和误解。注释应该在代码更新或修改后及时更新,以保证注释与代码的一致性。
- 注释应该按照一定的规范和格式进行编写,例如使用特定的注释符号、排版方式、注释级别等。在项目中,应该制定一份注释规范和标准,对注释的格式、内容、使用方法等进行明确规定,以保证注释的一致性和可读性。
5、变量
-
变量的命名规则:
-
命名只能使用英文字母,数字和下划线
_
,首个字符不能以数字开头 -
不能使用标点符号或空格
-
不能使用 Shell 中的关键字
-
变量名和等号之间不能有空格
以上这四点是硬性要求,不按上诉规会直接报错,而对于常量或者环境变量的命名一般我们都需要使用全大写字母,每个单词之间使用
_
分隔(PS:这只是规范,不是规则) -
-
Shell中常见的变量
- 环境变量(Environment Variables):环境变量是Shell进程中的全局变量,可以由Shell启动时设置,也可以在运行时使用export命令设置。常见的环境变量包括PATH、HOME、USER等。
- 用户定义变量(User-Defined Variables):用户定义变量是Shell脚本中自己定义的变量,可以存储任何类型的数据。变量名通常由字母、数字和下划线组成,但不能以数字开头。
- 位置参数变量(Positional Parameters):位置参数变量是指Shell脚本中传递给脚本的参数。
$0
表示脚本本身,$1
、$2
、$3
…分别表示第一个、第二个、第三个参数,以此类推。 - 特殊变量(Special Variables):特殊变量是Shell中预定义的一些特殊变量,具有特殊的含义。例如,
$?
表示上一个命令的返回值,$$
表示当前Shell进程的进程号。 - 只读变量(Read-Only Variables):只读变量是指Shell中不能修改其值的变量,通常用来保存Shell脚本的一些固定值。例如,
$RANDOM
表示一个随机数,$BASH_VERSION
表示当前Shell的版本号等。我们可以通过readonly
关键字来定义只读变量 - 数组变量(Array Variables):数组变量是一种特殊的变量,可以在一个变量中存储多个值。在Shell中,可以使用下标来访问和修改其中的元素
主要分为三大类
- 自定义变量(局部变量):一般是指开发者在Shell脚本中定义的变量,这些变量仅在当前Shell示例中有效,其它Shell示例无法访问,属于局部变量
- Linux中已定义的环境变量(环境变量):所有的程序,包括Shell启动的程序,都能访问环境变量(比如PATH、HOME……),有些程序需要环境变量来保证其正常运行(必要的时Shell脚本也可以定义环境变量)
- Shell中的预定义变量(Shell变量):Shell变量是由shell程序设置的特殊变量。Shell变量中有一部分是环境变量,有一部分是局部变量,这些变量保证了shell的正常运行
-
常用操作
-
查看环境变量
-
set
:显示当前shell中自定义的变量,包括用户的环境变量,按变量名称排序。仅在当前Shell有效,可以显示Shell的自定义的变量备注:直接 set 是查看当前系统中的所有环境变量,这个输出比较多,一般我们可以搭配
管道符+grep
命令进行筛选Linux的
declare
命令不加参数和set的作用类似
env
:查看所有环境变量,也可以设置环境变量。仅在当前会话中有效,可以显示和设置用户环境变量(Linux中定义的环境变量),用法和set类似export
:显示当前导出成用户变量的shell变量(当一个变量被导出时,它将成为子进程的环境变量,这意味着子进程可以访问该变量),并显示变量的属性(是否只读),按变量名称排序,用法和set类似
set和env都是用来查询环境变量,而export是用来查询导出称用户变量的Shell变量;set作用范围要大于env,set能够查询到env不能查询到的Shell中自定义的变量。以上就是三者之间的主要区别
-
-
删除变量:
unset
username=ghp # 自定义一个username变量 set | grep "username" # 查看username变量 unset username # 删除username变量
注意:只能删除只读变量
-
只读变量:
readonly
myUrl="https://www.runoob.com" unset myUrl echo $myUrl
-
6、数据类型
-
Shell中的数据类型:
- 字符串(String):字符串是Shell脚本中最常用的数据类型之一。字符串可以使用单引号(')或双引号(")来定义,可以包含任何字符。
- 数字(Number):Shell脚本中也支持数字类型,包括整数和浮点数。通常使用let命令或者$((expression))语法来计算数字。
- 数组(Array):数组是一种特殊的数据类型,可以在一个变量中存储多个值。在Shell中,数组可以使用下标来访问和修改其中的元素。
- 布尔型(Boolean):Shell脚本中没有原生的布尔类型,通常使用0表示假(false),1表示真(true)。
- 空值(Null):空值表示一个变量没有任何值。在Shell中,可以使用unset命令来清除一个变量的值。
除了以上常见的数据类型,还有一些特殊的数据类型,如文件描述符、命令输出等。掌握这些数据类型可以帮助Shell脚本编程更加灵活和高效。
6.1 字符串
-
字符串:字符串可以分为三类,单引号字符串,双引号字符串,不加引号的字符串
-
单引号字符串:
# hello.sh str='this is a string' echo $str # this is a string
注意事项:
-
单引号里的任何字符都会原样输出,单引号字符串中的变量是无效的;
-
单引号字串中不能出现单独一个的单引号(对单引号使用转义符后也不行),但可成对出现,作为字符串拼接使用。
-
-
双引号字符串
# hello.sh your_name="ghp" str="my name is \"$your_name\"! \n" echo $str # my name is ghp!
如果出现了
command not fount
,这是由于 hello.sh 编码格式不对,我就踩坑了,=左右一定不能有空格,因为在写Java代码时,写空格写习惯了双引号相较于单引号的优点
- 可以使用转义符,单引号是直接输出
- 可以直接在字符串中使用变量,单引号只能通过拼接
-
不加引号的字符串
str=abc echo $str # abc
注意:定义的变量不能含有空格
-
-
常见的字符串操作
-
字符串拼接
your_name="ghp" # 使用双引号拼接 str1="hello, "$your_name" !" str2="hello, ${your_name} !" echo $str1 # hello, ghp ! echo $str2 # hello, ghp ! # 使用单引号拼接 str3='hello, '$your_name' !' str4='hello, ${your_name} !' echo $str3 # hello, ghp ! echo $str4 # hello, ${your_name} !
-
获取字符串长度
string="abcd" echo ${#string} # 4 echo ${#string[0]} # 4
-
获取子字符串
str="runoob is a great site" echo ${str:6:8} # is a gr
备注:从第7个字符开始,第7个字符是b后面的空格,然后往后数8个字符,也就是到 gr 结束
runoob[ is a gr]eat site
。类似于Python中的切片 -
查找字符
str="runoob is a great site" echo `expr index "$str" io` # 4
备注:查找字符
i
或o
,谁先出现就先计算谁,这里o
先出现,它是第4个字符,所以输出4
-
6.2 数组
-
数组的定义:
数组名=(值1 值2 ... 值n) # 示例: arr=(1 2 3) # 备注:空格的数量没有影响,字符串数组要用引号 arr=( 1 2 3 ) arr[0]=1 arr[1]=2 arr[3]=3
-
常见的数组操作
-
获取数组中的元素
# 读取数组中的元素 ${数组名[下标]} # 示例 arr=(1 2 3) echo ${arr[1]} # 2 echo ${arr[@]} # 1 2 3
-
获取数组的长度
# 取得数组元素的个数 ${#arr[@]} # 或者 ${#arr[*]} # 取得数组单个元素的长度 ${#arr[下标]}
-
7、参数传递
$n
:n表示一个正整数,1表示第一个参数,2表示第二个参数……$#
:传递到脚本的参数个数$*
:显示所有向脚本传递的参数$@
:显示所有向脚本传递的参数$$
:脚本运行的当前进程ID号$!
:后台运行的最后一个进程ID号$-
:显示Shell使用的当前选项,与set命令功能相同$?
:显示最后命令的退出状态,0没有错误,其它任何值都表明有错误$_
:表示的是打印上一个输入参数行, 当这个命令在开头时, 打印输出文档的绝对路径名
示例:
#!/bin/bash
echo "Shell 传递参数实例!";
echo "\$0 执行的文件名:$0";
echo "\$1 第一个参数为:$1";
echo "\$2 第二个参数为:$2";
echo "\$3 第三个参数为:$3";
echo "\$# 传递脚本的参数个数: $#"
echo "\$* 所有传入脚本的参数: $*"
echo "\$@ 所有传入脚本的参数: $@"
echo "\$$ 脚本运行的当前进程ID: $$"
echo "\$! 后台运行的最后一个进程ID: $!"
echo "\$- shell使用的当前选项: $-"
echo "\$? 最后命令退出的状态: $?"
echo "\$_ 上一个输入参数行: $_"
sh test.sh 1 2 "3"
Shell 传递参数实例!
$0 执行的文件名:test.sh
$1 第一个参数为:1
$2 第二个参数为:2
$3 第三个参数为:3
$# 传递脚本的参数个数: 3
$* 所有传入脚本的参数: 1 2 3
$@ 所有传入脚本的参数: 1 2 3
$$ 脚本运行的当前进程ID: 53206
$! 后台运行的最后一个进程ID:
$- shell使用的当前选项: hB
$? 最后命令退出的状态: 0
$_ 上一个输入参数行: $? 最后命令退出的状态: 0
-
$*
与$@
区别:- 相同点:都是引用所有参数。
- 不同点:只有在双引号中体现出来。假设在脚本运行时写了三个参数 1、2、3,,则 "* " 等价于 “1 2 3”(传递了一个参数),而 “@” 等价于 “1” “2” “3”(传递了三个参数)。
#!/bin/bash echo "-- \$* 演示 ---" for i in "$*"; do echo $i done echo "-- \$@ 演示 ---" for i in "$@"; do echo $i done
sh test.sh 1 2 3 -- $* 演示 --- 1 2 3 -- $@ 演示 --- 1 2 3
8、运算符
Shell 编程支持下面几种运算符
- 算数运算符
- 关系运算符
- 布尔运算符
- 逻辑运算符
- 字符串运算符
- 文件测试运算符
详情请参考:Shell 基本运算符 | 菜鸟教程 (runoob.com)
-
计算指令/符号
-
算术运算符
假定变量 a 为 10,变量 b 为 20
注意:
- 条件表达式要放在方括号之间,并且要有空格,例如:
[a==b]
是错误的,必须写成[ a == b ]
,但是在[]
中进行数值计算时,不需要空格,比如[a+b]
- 乘
*
前边必须加反斜杠\
才能实现乘法运算 - 在 MAC 中 shell 的 expr 语法是:
$((表达式))
,此处表达式中的*
"不需要转义符号\
。
- 条件表达式要放在方括号之间,并且要有空格,例如:
-
关系运算符
假定变量 a 为 10,变量 b 为 20
注意:关系运算符只支持数字,不支持字符串,除非字符串的值是数字。
-
布尔运算符
假定变量 a 为 10,变量 b 为 20
-
逻辑运算符
假定变量 a 为 10,变量 b 为 20
-
字符串运算符
下表列出了常用的字符串运算符,假定变量 a 为 “abc”,变量 b 为 “efg”:
-
文件测试运算符
其他检查符:
-S
: 判断某文件是否 socket。-L
: 检测文件是否存在并且是一个符号链接。
9、常用命令
9.1 echo命令
Shell 的 echo 指令与 PHP 的 echo 指令类似,都是用于字符串的输出。命令格式:
echo [参数] string
参数说明:
-n
:当指定-n
选项时,其后的换行符被抑制;即不会在最后自动换行-e
:当指定-e
选项时,则将解释以下反斜杠转义字符
您可以使用echo实现更复杂的输出格式控制。
-
显示普通字符串:
echo "It is a test"
这里的双引号完全可以省略,以下命令与上面实例效果一致:
echo It is a test
-
显示转义字符
echo "\"It is a test\""
结果将是:
"It is a test"
同样,双引号也可以省略
-
显示变量
read 命令从标准输入中读取一行,并把输入行的每个字段的值指定给 shell 变量
#!/bin/sh read name echo "$name It is a test"
以上代码保存为 test.sh,name 接收标准输入的变量,结果将是:
[root@www ~]# sh test.sh OK #标准输入 OK It is a test #输出
-
显示换行
echo -e "OK! \n" # -e 开启转义 echo "It is a test"
输出结果:
OK! It is a test
-
显示不换行
#!/bin/sh echo -e "OK! \c" # -e 开启转义 \c 不换行 echo "It is a test"
输出结果:
OK! It is a test
-
显示结果定向至文件
echo "It is a test" > myfile
-
原样输出字符串,不进行转义或取变量(用单引号)
echo '$name\"'
输出结果:
$name\"
-
命令执行结果
echo `date`
结果将显示当前日期
Thu Jul 24 10:08:46 CST 2014
9.2 printf命令
上一章节我们学习了 Shell 的 echo 命令,本章节我们来学习 Shell 的另一个输出命令 printf。
printf 命令模仿 C 程序库(library)里的 printf() 程序。
printf 由 POSIX 标准所定义,因此使用 printf 的脚本比使用 echo 移植性好。
printf 使用引用文本或空格分隔的参数,外面可以在
printf
中使用格式化字符串,还可以制定字符串的宽度、左右对齐方式等。默认的 printf 不会像echo
自动添加换行符,我们可以手动添加\n
。
printf
语法格式:
printf format-string [arguments...]
参数说明:
-
format-string
: 为格式控制字符串 -
arguments
: 为参数列表
示例:
#!/bin/bash
printf "Hello, Shell\n"
printf "%-10s %-8s %-4s\n" 姓名 性别 体重kg
printf "%-10s %-8s %-4.2f\n" 郭靖 男 66.1234
Hello, Shell
姓名 性别 体重kg
郭靖 男 66.12
备注:%s %c %d %f
都是格式替代符,%s
输出一个字符串,%d
整型输出,%c
输出一个字符,%f
输出实数,以小数形式输出。
%-10s
指一个宽度为 10 个字符(-
表示左对齐,没有则表示右对齐),任何字符都会被显示在 10 个字符宽的字符内,如果不足则自动以空格填充,超过也会将内容全部显示出来。%-4.2f
指格式化为小数,其中 .2
指保留2位小数。
知识拓展:常见的转义符
9.3 test命令
test命令主要用于:数值测试、字符串测试、文件测试
-
数值测试
示例:
#!/bin/bash num1=100 num2=100 if test $[num1] -eq $[num2] then echo '两个数相等!' else echo '两个数不相等!' fi
两个数相等!
-
字符串测试
示例:
#!/bin/bash num1="a b" num2="ab" if test $num1 = $num2 then echo '两个字符串相等!' else echo '两个字符串不相等!' fi
两个字符串不相等!
-
文件测试
示例:
#!/bin/bash if test -e /home/ghp/test.sh then echo '文件已存在!' else echo '文件不存在!' fi
文件已存在!
知识拓展:逻辑操作符
Shell 还提供了与
-a
(与) 、-o
(或)、!
(非) 三个逻辑操作符用于将测试条件连接起来,其优先级为:!
最高,-a
次之,-o
最低
#!/bin/bash
if test ! -e /home/ghp/test.sh -o -e /home/ghp/unexite.sh
then
echo '至少有一个文件存在!'
else
echo '两个文件都不存在'
fi
两个文件都不存在
备注:-e /home/ghp/test.sh得到的结果为 真,但是前面有一个 ! 从而导致结果为 假,-o表示或,只有有一个为真就为真,结果-e /home/ghp/unexite.sh 的结果也是 假,两个都为假,最终的结果就为假了
10、流程控制
10.1 条件判断
-
if
if condition then command1 command2 ... commandN fi
-
if else
if condition then command1 command2 ... commandN else command fi
注意:else中的command不能为空,在Java中是可以的,但是Shell中是不允许的
-
if else if esle
if condition1 then command1 elif condition2 then command2 else commandN fi
示例:
if 0
then
echo "条件为真"
else
# echo "条件为假"
fi
else为空直接报错:
取消注释,就能运算成功了:
10.2 循环
11、函数
Shell中的函数总共非为两大类:有返回值的函数和没有返回值的函数
函数的定义方式:
[ function ] funname [()]
{
action;
[return int;]
}
备注:这里的[]表示Shell中的运算符,而是表示这个参数可以省略
示例:
#!/bin/bash
# 没有返回值的函数
demoFun(){
echo "这是我的第一个 shell 函数!"
}
echo "-----demoFun函数开始执行-----"
demoFun
echo "-----demoFun函数执行完毕-----"
# 有返回值的函数
funWithReturn(){
echo "这个函数会对输入的两个数字进行相加运算..."
echo "输入第一个数字: "
read aNum
echo "输入第二个数字: "
read anotherNum
echo "$aNum 和 $anotherNum 相加的结果为:"
return $(($aNum+$anotherNum))
}
funWithReturn
echo "输入的两个数字之和为 $? !"
#!/bin/bash
# 带参函数
funWithParam(){
echo "第一个参数为 $1 !"
echo "第二个参数为 $2 !"
echo "参数总数有 $# 个!"
echo "作为一个字符串输出所有参数 $* !"
}
funWithParam 1 2 3
注意:获取第10个参数是,不能这样写$10
,要这样写${10}
12、输入/输出重定向
Linux Shell 重定向分为两种,一种输入重定向,一种是输出重定向;从字面上理解,输入输出重定向就是「改变输入与输出的方向」的意思。
12.0 前置知识
-
什么是输入重定向和输出重定向?
输入方向就是数据从哪里流向程序。数据默认从键盘流向程序,如果改变了它的方向,数据就从其它地方流入,这就是输入重定向。输出方向就是数据从程序流向哪里。数据默认从程序流向显示器,如果改变了它的方向,数据就流向其它地方,这就是输出重定向。
-
什么是标准输入设备和标准输出设备?
计算机的硬件设备有很多,常见的输入设备有键盘、鼠标、麦克风、手写板等,输出设备有显示器、投影仪、打印机等。不过,在 Linux 中,标准输入设备指的是键盘,标准输出设备指的是显示器。
-
什么是文件描述符?
Linux 中一切皆文件,包括标准输入设备(键盘)和标准输出设备(显示器)在内的所有计算机硬件都是文件。
为了表示和区分已经打开的文件,Linux 会给每个文件分配一个 ID,这个 ID 就是一个整数,被称为文件描述符(File Descriptor)。
12.1 输出重定向
Bash 支持的输出重定向符号:
备注:在输出重定向中,>
代表的是覆盖,>>
代表的是追加
注意:
-
输出重定向的完整写法其实是
fd>file
或者fd>>file
,其中fd
表示文件描述符,如果不写,默认为 1,也就是标准输出文件。当文件描述符为 1 时,一般都省略不写,如上表所示;当然,如果你愿意,也可以将command >file
写作command 1>file
,但这样做是多此一举。当文件描述符为大于 1 的值时,比如 2,就必须写上。 -
fd
和>
之间不能有空格,否则 Shell 会解析失败;>
和file
之间的空格可有可无。为了保持一致,我习惯在>
两边都不加空格。错误示例:
echo "你好" 1 >log.txt
在log.txt中你会发现是
"你好" 1
这是因为上面1和>之间存在空格,它的语句变成了 echo “你好” 1 1>log.txt
示例:
# 将 Hello World! 输出到 test 文件(test文件不需要先创建,Shll会自动在当前目录创建test文件)
echo "Hello World\!" > test
# 查看test文件中的内容
cat test
Hello World\!
for str in "abcd 123 张三 !@"
do
echo $str >> test # 将输入结果以追加的方式重定向到文件
done
12.2 输入重定向
Bash支持的输入重定向:
PS:和输出重定向类似,输入重定向的完整写法是fd<file
,其中 fd 表示文件描述符,如果不写,默认为 0,也就是标准输入文件。
示例:
准备工作:
需要熟悉wc
命令(不知道为什么看到这个命令我脑子里蹦出来一句wc)
wc [参数] [文件名]
参数说明:-c
选项统计字节数;-w
选项统计单词数;-l
选项统计行数
之前用过的test文件:
Hello World\!
abcd 123 张三 !@
示例1:获取文件的行数
wc -l < test
2 # 获取test文件的行数
示例2:逐行读取文件
#!/bin/bash
while read str
do
echo $str
done < test
这种输入重定向的写法叫做代码重定向
示例3:统计用户在终端输入的文本的单词或数字数量
[ghp@node1 ~]$ wc -w << end
> 1 2 3
> 4\?
> end
4 # -w只统计单词和数字
-
Here Document
:Here Document 是 Shell 中的一种特殊的重定向方式,用来将输入重定向到一个交互式 Shell 脚本或程序。command << delimiter document delimiter
它的作用是将两个 delimiter 之间的内容(document) 作为输入传递给 command
注意:结尾的delimiter 一定要顶格写,前面不能有任何字符,后面也不能有任何字符,包括空格和 tab 缩进。开始的delimiter前后的空格会被忽略掉。
示例:
cat << EOF 欢迎来到 菜鸟教程 www.runoob.com EOF
欢迎来到 菜鸟教程 www.runoob.com
-
/dev/null
文件:/dev/null 是一个特殊的文件,写入到它的内容都会被丢弃;如果尝试从该文件读取内容,那么什么也读不到。但是 /dev/null 文件非常有用,将命令的输出重定向到它,会起到"禁止输出"的效果。command > /dev/null
13、文件包含
所谓的“文件包含”是指可以在一个文件中引入其它的文件。比如我们可以在Shell脚本中引用其它脚本文件
. filename # 注意点号(.)和文件名中间有一空格
或
source filename
示例
脚本一:
#!/bin/bash
name="ghp"
脚本二:
#!/bin/bash
#使用 . 号来引用test1.sh 文件
. ./test1.sh
# 或者使用以下包含文件代码
# source ./test1.sh
echo "我的名字:$name"
执行脚本二
我的名字:ghp
参考资料:
- Shell 教程 | 菜鸟教程 (runoob.com)
- Shell脚本:Linux Shell脚本学习指南(超详细) (biancheng.net)
- Shell编程: shell脚本5种执行方式血煞长虹的博客-CSDN博客
- Shell环境变量set、env、export_訾零的博客-CSDN博客