linuxC语言
文章目录
知识点储备
gcc的编译流程
第一步:预处理—》将C源文件编译成C文件
头文件展开,注释去掉,宏替换掉,不做语法检查 gcc -E test.c -o test.i
第二步:编译–》将预处理之后C文件编译成汇编文件
gcc -S test.i -o test.s
第三步:汇编—》将汇编文件编译生成机器文件
gcc -c test.s -o test.o
第四步:链接—》将所有的机器文件共同参与链接,生成一个可执 行文件
gcc *.o -o App
传参的选择思路
看是否需要在子函数内部引起实参本身发生改变。
eg: int a = 90,b = 89;
子函数中实现ab两个数字的交换—》(在子函数中引起实参a,b本身发生改变,因此需要将a,b的地址传过去。
func(&a, &b);
—>才可以在子函数中通过指针来间接引起实参a,b的交换int *p = NULL;
子函数中实现给实参p赋值一个连续空间的首地址(子函数中引起实参,此时会具备有一个首地址,因此需要将&p传过去)func(&p);
–> Pointer = &p;
–>* Pointer = p;通过给*Pointer赋值就相当于给实参p赋了值。
一、C高级
1、指针函数
概念:函数返回值类型是指针类型的函数
2、函数指针
2-1函数指针的概念
指向函数的指针(函数的本质是存在内存中的一段二进制代码,因此会占据一片空间,同时该片空间的首地址用函数名来代替)
2-2 函数指针的定义格式
定义函数指针方式:
返回值类型 (*pFunc)(形参列表);
2-3 关键字typedef取别名的方法
typedef: 给已存在的一个数据类型在其作用域内取一个别名
用法: typedef 类型名 新类型名;
注意:
- 对于基本类型可以按照以上取别名的方式去写,但是对于函数指针类型需要用以下的的方式进行定义。
typedef int MYInt;
MyInt a;
- 对函数指针类型取别名的写法:
返回值类型 (*新类型名)(形参列表);
2-4 函数指针数组的定义
函数指针数组: 数组元素类型是函数指针类型的数组。
定义:
- 取完别名之后可以这样定义函数指针数组。
`函数指针类型 数组名[元素个数];`
- 返回值类型
`(*数组名[元素个数])(参数表列表);`
2-5 回调函数
概念: 把B函数的地址即(函数名或者&函数名)作为A函数的参数,传递给A函数,在A函数中通过使用这个参数来间接调B函数的过程就称为“回调函数”
3、动态内存管理
针对:堆区
在堆区中:常见的操作有—》申请空间,释放空间,初始化空间
因此,以上操作全局需要借助于函数来实现:
申请空间:malloc calloc
释放空间:free
初始化空间:memset
扩容空间:realloc
头文件: #include <stdlib.h>
函数原型:
3-1申请空间
`void *malloc(size_t size);`
功能:申请空间在堆区中
参数:所需申请空间占据的字节数
返回值:成功返回连续空间的首地址,失败返回NULL
`void *calloc(size_t nmemb, size_t size);`
功能:申请空间
参数:
参数1:所需申请的元素个数
参数2:元素的大小(字节数)
返回值:成功返回连续空间的首地址,失败返回NULL
注意:calloc在申请完空间之后,会自动将申请的连续空间初始化为’\0’
3-2释放空间
void free(void *ptr);
功能: 释放空间
参数: 所需释放空间的首地址
返回值: 无返回值
3-3扩容空间
void *realloc(void *ptr, size_t size);
功能:用来扩容空间
参数:
参数1:所需扩容空间的首地址(malloc的返回值)
参数2:扩容之后总的字节数(旧 + 新)
返回值:成功返回扩容之后空间的首地址,失败返回NULL
注意:扩容之后的空间首地址可能和之前的地址一样,也可不样!!!
#include <string.h>
3-4重置空间
void *memset(void *s, int c, size_t n);
功能:用来重置一片内存空间 (当做清空空间居多!)
参数:
参数1:所需重置内存空间首地址
参数2:所需重置的字符 —》’\0’ , 0
参数3:所需重置内存空间的大小—》sizeof()
4、结构体
概念:
是一种构造数据类型,目的是为了将一个事物的多重属性表示清楚(属性可能是不同的数据类型,也可以是相同的数据类型)。
4-1如何构造结构体
struct 结构体名
{
数据类型1 成员1 ;
数据类型2 成员2;
。。。。
数据类型N 成员N;
};
4-2如何定义结构体变量
struct 结构体名 变量名;
4-3如何给结构体成员进行赋值
变量名= {值1,值2.。。。。。。};
struct 结构体名 变量名 = {值1,值2,。。。。。};
4-4如何访问结构体中的成员
方式1:变量名.成员名;
方式2:结构体指针->成员名;
定义结构体数组,实现对于一批数据的输入输出。
4-5结构体的字节对齐
4-5-1概念
在申请结构体空间时,会遵循“字节对齐”的原则!
4-5-2分类讨论什么是字节对齐?
- 考虑在范围之内的成员必须为基本数据类型
在32OS:系统最多一次性开辟4个字节
怎样确定每一次开辟空间的大小,依赖于成员中占据字节空间最大的那个数据类型,将其作为基准,来进行每一次空间大小的开辟,但是成员有超过上限4字节的数据类型,此时仍按照4字节进行开辟空间。反之,则按照那个最大的类型占据的字节数进行开辟.
在64OS:系统最多一次性开辟8个字节
怎样确定每一次开辟空间的大小,依赖于成员中占据字节空间最大的那个数据类型,将其作为基准,来进行每一次空间大小的开辟,但是成员有超过上限8字节的数据类型,此时仍按照8字节进行开辟空间。反之,则按照那个最大的类型占据的字节数进行开辟。 - 注意:
不管是32OS还是64OS,在存储成员时,均需要保证存储的地址编号和该成员自身的数据类型大小成整数倍的关系,否则往后寻找下一个合适的地址空间进行存储。
因此结合以上两点累确定结构体类型占据的字节数!!!。
共用体
概念:多个成员共用同一片空间,因此开辟内存空间时,会按照占据内存空间最大的数据类型进行开辟。
定义格式:
union 共用体名
{
数据类型1 成员1;
。。。。
数据类型N 成员N
};
注意:共用体的使用方法和结构体一致,唯一区别是:结构体的成员空间是独立的,而共用体的成员共用同一片空间。
6、枚举
概念:跟宏比较类似,意味着也是一些常量值,只不过这些常量值是被放在一个集合里面。
如何定义一个枚举类型?
enum 枚举名
{
枚举数值名1,
枚举数值名2,
。。。。
};
7、大小端(字节序)
概念:计算机中存储数据的时候到底将低字节或者高字节处的内容存储在低地址还是高地址的问题。
大端存储:低字节处的内容存储在高地址处,高字节处的内容存储在低地址处。
小端存储:低字节处的内容存储在低地址处,高字节处的内容存储在高地址处。
低字节:一串二进制数据的右边低地址:小的地址编号
8、调试BUG的方式
8-1方法一
printf打印 —>最直接
在自己感觉出错的代码段前后加上部分printf输出内容,然后编译运行来判断问题的出处。
8-2方法二
gdb调试工具
流程:
- 生成带有调试信息环境的可执行文件
方式:gcc -g test.c -o App - 进入该可执行文件
方式:gdb App - 设置断点 -->让程序从哪里开始调试
方式:b 行标/函数名 - 运行
方式: r - 单步运行
n: 不进入子函数内部,但不代表不执行子函数
s: 进入子函数内容,并开始执行子函数中每一行代码 - 找到错误所在的行
响应:看到程序打印出一行文本“Program recived Sigmentation fault…”,上一行就是引起错误的所在行。 - 结束调试
方式:按下q退出即可。
9、对于段错误的理解
在C语言阶段出现段错误的原因:
- 数组越界
- 操作空指针或者野指针
- 修改常量区内容
10、递归函数
概念:重复调用其他函数或者调用自己,但是调用的时候一定要注意结束调用的条件。
如何编写一个标准的递归函数?
三要素:1)从哪里开始?2) 从哪里结束?3) 每一步干什么?
11、头文件的书写(多文件编译)
格式:条件编译—》防止同一个头文件被重复定义
创建一个后缀是.h文件eg: touch test.h
打开test.h —> vim test.h
编写以下代码:
#ifndef _TEST_H_
#define _TEST_H_
...
1、宏定义
2、结构体定义
3、取别名
4、全局变量的声明
5、函数的声明
6、枚举类型的定义
#endif
之前:书写代码需要一个C文件即可
现在: 具备书写一个项目的思想
项目是什么样的?—》会有很对不一样的需求,因此每一个需求可能会交给一个人去完成,因此书写一个完整的项目需要多个人去负责,意味着会有多个.c文件需要进行书写,也需要有一个.h文件作为辅助,进行编译。
注意:对于以上需求,需要通过主文件进行调用—》.c文件
综上: 1个主文件 + 若干个子文件 + 若干个头文件
12、Make
概念:工程管理工具,可以将很多.c文件+.h文件进行统一管理
使用: 命令行输入make 目标名
即可
如何编写一个Makefile文件?
—》统一格式
目标:依赖
[Tab]命令表
12-1Make中的一些变量
12-1-1用户自定义变量
格式:变量名:=值 (定义变量且赋初值,变量名建议大写)
12-1-2自动变量
$ < :依赖中的第一个依赖
$ ^ :所有依赖
$@:目标名
12-1-3系统预定义变量
CC:编译器的名称,默认值是cc ,用户可以自己赋值为: eg CC :=gcc
CFLAGS:编译器的选项,无默认值,用户可以自己赋值:eg: CFLAGS:= -c -g -Wall
RM:代表删除,默认值为:rm -f,用户可以自己赋值为 eg: RM := -rf
12-1-4环境变量
export :添加一些指定的环境变量到整个系统环境中去
export 变量1 变量2 变量3
二、LinuxOS
1、Linux的体系结构
内核:
1.核心组件,负责管理操作系统的执行。
2. 进程管理,内存管理,网络管理,文件系统管理,设备驱动管理
shell:
本质是一个命令行解释器,起到中间桥梁的作用,负责接收用户输入的命令,并简化其翻译提交给内核,让内核做出回应。
文件系统:
数据在设备或者分区上组织文件的一种方法(数据结构)。
分为:
1.磁盘文件系统(U盘),虚拟文件系统(隐藏了跨文件系统类型数据传输的细节,调用者只需要使用统一的接口,即可完成不同文件系统类型的之间的数据交互。),网络文件系统(进程间网络通信时,数据的接收以及转发)。
2.实用程序:每一个独立的系统,都会配备自己专属的一套程序:编辑器,编译器,浏览器,办公套件,数据库。。。。
2、Linux的软件包管理
思路:
- 在工程总目录下,创建tags文件,目的是将工程中所有的文件进行关联 代码为:命令行输入–》ctags -R (-R代表递归关联)
- 在含有tags文件的路径下打开一个文件,比如:vim ./include/stu.h
- 在需要跳转的位置,比如经常在函数声明的位置,输入 ctrl }这个组合键,即可跳转至该函数的实现文件处
- 阅读完毕代码之后,通过ctrl t 组合键实现返回上一次跳转的位置.
如何设置一个固定的IP地址?
关心4个参数:IP地址(192.168.0.num) , 子网掩码(255.255.255.0) , 网关(192.168.0.1), DNS服务器(8.8.8.8 / 8.8.4.4)
3、Linux的网络基础
3-1IP地址
IP:Internet Protocol ---->网络协议,在通信中起到路由的功能
IP地址的形式:由点分十进制的数字组合而成,总共占4给字节(32位二进制数据):eg:192.168.0.89
IP地址的组成:网络地址(高位) + 主机地址(低位) I
P地址类型:因为网络地址和主机地址所占字节数的不同,可以划分为:A类 B类 C类 D类 E类
IP地址5种类型的划分,按照网络地址和主机地址所占的比例:
- A类IP:网络地址占1个字节,主机地址占3个字节,并且规定网络地址的最高位是0
范围:0.0.0.0 ~ 127.255.255.255
注意: 0.0.0.0为任意地址,用户不会获得,网络地址会从1开始,主机地址也是从1开始分配给用户,127开头的IP地址都是本地环回地址,用户无网络时进程间通信,以255结尾的IP地址都是广播地址,用户也不会被分配到,因此,用户在A类IP范围中,可以获取的有效IP地址范围为:1.0.0.1 ~ 126.255.255.254 - B类IP:网络地址占2个字节,主机地址占2个字节,并且规定网络地址的最高位是10
- C类IP:网络地址占3个字节,主机地址占1个字节,并且规定网络地址的最高位是110 范围:192.0.0.1 ~ 223.255.255.254 (优化之后的有效IP地址范围)
- D类IP:目前用于组播实现比较多
- E类IP:目前处于保留,等待将来使用
3-2子网掩码
作用:判断当前两台主机之间的通信是外网通信还是内网通信
方法:
A:192.168.0.199 —》子网掩码:255.255.255.0
B:192.168.2.188 —》子网掩码:255.255.0.0
假如A想给B发消息:把A和B的IP地址均和A的子网掩码进行相与,查看网段是否一致,如果一致则代表可以直接通信即内网通信,否则需要外网通信(借助网关)。
假如B想给发消息:把A和B的IP地址均和B的子网掩码进行相与,查看网段是否一致,如果一致则代表可以直接通信即内网通信,否则需要外网通信(借助网关)。
3-3网关
作用:由一台主机通往另一台主机的IP地址(针对外网通信的时候)
网关可以有多个,但是一般会有一个默认网关:C类–》192.168.X.1 (X是网段号)
3-4DNS服务器
域名解析服务器,存储的是域名和IP的对应关系,当用户访问域名的时候,就会查询DNS服务器上的表,进而找到域名对应的IP地址。
eg:ping www.baidu.com —>最终还是借助于DNS服务器:8.8.8.8 / 8.8.4.4 来查找www.baidu.com对应的IP地址
如果没有DNS服务器,就不识别域名,会报Unknown host。。。。
4、Linux下的shell命令
命令的学习:三要素
命令名称 [ 选项 ] [ 参数 ];
总结:
- 命令名称不能省略
- 选项和参数是可选的(可有可无可多个)
- 不管是命令,还是代码在同一行写不完时,需要先输入空格,在输入反斜杠,再按下回车即可在下一行进行书写。
- 将多个命令书写在一起时,多个命令之间需要通过分号来隔开。
4-1用户切换命令
su:切换用户状态的命令
方式:
- 方式1:su 用户名:将用户身份切换至指定的用户状态,此时所在路径和切换之前的用户位置一样。
- 方式2:su - 用户名:将用户身份切换至指定的用户状态的同时,也将用户之前所在的路径切换至指定用户的家目录。
4-2用户管理命令
4-2-1修改密码
格式:
sudo passwd 用户名
注意: 输入:passwd也可修改密码,但是默认修改当前用户的密码(密码只能越来越长!,所以不建议,还是记住sudo passwd 用户名这个通用的公式即可。)
4-2-2创建新用户
格式:
sudo adduser 新用户名
4-2-3删除用户
格式:
sudo deluser 用户名
注意:想要彻底删除用户的时候,添加–remove-home这个选项即可。
4-3常见的shell命令
4-3-1env
打印环境变量以及变量对应值的命令,环境变量的值为多个时,以冒号隔开。
4-3-2ln
创建链接文件的命令
链接文件的分类:
- 软链接:称为符号链接文件,以源文件的所在路径创建的一个文件,意味着软链接文件存储的是指向源文件的一条路径,类似于Windows下的快捷方式。
创建方式:
`ln -s 源文件(带绝对路径) 软链接文件`
- 硬链接:以物理编号inode编号创建的文件,意味着:
方式:
`ln 源文件(相对/绝对路径) 硬链接文件`
注意:源文件的写法,可以不加绝对路径,因为和路径没关系。只是源文件的一个别名。
对于软链接和硬链接文件的总结:
- 软链接:
1、源文件和软链接是两块空间,并且软链接文件存储的是指向源文件的一条路径
2、源文件和软链接的影响是双向的。
3、创建软链接文件时,源文件建议写成绝对路径的方式,可以提高软链接文件的移植性。
4、当删除源文件时,软链接立马失效,当恢复(创建一个与之前源文件同名的新文件)源文件时,此时软链接文件会生效,但是此时指向的是最新的文件。 - 硬链接:
1、源文件和硬链接是同一片空间,可以理解为硬链接是源文件那片空间的一个别名而已。
2、源文件和硬链接的影响是双向的。
3、创建硬链接文件时,源文件以相对路径或者绝对路径都可以,不依赖路径而存在。
4、当删除源文件时,硬链接不受影响,可以理解为那片空间的名字少了一个,此时依旧可以通过硬链接来打开之前源文件的空间并进行操作。(可以当做备份或者误删来使用)。
注意:
如何确保两个文件是否为同一个文件?
-----》打印分配给每一个文件物理编号inode号来查看—》ls -i 即可打印出编号。
4-3-3echo
标准输出命令,功能类似于Printf
用法:
- 方式1:打印指定的一个字符串
- 方式2:打印变量的值(注意:通过$符号完成对变量值的获取)
总结:不管是方式1还是方式2,通过echo 输出的时候,均需要书写””引起来就不会出错。
4-3-4chmod
对于文件的文权限进行更改
创建新文件的初始权限是:rw- rw- r-- —》0664,如果需要对该文件的 权限进行升级或者降级时,就需要通过chmod来做。
假设:文件为:test.c —>初始权限:0664
- 方式1: 八进制法
chmod 0774 test.c / chmod 774 test.c - 方式2:符号标记法
用户:u
用户组:g
其他用户:o
所有用户:a
chmod u+x test.c
chmod u-x test.c
chmod a+x test.c
chmod +x test.c (等价于a + x)
4-3-5tar
来实现打包相关的命令
选项:
-c:打包
-x:解包
-v:可视化(可以看到打包,压缩,解包,解压的过程)
-z:可以调用压缩工具为gzip
-j:可以调用压缩工具为bzip2
-f:可以指明需要打包压缩的文件名
注意: -C 代表可以指定解包或者解压之后的位置,如果不写,则默认解包或者解压到当前用户工作位置。
4-3-6grep
查找对象是文件中内容,在一个文件中去匹配指定的格式,匹配搜索指定的格式(文件中)
格式:
`grep 选项 格式 路径`
解释:
-c:匹配包含指定格式所在行的行数
-n:匹配包含指定格式所在行
-v:匹配除了包含指定格式所在行的其他行
4-3-7find
查找,查找对象是文件
格式:
`find 路径 选项 描述`
解释: -name:代表需要查找指定文件名
4-3-8wc
统计文件的大小,单词数,以及文件的行数
4-4shell特殊字符
4-4-1通配符
*:匹配任意长度的内容。—》最为常用。
?:匹配含有一个长度的内容
[范围]:匹配含有范围之内的一个长度的内容
[指定范围]:匹配含有指定范围之内的一个长度的内容
[ ^指定范围]:匹配除了指定范围之外的任何一个长度的内容
4-4-2管道
格式:
`command1 | command2 | ..... | commandN`
理解: 将前一个命令的输出作为后一个命令的输入
补充:xargs 命令—》会具备转换功能(将输出格式化为一行,作为参数赋值给下一个命令)
4-4-3命令置换
格式:
`Command1 Command2`
理解:将Command2的输出作为Command1命令的参数
思考:管道和命令置换有啥区别?
-管道是将输出作为输入,等价于将输出作为文本流,所以接下来的操作就会直接对该文本流进行操作
-命令置换将输出作为参数,等价于在接下来操作中会进入参数所代表的文件里面去操作。
4-4-4重定向
概念:重新定义输出或者输入的方向为自己指定的
输入重定向:
之前对于输入,默认的方向为键盘,现在可以将默认的输入方向即从键盘获取输入源改变到从比如文件中去获取一个输入源。
eg: cat:查看指定文件的内容
cat 1.c —》 cat < 1.c ( <可以省略不写 )
输出重定向:之前对于输出,默认的方向为终端,现在可以将默认的输出方向从向终端输出改变到向比如一个文件中去输出。
情况讨论:
- “>”:重定向到的文件不存在时,新建并打开并存储,反之则直接先清空之前内容,再打开并存储,但是只能接收正确命令的结果。 >>:重定向到的文件不存在时,新建并打开并存储,反之以追加模式打开文件并存储,但是只能接收正确命令的结果。
- “2>”: 重定向到的文件不存在时,新建并打开并存储,反之则直接先清空之前内容,再打开并存储,但是只能接收错误命令的结果。
- “2>>”:重定向到的文件不存在时,新建并打开并存储,反之以追加模式打开文件并存储,但是只能接收错误命令的结果。
- “&>”:重定向到的文件不存在时,新建并打开并存储,反之先清空之前内容,再打开并存储,不论正确输出或者错误的结果均可接收并存储。
- “&>>”:重定向到的文件不存在时,新建并打开并存储,反之以追加模式打开文件并存储,不论正确输出或者错误的结果均可接收并存储。
5、Linux下的shell编程
5-1脚本的理解
脚本也是由一系列命令组合起来,并且加入了一定的控制结构之后所形成的文本,就称之为脚本,优点是可以自动且重复的去执行某件事情,比如:开机或者关机之前以及之后可以自动的去执行一部分代码,因为脚本也是多条shell命令的有序结合,因此在终端上能够完成的事情全部可以使用脚本来完成(重复使用)。
当执行脚本的时候,shell这个解释器就会逐行去翻译命令,并将结果提交给内核,内核接收到结果之后,就会去驱动硬件进行响应。
因此:脚本就是一门解释型的语言,本质是多条shell命令的有序集合(可能会加入一定量的控制结构语句)。
总结:
shell命令:理解为用户发送给内核一种信号(该信号是由shell来完成解释)
shell:命令行解释器(专门负责将用户输入的命令或者语句翻译给内核)
shell脚本:多条shell命令的有序集合(可能会引入一些控制结构语句)
5-2脚本的编写格式
第一步:顶格书写:#!/bin/bash ----》交代即将书写完毕的脚本由谁完成解释工作。
第二步:按照shell规定的语法进行编码即可。
5-3脚本的变成步骤
第一步:新建一个后缀为.sh的文件(和之前C文件一样)
第二步:修改文件的权限(chmod 来修改文件的权限为可执行,至少自己具备可执行权限)
第三步:直接执行(./可执行文件名字 运行即可)
5-4脚本的语法
对于变量的定义:脚本中的数据类型称为“弱类型”,意味着没有数据类型的区分。
5-4-1自定义变量
方法: 变量名;----》建议大写
赋值: 变量名=值;—》等号前后不能有空格。
引用: ${变量名} / $变量名
(存在风险:如果变量名和之后的字符串紧挨着时,会被视为一个新的变量名);`
建议:引用变量值时,以{}的形式引用比较安全。
5-4-2位置变量
理解为:变量的值可以从命令行传入
我们怎样使用传入进来的数值?
—》
和数字进行结合:
和数字进行结合:
和数字进行结合:N (N 是数字,从0开始)
5-4-3系统预定义变量
系统之前规定将$符号和指定的另外一个字母两者相结合,之后具备一定的含义。
$ #:统计命令行参数的个数(有效参数的个数–》不包含可执行文件的名字)
$ @:统计传入的参数本身(有效参数)
$*:统计传入的参数本身(有效参数)
$?:获取上一条命令的退出状态:状态数值不是0就是1(0代表上一条命令时成功执行,反之为失败执行)
5-4-4环境变量
—》查看系统中的所有环境变量的命令:env
操作:
- 添加新环境变量:
`export 变量名=值`
(可以一次性赋值多个,多个数值之间以冒号隔开)
- 修改环境变量值:
export 变量名=新值:${变量名}
/
export 变量名=${变量名} :新
值清除环境变量:
unset 变量名
5-5脚本的语句
5-5-1说明性语句
凡是以#开头的语句都是说明性语句,可以理解为注释。
5-5-2功能性语句
5-5-2-1动态获取变量的值
命令:read —>功能类似于scanf函数的功能
方式:
read 变量名1 变量名2 。。。 变量名 (定义变量且赋初值)
提示语句的写法:
方式1:通过echo “提示语句”
方式2:使用read的同时去打印:read -p “提示语句” 变量名
5-5-2-2同一幅的转义
- 软转义: 双引号 和 不加双引号 —》软转义(会保留shell特殊字符的含义)
eg: 在打印输出的时,遇到 变量名时,会先执行 {变量名}时,会先执行 变量名时,会先执行{变量名},访问到数值之后再去输出。还有遇到命令的时候,也会先执行命令,将命令执行之后的结果再去输出。
总结:
双引号和不加双引号在多数情况下,两者没啥区别,但是又不完全等价。
具体区别有两种情况:- 情况1:含有多个空格
比如: echo “wangjia jia”; —>原样输出
echo wangjia jia; —》wangjia jia (中间只会有一个空格,将其他空格全都抹掉) - 情况2:在含有\
- 情况1:含有多个空格
综上所述:在以后输出时,建议都加上双引号,结果一定符合预期数值。
- 硬转义: 单引号 和 \ —》硬转义(会屏蔽掉shell特殊字符含义)
eg: 在打印输出时,遇到$ {变量名}或者命令时,不会去执行${变量名}取到数值或者执行命令,反而将它们视为一个字符串去直接输出。
5-5-2-3expr算术运算命令
功能: + - * / %
方式:
expr 变量名1 运算符 变量名2
总结: expr和变量名之间至少保留1个空格,运算符和两个变量名之间也要存在空格。
5-5-2-4测试命令test
测试命令---->代替判断语句
测试格式:
第一种: [ 对象1 测试条件 对象2 ]
第二种: test 对象1 测试条件 对象2
测试对象:
- 整形:测试对象假设为:num1 num2
- 等于: num1 -eq num2
- 不等于:num1 -ne num2
- 大于: num1 -gt num2
- 大于等于:num1 -ge num2
- 小于: num1 -lt num2
- 小于等于: num1 -le num2
等于:equal 不等于:not equal 大于:greater than 大于等于 :greater than equal 小于:less than 小于等于:less than equal
- 字符串:测试对象假设为:str1 str2
1. 等于: str1 = str2 (空格必须有,否则被视为变量赋值)
2. 不等于:str1 != str2
3. 字符串长度为0: -z str1/str2
4. 字符串长度不为0:-n str1/str2 - 文件属性:假设测试对象为:f1 f2
1. -f :测试对象是否存在且为普通文件
2. -d :测试对象是否存在且为目录文件
3. -L :测试对象是否存在且为软链接文件(符号链接文件)
4. -r:测试对象是否存在且具备可读权限
5. -w:测试对象是否存在且具备可写权限
6. -x:测试对象是否存在且具备可执行权限
7. -s:测试对象的大小
8. f1 -nt f2:测试f1是否比f2更新(文件最后一次保存的时间)
9. f1 -ot f2:测试f1是否比f2更旧(文件最后一次保存的时间)
5-5-3结构性语句
5-5-3-1顺序结构
- 多路分支:
if:
形式参考如下:
if 测试语句
then
命令表
elif 测试语句
then
命令表
。。。
else
命令表fi
- case:
形式参考如下:
`case 变量值 in
模式1)
命令表
;;
模式2)
命令表
;;
...
*)
命令表
esac
注意:在脚本中:与使用-a表示,或使用-o表示,非使用!表示
5-5-3-2选择结构
5-5-3-3循环结构
for while
C中:
I
nt i = 0;
for(;表达式2;表达式3)
{
循环体
}
- 脚本中的for循环:
- 形式1:带参数列表
for 变量名 in 单词列表
do
命令表
done
seq:产生指定范围之内的所有整数。
用法:
seq 范围1 范围2
2. 形式2:不带参数列表
3. 形式3:类似于C风格
- 脚本中的while循环。
格式:
while 条件判断
do
命令表
done
死循环:
while [ true ]
do
命令表
done
5-6脚本函数
函数定义格式:
function_name()
{
命令表1
命令表2
。。。
命令表N
}
如何调用这个函数:
- 方式1: 变量名 =
function_name 参数1 参数2 。。。。
—》查看变量名的值来获取函数调用的输出信息 - 方式2:function_name 参数1 参数2 。。。。。。 —》查看函数的执行结果通过打印$?
如何在子函数内部访问实参?
通过$ N这样的结合访问(N是数字)
注意:
- shell函数中的返回值范围是0-255之间,超过255从0开始重新取值(环回),但是子函数内部没有限制。
- 对于实参,可以通过位置变量来进行传参。—》$N来访问传递给实参的数值