下午 + 第二天 + 第三天 结构体 堆区操作 make工程管理
- 第五天命令 gdb shell脚本以及shell编程
结构体
包含C语言中所有的简单的数据类型 以及复杂数据类型的一种复合数据类型
结构体的定义
Strcut---》用来声明这是一个结构体
Struct +结构体名
{
数据1;
数据2;
。。。。。。。
};
struct people
{
Char name[20];
Int age;
};---->结构体 内部有简单的数据类型int,有复杂的数据类型 数组
C只提供结构体的关键字struct,但是内部的数据类型全部由个人自己进行定义。
用户创建的结构体---》作为一个数据类型而存在。
结构体访问内部成员
结构体定义好只是一个数据类型,如果要访问内部的成员,需要用到结构体变量或者结构体指针。
结构体变量
Tyepdef重命名
Typedef int int_t;
结构体指针
通过结构体数据类型来定义结构体指针
操作指针的本质:直接操作指针,从而实现简介的操作某一片空间里面(地址标号)的内容。
结构体嵌套
结构体是一个复合的数据类型,内部的成员是简单的和复杂的数据类型,但是同时还可以包括结构体
Struct people
{
Char name[20];
Int age;
};
Struct student
{
Int score;
};
现在将这两个结构体进行嵌套
Struct people
{
Char name[20];
Int age;
Struct student s; //struct student *s;如果使用指针,一定会有一个学生类型的结构体变量
};
引用成员
结构体变量访问结构体变量
结构体变量访问结构体指针
指针访问变量
指针访问指针
字节对齐
计算结构体的大小
Struct people
{
Char name[29];
Int age;
Double height;
};---》48
在计算结构体大小的时候,先看结构体内部成员的数据类型有没有超过4个字节,如果没有,就按照最大的数据类型进行对齐,如果超过4字节,就按照4字节对齐。
Struct a
{
Char b;
Short c;
Char d;
Int e;
};--->12字节
初始化
在定义结构体变量的时候才能进行赋值,不能在定义结构体的时候赋值,因为结构体是个数据类型。
结构体数组
数组:同一类型元素的集合。
结构体数组:是一个数组,只不过数据的类型是结构体类型
Struct people
{
Char name[20];
Int age;
};
Struct people a,b,c;
Struct people Arr[3] = {{“aa”,1},{“bb”,1},{“cc”,1}};--->结构体数组
访问内部元素:arr[0].name;arr[0].age;
赋值
Scanf(“%s”,arr[0].name);
Scanf(“%s”,arr[1].name);
Scanf(“%s”,arr[2].name);
For(i=0;i<3;i++)
{
Scanf(“%s”,arr[i].name);
}
在对结构体内部的元素进行输入输出时,不管是通过结构体指针访问还是结构体变量,输入的时候只需要看内部元素的输入输出方式,因为结构体指针和变量只是提供了一种访问内部元素的方式。
定义一个结构体,内部元素有姓名,性别,年龄。然后定义一个具有五个元素的结构体数组。对年龄进行排序。然后输出全为男性的名字和全为女性的名字。
- 变量的数据类型---》去掉变量名
Int arr[5];--->int [5];--->int (*p)[5]; 数组指针永远指向一维数组
Int arr[2][5];--->int (*p)[5];
数组指针和一维数组
指针函数和函数指针
函数
返回值 函数名(形参)
{
结构;
}
返回值:
- 库函数,系统调用,接收程序执行的结果
- 判断函数调用是否成功
- Return 0;主函数结束
函数的本质:存在于内存上的一段二进制代码
函数名:二进制代码的入口地址
指针函数
是一个函数,返回值是一个指针类型
Char * strcat(char * s1,char * s2);
函数指针
是一个指针,指向一个函数
int pthread_create(pthread_t *thread, const pthread_attr_t *attr,void *(*start_routine) (void *), void *arg);
在判断指针类型的时候,需要知道指针的指向类型----》先找出函数的数据类型,然后加*,起名
Char * strcat(char * s1,char * s2);
Int strcmp(char *s1,char *s2);---->int (*p)(char *,char *) = strcmp/&strcmp;
- strcat的数据类型---》char * (char *,char *)//去掉函数名和形参名
- 加*取名---》char * (*p)(char *,char *) = strcat//将函数名看作入口地址 p = strcat
- Char * (*p)(char *,char *) = &strcat//将函数的空间看作一个整体 p = &strcat
函数指针数组
是一个数组,数组元素是指针,指针是指向函数的。
Char * strcat(char *s1,char * s2)
Int strcmp(char *s1,char * s2)
当代码中出现函数指针数组的时候,需要两个或者两个以上的函数的数据类型相同。
Int add(int a,int b)
{
Return a+b;
}
Int div(int a,int b)
{
Return a/b;
}
Int mul(int a,int b)
{
Return a-b;
}
三个函数的类型都相同:int (*p)(int ,int ) = add;int (*p)(int ,int ) = &add;
Int (*q)(int,int ) = divInt (*q)(int,int ) = ÷
Int (*z)(int,int) = mul;Int (*z)(int,int) = &mul;
Int (*arr[3])(int,int) = {add,div,mul};
Int (*arr[3])(int,int) = {&add,&div,&mul};
Arr[3]是函数指针数组
共用体
共用同一片内存空间
Union a
{
Int a;
Char b;
Short c;
};
共用同一片空间,先找最大的数据,那么共用体的大小就是最大的数据类型的大小。
共用体每个元素的地址都相同
大小端
堆区
#include <stdlib.h>
void *malloc(size_t size);
在堆区申请空间
参数:申请的空间大小
返回值:成功返回空间首地址,失败返回NULL
因为malloc的返回值是void *,所以在申请空间成功之后,根据所申请到的空间进行强制类型转换
Int * p= (int *)malloc(sizeof(int)*5);
#include <string.h>
void *memset(void *s, int c, size_t n);
作用:清空空间(任何空间)
参数1:空间的首地址
参数2:用来清空空间的字符
参数3:清空空间的大小
Memset(p,0,sizeof(int)*5);
void free(void *ptr);
清空空间
参数:空间的首地址
void *realloc(void *ptr, size_t size);
参数1:空间的首地址
参数2:扩容的大小
返回值:扩容后的空间首地址
如果malloc之后的放不下,那么重新开辟空间进行存放,空间的首地址会改变,原本malloc的内容会被复制
如果放得下,那么就在malloc空间之后进行开辟,空间首地址不变
定义学生结构体,姓名,年龄,三门课的成绩,平均成绩。
- 使用malloc开辟空间(3)
- 输出姓名最大的人的信息
- 计算三门的平均成绩,并输出平均成绩85以上的人
- 输出年龄最大的人的地址
封装实现(自定义函数)
将封装的函数,使用函数指针数组实现
枚举
枚举内部的元素相当于给数字起别名。
#define M 4--->宏定义
Typedef int int_t;
enum A
{
malloc_ok,
Input_ok,
Output_ok,
};
枚举变量可以是字符,可以是数字,但是具体的结果要看格式控制符,并且枚举的大小永远是4字节。不能将浮点型作为枚举的变量。字符(字符串)都是数字的别名。
递归函数
在子函数的内部,自己调用本身的子函数
一个函数具有的功能,需要不断地进行更新,那么就可以写成递归函数(所要实现的功能复合一定的规律)
1+2+。。。。。+100
书写递归
- 从什么地方开始
- 从什么地方结束
- 从开始到结束怎样变化
Int digui(int sum)
{
If(1 == sum)
{
Return 1;
}
}
Main()
{
Digui(100);
}
For(i=0;i<100;i++)
make工程管理
Make相当于使用一个命令,但是需要相对应的规则才能够运行make
Makefile里面方的就是make所执行的规则
目标:依赖
[TAB]命令表
目标:所希望生成的文件
依赖:生成目标所依赖的源文件
命令表:以来怎么样变为目标
命令表
预处理 gcc -E 1.c -o 1.i 头文件展开,去掉注释,发生宏替换
编译
汇编
链接
一般将前三步合在一起,称作单独编译不链接
gcc -c 1.c -o 1.o
以1.c为例
.c文件一般作为依赖
1.o:1.c
Gcc -c 1.c -o 1.o
.o文件也可以作为依赖
1:1.o
Gcc 1.o -o 1
.c文件没有依赖,可执行文件没有目标
假目标
没有依赖,相当于是一个命令
.PHONY:---》声明clean是假目标
Clean:
Rm 1.o
Rm 1
自定义头文件
Test.h
#include <test.h>--->去 /user/include 寻找复合名字的头文件
#include “test.h”在用户当前工作路径下寻找头文件
“”包裹的头文件一般是用户自定义头文件
#ifndef _TEST_H_
#define _TEST_H_ ----->防止头文件重复包含
//需要用的库函数
//宏定义
//枚举
//结构体/共用体
//函数声明
#endif
将可执行文件的目标,依赖和命令表写在makefile的最上面
Make管理文件,根据文件的更新时间进行管理,执行最新的文件
多文件编译
- 自定义头文件
- 拆分子函数---》创建一个.c文件,将子函数全部写到.c内部,然后加上自定义头文件
- 书写makefile
系统预定义变量
CC 系统预定义的编译器 gcc
CFLAGS 预定义的编译选项 -c
$@ 文件的完整名字 (单独的.o目标,只能写在命令表中)
$^ 非重复的依赖文件 (所有的.o)
$< 第一个依赖文件的名称 (单独的.c依赖,只能写在命令表当中)
1.c 2.c
App:1.o 2.o
Gcc $^ -o $@
1.o:1.c
Gcc -c $< -o $@
2.o:2.c
Gcc -c $< -o $@
采用系统预定义的变量来代替缩写的目标.o和依赖.c
自定义变量
自己定义的变量的名字
A B是自定义的变量名,如果要使用App,或者所有的.o文件,需要加上$
结构体
Int double
结构体是自定义的数据类型
可以通过结构体数据类型定义结构体变量和结构体指针
Struct lion
{
Char name[20];
Struct tager ta; /*ta
};
Struct lion l;//*l
结构体数组
一片连续的空间,内部数据是结构体类型
Typedef Struct student
{
Char name[20];
Int age;
}STU;
STU s[5];
S[0]~s[4]
For(i=0;i<5;i++)
{
Scanf(“%s”,s[i].name);
}
Malloc
Int * p=(int *)Malloc(sizeof(int));
STU *p = (STU *)Malloc(sizeof(STU));
Int mymalloc(STU ** st)
{
*st= (STU *)Malloc(sizeof(STU));
If(*st == NULL)
}
一级指针和二级指针
Int a = 20;
Int *p = &a;
Int *q = p;
对于一级指针,操作指针p,并不会引起指针q的指向发生改变
Int a = 20;
Int *p = &a;
Int **q = &p;
对于二级指针,操作指针q,会引起p的指向发生改变
Make
Makefile--->脚本
目标:依赖
命令表
多文件编译
系统预定义变量和自定义变量
CC
CFLAGS
$@
$^
$<
OBJS = main.o malloc.o
OBJ = App
Export OBJS OBJ
App:main.o malloc.o
${OBJ}:${OBJS}
${CC} ${OBJS} -o ${OBJ}
makefile嵌套
网络基础
IP 子网掩码 网关 DNS服务器
IP
IP:主机的唯一标识
点分十进制--》192.168.1.1
IP的分类和组成
A:一个网络地址+三个主机地址
网络地址最高位为0 0000 0000 ~0111 1111--》0~127
0.0.0.0~127.255.255.255
0.0.0.0:源地址 没有明确的Ip,都会被0.0.0.0接受
127开头的地址 本地环回地址
255结尾的地址 组播和广播地址
B: 两个网络地址+两个主机地址
第一个网络地址的最高位是10 10000000~10111111---》128~191
C:三个网络地址+一个主机地址 11000000~11011111--》192~223
D:第一个地址是1110
E:第一个是11110
子网掩码
- 分割IP
- 通信
子网掩码
C类IP:默认子网掩码 :网络地址全为1,主机地址全0
255.255.255.0
A:192.168.2.1--->255.255.255.0
B:192.168.2.3--->255.255.255.0
判断能否进行通信:
先用主机的IP和子网掩码进行与操作(位操作)
A:192.168.2.0
B:192.168.2.0
- B在同一个网段,可以通信
A:192.168.2.1--->255.255.255.0
B:192.168.3.3--->255.255.0.0
A:192.168.2.0
B:192.168.0.0
- ->B发消息B的子网掩码和A进行与操作:192.168.0.0,和B在同一个网段,可以发送消息
- -A发消息
A的子网掩码和B进行与操作:192.168.3.0,和A不在同一个网段,发送消息显示主机不可达
进行ping命令,ping不通
网关
Gateway
网关的作用:不同网段的主机如果需要通信,就需要借助网关(网间连接器)
默认的网关192.168.x.1---》x是主机所在的网段
DNS服务器
域名解析服务器
域名相当于是网址
在计算机中存在域名服务表,这个中将IP地址和域名进行对应,输入baidu.baidu.cn
Baidu.com都会跳转到www.baidu.com,然后将这个域名进行解析。
一个IP可以对应多个域名,一个域名只有一个对应的IP
SHELL
外壳,保护,跟外界交互的桥梁
这个是命令行提示符,需要在这里输入命令
执行命令之后,系统会给出相应的操作---》交互
Shell是什么?
Shell在系统当中叫命令行解释器,在/bin里面有所有的命令。
解释?
将在命令行提示符输入的字符串,去/bin目录下找同名的字符串,如果找到,那么就进行对应的操作,如果没有 command not found(去/bin找文件,而不是翻译成01二进制)
Bash?
Bash是一个进程,打开一个终端就会有一个bash产生
查看当前所有运行的进程
内核:linux是内核,乌班图才是linux操作系统,以一个操作系统的组成需要 :内核+实用程序+文件系统。
内核管理
磁盘管理
网络管理
进程管理
硬件管理
内核进行管理的时候一定有对应的设备,这些设备或者应用程序就是系统开发公司进行开发的,和内核相互匹配,构成一个完整的操作系统
SHELL命令
名称选项参数
选项参数可省,名称不可省
- 用户命令
Sudo su root
Su root
Su-
添加用户
判断用户有没有添加成功需要看 /etc/passwd,如果当中存在,说明用户存在
Cat
在终端上查看当前文件的内容
Head/tail + 文件名 查看文件头/尾 十行的内容
More/less
More和cat相似 less之后会显示当前文件的内容,不会显示命令行提示符
Grep 查找(查找已知文件内部的内容)
Grep+ 参数+需要查找的内容 + 路径/文件名
参数
-n:显示所查找的内容
-v:显示除了所查找的内容之外的所有内容
-c:显示查找内容的行数
-R:查找内容的行数,并标红
Grep只适合查找已知文件内部的内容
Find 查找(查找文件具体的名字)
如果文件不存在,会显示,并且还会显示所查找路径下的所有内容
Find和grep一般合在一起使用
根据文件的名称进行查找
Find + 路径 + -name + 文件名---》显示路径下所有查找的同名文件
查找命令具体的用法: man 1 命令名称
Chmod
更改文件的权限/文件夹的权限
Chmod + 权限 + 文件名
1+3+3+3
1:文件的属性
b:块设备文件
c:字符设备文件
d:目录文件
-:普通文件
l:链接文件
s:套接字文件
p:管道文件
第一个3:用户组的权限rwx ---》111
第二个3:用户的权限rwx--》111
第三个3:其他用户组的权限r-x--》101
111文件夹的权限:775
一个文件夹最大的权限是d rwx rwx rwx--->777,但是新建一个文件夹的权限是775,因为有文件掩码的存在,用最大权限-文件掩码 = 新文件夹的权限
新建一个文件的权限是664,因为文件夹的最大权限是777-文件掩码,得出来的文件夹的权限,给奇数位减1,偶数位不变,得到的就是文件的权限。
文件掩码存在的意义:不让初始的文件夹权限过大
文件夹的权限一般给775,文件的权限一般给664
绿色文件不仅是可执行文件,权限最高的文件也是绿色,命令也是绿色
数字标记法
Chmod + 权限 + 文件名 权限:000~777,但是文件的权限要给奇数位减1,所以是666
字符标记法
用户:u
用户组:g
其他用户组:o
所有:a
Chmod u+x 1.c --->给用户增加可执行的权限
Chmod a-r 1.c ---> 给所有用户都取消可读的权限
Tar
C:打包
X:解包
V:可视化
F:指明打包的文件名
J:调用打包工具为bzip2
Z:调用打包工具居委gzip
Tar -cvf 1.tar 1.c 打包
Tar -xvf 1.tar -C 路径 解包到指定路径
Tar -cvzf 1.tar.gz 1.c 打包并用gzip压缩
Tar -xvzf 1.tar.gz -C 路径 用gzip解压缩
Tar -cvjf 1.tar.bz2 1.c 打包并用bzip2压缩
Tar -xvjf 1.tar.bz2 -C 路径 用bzip2解压缩
Ln
创建软硬连接
软连接 ln -s 源文件(绝对路径/相对路径) 目标文件
硬链接 ln 源文件(绝对路径/相对路径) 目标文件
软连接文件相当于一条指向源文件的路径,inode不一样,是两个文件
硬链接文件相当于给源文件起了别的名字,但是都属于同一个文件,因为源文件和硬链接文件的inode一样。
环境变量env
在命令行提示符输入env,会出现当前的环境变量类似于makefile里面的CC=gcc
取某一个变量具体的值,但是要加上echo,echo(命令)相当于C语言里面的printf(库函数)(输出)
更改环境变量
./是指明可执行文件所处的位置
如果不加./,那么就会去PATH所添加的路径当中寻找一个叫a.out的可执行文件
此时就是用a.out来执行代码,需要更改PATH
更改PATH
- 临时修改( 绝对路径修改)Export PATH=/home/linux/23091:${PATH}--->${PATH}
临时修改实在某一个终端上进行的,取消临时修改只需要关闭修改过的终端 - 永久修改
修改配置文件
拉到最后一行,添加临时修改PATH的命令
再修改的终端上查看PATH,不会显示修改后的结果,但是重新打开终端之后,PATH会变成修改过的PATH
取消永久修改
Vi ~/.bashrc ,然后删除添加的临时修改的语句
软转义和硬转义
对于env来讲(PWD)
软转义:输出特定字符内部的内容“${PWD}”--->两个意义相同,都输出/honme/linux
硬转义:输出特定的字符‘${PWD}’ echo ‘$PWD’---->${PWD}/$PWD
对于带有特殊含义的字符
硬转义:需要给输出的字符加上单引号,输出的内容就是单引号引起来的内容(不管所写的字符有没有特殊含义,都会原样输出单引号内部的内容)
软转义:加上双引号或者什么都不加,对于字符,会输出字符所代表的特殊含义
对于普通的字符串
软转义(不带引号)
软转义(带双引号)
硬转义
对于硬转义,单引号里面是什么,就输出什么
特殊字符
通配符
*:匹配任意符合要求的长度
?:匹配符合要求的一个长度
[abc]:匹配中括号内部符合要求的一个长度
[^abc]:匹配除了符合要求之外的其他文件(一个长度)
管道
|
Command 1 | command 2 | ......| command n
将管道前的一个命令的输出,当作后一个命令的输入
Sudo apt-get install cowsay/fortune-zh
Fortune-zh是将古诗输出到终端上,但是现在需要将它输出到牛里面。
先将古诗输出,然后作为输入给牛,就需要用到管道
在.c文件内部去查找printf语句
- 找.c文件 find ./ -name *.c
- 查找printf语句 grep -n “printf”
- 两个命令通过管道结合
不出现结果的原因:
管道是将前一个的输出,当作后一个的输入,但是grep不需要输入,需要的是参数
Xargs----》将前一个的输出格式化成一行,当作参数传递给后一个命令
Find ./ -name student.c 这个得到的是一个具体的文件名字,然后通过 | 传递给grep的时候,这个文件被当做输入了,输入具有不确定性,但是grep需要一个具体的文件名,所以将find找到的结果,通过xargs转换成参数,然后通过管道传递给grep
命令置换
``命令置换的符号
Command1 `command2`
将后一个的输出当作前一个的参数
加上管道和命令置换,如果要查找*.c文件,需要去掉-name
命令置换和管道的区别
Ls是将当前目录下的文件显示在终端上,加上管道将这些内容全部当作输入给wc -l,也就是说wc -l统计ls展示出来的结果里面的行数,将ls显示出来的文件,每一个文件名当作了单独的一行然后进行统计,统计出来21行(这个命令相当于给wc了21个字符串去统计行数)
Wc -l实现统计文件的行数,ls显示当前路径下的内容,通过命令置换将ls的结果当作参数一个一个给wc -l,让wc -l去统计ls显示出来的每一个文件的行数(将每一个文件都给wc统计一遍)
重定向
标准输入:stdin
标准输出:stdout
输入重定向:<
输出重定向:>
一般不使用输入重定向
为什么需要使用输出重定向?
将文件的内容可以快速的输入到另一个文件当中
>:目标文件不存在会创建,如果源文件不存在并且目标文件有内容,会清空目标文件(覆盖)
>>:追加模式,每一次重定向之后都会追加到目标文件原文本的后面。如果源文件不存在,使用>>,并不会清空目标文件原本的内容
- :将信息重定向到目标文件,不会出现内容,目标文件不存在会创建。如果源文件不存在,目标文件会存放错误信息
2>>:以追加的方式保存错误信息,正确信息不会覆盖错误信息
&>:保存正确和错误信息,会覆盖
&>>:保存正确和错误信息,会追加
SHELL脚本
bash解释器
解释shell命令,如果不指定解释器,那么shell脚本无法运行
shell脚本的写法
- 先创建一个后缀名为.sh的文件
- 声明解释器,书写代码
- 更改文件的权限为可执行
- 运行
.sh文件第一行只能书写#! /bin/bash
SHELL的基本语法
由shell命令和字符串组成
自定义变量
Shell是一个弱类型,没有数据类型的区分
取变量的值
${变量名} $变量名
位置变量
系统预定义变量
$#
$@
$*
$?
$@,$*:去掉可执行文件之后,剩余的内容
$#:去掉可执行文件之后,剩余的内容的个数
$?:上一行代码的瑞出状态,正常退出0
环境变量
Env查看环境变量
$取环境变量的值
修改方式:export PATH=路径:${PATH}
SHELL语句和程序
Shell语句:由shell命令组成的
shell程序:由shell语句组成
Shell语句的分类
说明性语句
注释 #+注释语句
#! /bin/bash ---》交代解释器的位置
功能性语句
read 相当于C语言的scanf
echo 相当于C语言的printf
算数命令
+ - \* / %
`Expr $a + $b`
Expr是算数命令,只要用到算数命令,就需要加expr
会输出 expr 10 + 20,因为echo要输出一个结果,那么就需要一个参数,将后一个当作参数给前一个命令,需要用到命令置换
Expr 数据1 算术运算符 数据2
四者之间都要用一个空格间隔开
如果要将整体进行赋值,需要加上命令置换,等号两边不能加空格
测试命令
以n1 和n2为例
测试命令的写法有两种
&&与命令表
||或命令表
Test n1 n2
[ n1 n2 ] --->数据和中括号之间必须要用空格间隔
测试整形
大于:n1 gt n2
大于等于:n1 ge n2
等于:n1 eq n2
小于:n1 lt n2
小于等于:n1 le n2
不等于:n1 ne n2
测试字符串
等于:n1 = n2
不等于:n1 != n2
字符串长度是否为零
字符串长度是否不为零
测试文件
普通文件: -f n1
目录文件:-d n1
链接文件:-L n1
测试可读:-r n1
测试可写:-w n1
测试可执行
测试存在并且长度不为零
测试n1是否比n2新 n1 -nt n2
测试n1是否比n2旧 n1 -ot n2
逻辑语句
与:and
或:or
Test n1 and n2
Test n1 or n2
[ n1 -a n2 ]
[ n1 -o n2 ]
结构性语句
结构特性语句和测试命令一般同时使用
1.
If 命令
then
命令表
Elif 命令
Then
命令表
。。。
Else
Then
命令表
fi
输入一个字符串,判断字符串是否存在,如果存在,判断是普通文件还是目录文件,如果是普通文件,先给这个普通文件的所有用户加上可执行的权限,并且输入一句话。如果是目录文件,在该目录下创建一个名为test.txt的文本文件,并输入一句话
文件名一定是一个字符串,判断文件是否存在,用-n
判断文件是否存在并且长度不为零
一个字符串可能是文件名,也可能是普通的字符串,首先要判断字符串是否存在,然后在字符串存在的基础上,判断这个字符串到底是文件名还是文件夹名
Case
Case 变量 in
模式)
命令表
模式)
命令表
模式)
命令表
模式)
命令表
.........
Esac
一个测试条件,只不过测试内部的条件要成立
两个测试,但是两个测试的条件都要成立
Case的参数只能是整数,并且经过算术运算之后,会自动取整
For
for 格式 in 格式表
do
命令表
Done
Seq的方式,可以给i的起始位置和结束位置来进行输入(read)
换成位置变量也可以,因为$a $b是从键盘获取值,而$1 $2是从命令行提示符传递的参数
While
while 命令
Do
命令表
Done
当while的测试命令为真,或者直接写true,那么while就是一个死循环。
找水仙花数
SHELL函数
SHELL函数也是函数,但是SHELL是一个弱类型,没有数据类型的区分,所以SHELL
函数没有形参
add()
{
Echo “aaaa”
Echo “bbbb”
}
如何获取shell函数的值?
- 命令置换Value=`add 参数1 参数2 ......参数n`
位置变量也是输入,只不过实在运行脚本的同时取给函数一个固定的值
Read输入,实在脚本运行途中,给函数固定的值
- 直接调用
Add 参数1 参数2......参数n
命令置换和直接调用输出时候的区别
命令置换将输出格式化成一行,当作参数传递给前一个,所以函数的调用结果显示的是一行,而直接调用显示的是三行