一.shell编程基础
1.本质:shell命令的有序集合
2.特点:减轻管理员的工作量,提高处理文本文件的速度
3.shell是解释性语言,故shell脚本不需要编译,
4.cat /etc/shells 表示查看当前系统支持的解释器 echo $SHELL 表示查看当前系统默认解释器,
shell编程的步骤:
新建shell文件 → 更改文件权限 执行文件
5.shell 变量:
1.用户自定义变量:
①以数字、字母、下划线组成,不能以数字开头。
②最好能够见名知意。
③变量前不需要数据类型
④变量后面不需要以分号结束。
⑤变量在使用的时候不需要定义可以直接使用。
⑥变量在赋值的时候后面不能有空格。
⑦变量赋值的时候默认都是字符串。
⑧变量在使用的时候要加$符号。
2.位置变量,命令行参数
$0:脚本的文件名
$1-9:表示第一个到第九个命令行参数
3.预定义变量
$#:命令行参数的个数
** ∗ ∗ @ / **@/ ∗∗@/*:包含所有的命令行参数
$?:上一个命令退出状态 正产退出返回0
$$:正在执行进程的ID号
4.环境变量
HOME:列出用户的主目录
PATH:shell的搜索路径
二.字符串的相关操作
1.字符串的拼接
!/bin/bash
var1="Hello"
var2="world"
var3="$var1 $var2"
echo $var3 //Hellow world
2.字符串的拷贝
!/bin/bash
var1="Hello"
var2=$var1
echo $var2 //Hellow
3.求字符串的长度
!/bin/bash
var1="Hello"
echo ${#var1} //var1是变量名,无需加$ 结果为5
4.提取字符串
(1)${str:start:len}:表示start位置开始,向后提取len长度的字符
(2)${str:start}:表示从star位置开始提取到末尾
(3)${str:0-start:len}:表示从右侧向左侧寻找start的位置,向后提取len长度的字符
(4)${str:0-start}:表示从右侧向左侧寻找start的位置,向后提取到末尾
(5)${str#*sub}:表示从左侧向右侧寻找第一次出现sub的位置并将sub后的所有字符显示出来
(6)${str##*sub}:表示从左侧向右侧最后一次出现sub的位置并将sub后的所有字符显示出来
(7)${str%sub*}表示从右侧向左侧找第一次出现sub的位置并将sub左侧所有字符显示出来
(8)${str%%sub*}表示从右侧向左侧最后一次出现sub的位置并将sub左侧的所有字符显示出来
注:#左%右双最后
三.Shell数组
1.数组的声明
Shell只支持一维数组,且数组成员默认为字符串
在Shell数组中,无需声明数组大小(不需要指定元素个数)
arr=(1 2 3 4 aaa hello)
arr[n]=6 //表示将数组的下标为n的成员赋值
2.数组成员的访问
${arr[*]}/${arr[@]} //表示访问数组所有成员
${arr[n]} // 表示访问数组下标为n的成员
${#arr[*]} //表示获取数组中已经被赋值成员的个数
${#arr[n]} //表示获取数组下标为n的成员的长度
unset arr // 清除数组
unset arr[n] //清除数组中下标为n的成员
Shell的功能语句
(1).说明性语句
# 注释一行
:<<EOF EOF #表示范围的注释。注释EOF之间内容
:<<! ! #表示范围的注释。注释EOF之间内容
注意:EOF要配套使用,不能单独使用!
(2).功能性语句
echo 自带换行功能
-n 不换行
-e 表示特殊的转义输出
read 表示从终端输入
read var var1 var2 多个输入
-s 静默输入,即不在终端显示输入内容
-t time 限制输入的时间
-p "input"表示提示的作用 表示在终端上显示提示的内容
-n 变量名 表示限制输入的长度
-a 数组名 表示从终端输入数
test 表示测试 测试对对象: 字符串 整数 文件属性
字符串:test s1 = s2 表示测试s1字符串和s2的字符内容是否一致(一致返回0,不一致返回1)
test s1 != s2 表示字符串之间是否有差异
test -z 表示测试字符串的长度是否为零
test -n 表示测试字符串的长度是否为零
整数 a -eq b 表示测试两整数是否相等
a -ne b 表示测试两整数是否不相等
a -gt b 表示整数a是否大于b
a -ge b 表示整数a是否大于等于b
a -lt b 表示整数a是否小于b
a -le b 表示整数a是否小于等于b
文件 -d 文件名 测试是否是目录文件
-e 文件名 测试文件是否存在
-f 文件名 测试文件是否为普通文件
-L 文件名 测试文件是否为链接文件
-r(w/x) 文件名 测试文件是否具有读(读、执行)的权限
-s 文件名 测试文件是否存在,且长度是否为 0
文件名 -nt 文件名 测试文件1是否比文件2更新
文件名 -ot 文件名 测试文件1是否比文件2更旧
四.shell中的运算
1.运算
+,-,*,/,%
shell中被赋值的都是字符串所以不能直接进行算数运算。如果想要完成算数运算,必须使用特殊的标识来完成。
1.(())
((表达式1,表达式2,表达式3))
执行最后一个表达式
2.$[]
一般执行幂运算
$[3**2] 表示算3的2次方
2.expr
①expr可以将结果主动打印出来。
②expr在运算的时候要加上空格。
③expr在引用变量的时候要加上$.
④expr如果将expr的结果赋值给变量的时候要加命令置换。(命令置换在esc按键下的位置)。
⑤expr不支持自加和自减运算
⑥expr在使用乘法运算的时候必须加上转义符号(*).
⑦expr执行不了幂运算。
2.结构性语句
(1).条件语句
if 条件表达式
then
命令表 #(条件为真时执行)
fi #if与fi相当于将要运行代码的括号,必须配对使用
如果条件表达式的结果为真就执行命令表中的内容,如果为假就不执行。
if和fi相当于两个括号将要运行的代码括起来,所以if和fi必须配对使用。
命令表中的命令可以是一条也可以是多条。
形式2
if 表达式
then
命令表1
else
命令表2
fi
形式3
if 表达式1
then
命令表1
elif 表达式2
then
命令表2
fi
形式4
if 表达式1
then
命令表1
else if 表达式2
then
命令表2
fi
fi
练习:判断一个文件是否是普通文件,如果是普通文件则判断该文件是否有写的权限,如果有写的权限直接写入"hellowrold",
如果没有写的权限则,给该文件加上写的权限后再写入"hellowrold".
#!/bin/bash
if test -f $1
then
if test -w $1
then
echo "hellowrold" > $1
else
chmod 0777 $1
echo "hellowrold" > $1
fi
fi
(2).多路分支语句
case....esac #用于多条件测试
case 字符串变量 in
模式1) 命令表1;;
模式2) 命令表2;;
模式3 |模式4) 命令表3;;
[8-8][0-9]) 命令表4;; #表示范围性的匹配(80-89)
*)命令4;;
esae
注意:(1)case值检测字符串
(2)可匹配多个模式,用|隔开
(3)命令表以;;结束,退出case语句,最后一个;;可省略
(4)字符*匹配其他所有格式
(5)case与esac配套使用
练习:从键盘输入一个成绩,打印对应的等级。
#!/bin/bash
read i
case $i in
100) echo "S";;
[9][0-9]) echo "A";;
[8][0-9]) echo "B";;
[7][0-9]) echo "C";;
[6][0-9]) echo "D";;
*) echo "E";;
esac
(3).循环语句
while....do...done
while 命令表达式
do
命令表
done
#先判断表达式的真假,如为真,执行循环体内容,若为假,则退出循环
练习:猜数字的小游戏
num=$[RANDOM%100]
#!/bin/bash
num=6
num1=$[RANDOM%100]
while test $num -gt 0
do
read younumber
if test $younumber -gt $num1
then
echo "big"
fi
if test $younumber -lt $num1
then
echo "small"
fi
if test $younumber -eq $num1
then
echo "good"
exit
fi
num=`expr $num - 1`
done
注意:do与done配套使用
for...do...done
for 变量名 in 单词表
do
命令表
done
当循环次数已确定或者已知的时间用for循环来多次执行一条或者一组命令。
变量依次取单词表中各个单词每取一次就执行一次循环体的内容,循环体执行的次数是由单词表的个数决定的。
seq序列
seq 首数 增量 尾数 //seq 1 1 100 表示从1开始,每次加1 加到100
seq 首数 尾数 //seq 1 100 也表示从1开始每次加1加到100
seq 尾数 //seq 100 表示从1开始每次加1加到100
for i in 单词表
do
for j in 单词表
do
命令表
done
done
练习:打印99乘法表
#!/bin/bash
for i in `seq 9`
do
for j in `seq $i`
do
echo -n -e "$i*$j=`expr $i \* $j`\t"
done
echo
done
练习:求当前目录下的普通文件的数量。
循环控制语句:
break:在shell脚本中,表示跳出本层循环。
break n:表示跳出n层循环
continue:
continue语句则马上转到最近一层循环语句的下一轮循环上,
continue n则转到最近n层循环语句的下一轮循环上.
#!/bin/bash
for i in `seq 3`
do
for j in `seq 3`
do
echo $i $j
continue 2
done
echo
done
//结果
1 1
2 1
3 1
(4).shell函数:
在shell中常常把要多次使用且完成固定功能的一组命令封装在一个函数里面,当要使用该功能的时候就调用该函数就可以。
- 函数在调用之前必须要先定义。
- 调用程序可以传递参数给函数。
- 函数只能在当前shell中有效不能输出到子shell中。
shell函数的定义形式:
function 函数名(){
语句序列
}
注意:
1.shell函数没有数据类型
2.shell函数没有返回值类型
3.shell函数没有参数列表
4.shell函数使用的变量默认是全局变量
5.用local修饰的变量是局部变量。
函数的调用:
函数的调用直接就是函数名。
方式:
1.
#!/bin/bash
function add(){
sum=$((10+10))
}
add
echo $sum
2.
#!/bin/bash
function add(){
sum=$[$1+$2]
}
add 10 20
echo $sum
3. //bash demo17.sh 23 45
#!/bin/bash
function add(){
sum=$[$1+$2]
}
add $1 $2
echo $sum
五.C语言
1.gdb调试
1.步骤:1.用gcc对目标文件进行编译的时候加上-g选项
2.gdb ./a.out
2.gdb调试步骤:
(gdb) l :查看文件
p 变量名 表示查看变量
b 行号 表示在相应的行设置断点
n/s 表示单步运行
r 运行代码
info b 查看断点信息
c 恢复运行
help 帮助
q 退出gdb调试
注意:
- 1.在编译的时候一定要加上-g选项。
- 2.只有在代码运行的时候,才可以查看变量的值
- 3.设置断点后程序在指定的行之前停止。
大端存储:地址的高位存数据的低位,地址的低位存数据的高位。
小端存储:地址的低位存数据的低位,地址的高位存数据的高位。
//代码证明系统默认小端存储:
#include <stdio.h>
int main(int argc, char *argv[])
{
int a=0x11223344;
char *p;
p=(char *)&a;
if(*p==0x44)
{
printf("xiao\n");
}
else
printf("da\n");
return 0;
}
2.存储方式
auto,static,register,extern
(1).static:
1.修饰局部变量,延长生命周期。
2.修饰全局变量,限制作用域
3.修饰函数,限制作用域。
(2).extern:
进行外部引用
注意:
- 在外部引用变量的时候一定要是全局变量。
- 在外部引用函数的时候一定要加上函数的数据类型。
3.volatile:
1.防止编译器对变量进行优化
2.直接在内存中读取变量的值,而不是在缓冲区取
volatile int a=5;
a=10;
a=12;//如果不加volatile对a进行修饰,那么编译器将直接把a的值改为12,而不会先改为10,再改为12.
3.指针:
(1).定义:
在C语言当中,内存单元的地址被称为指针。
指针的定义形式:
<存储类型> <数据类型> *<指针变量名>
指针的存储类型是指指针本身的存储类型。
指针的数据类型是指针所指向的变量的数据类型。
(2).指针的运算
实质 就是地址的运算。 指针只能进行关系运算,算数运算,赋值运算。
关系运算:>,<
比较地址的高低。指向地址大的比指向地址小的大。
算数运算
px+n 表示向地址大的方向移动n个数据
px-n 表示向地址小的方向移动n个数据。
px++ 表示向地址大的方向移动一个数据。
px-- 表示向地址小的方向移动1一个数据。
x-py 表示两个指针之间相差元素的个数。(指针必须是同类型的指针,指针必须指向同一空间)
px+n的实际单元的内存量:
px+sizeof(数据类型)n
px-n的实际单元的内存量:
*px-sizeof(数据类型)*n
4.赋值运算;
可以给指针赋值的有:地址、指针,数组名
(1).指针数组:
本质:是数组,数组存放的元素是指针
定义形式:
<存储类型> <数据类型> *<指针变量数组名>[大小]
int *p[3];
(2).数组指针:
本质:是指针,指向数组。
定义形式:
<存储类型> <数据类型> (*指针变量名)[大小]
int (*****p)[3];
多级指针:遇到多级指针的时候画图把他们的关系描述清楚。
const修饰指针:
const修饰指针修饰位置不一样效果不一样。
const int p; //const修饰的是p,所以p的值不能被改变,但是p能改变。
int * const p; //const修饰的是p,所以p的指向不能改变,但是P能改变。
指针数组 | 数组指针 | |
---|---|---|
本质 | 数组 装着指针的数组 | 指针 指向数组的指针 |
理解 | p为指针,指向一个一维数组,数组长度为n | p是一个数组,共n个元素,元素为指针类型 |
定义形式 | int *p1[n] | int (*p2)[n] |
图 | ![]() | ![]() |
5.函数:
(1).定义:
函数是一个完成特定功能的代码模块,通常要求有返回值,也可以空值。
一般定义形式:
<数据类型> <函数名称>(形式参数说明)
{
语句序列;
return ;
}
(2).函数的定义:
<数据类型> <函数名称>(形式参数说明)
{
语句序列;
return ;
}
int add(int x,int y)
{
return x+y;
}
(3).函数的传参:
**复制传递:**就是将实参的值,复制了一份传递给实参,所以改变形参的值相对应的实参的值不会改变。
**地址传递:**就是将实参的地址传递给形参,所以改变形参的值,对应的实参的值也会改变。
练习:写一个函数实现两个数的交换。
#include <stdio.h>
void exchange(int *x,int *y);
int main(int argc, char *argv[])
{
int x=5,y=7;
printf("%d %d\n",x,y);
exchange(&x,&y);
printf("%d %d\n",x,y);
return 0;
}
void exchange(int *x,int *y)
{
int temp=*x;
*x=*y;
*y=temp;
printf("%d %d\n",*x,*y);
}
①指针函数:
本质:是函数,函数的返回值是指针。
返回有效的地址:
- 1.全局变量的地址
- 2.返回传入参数的地址。
- 3.malloc申请的地址。
- 4.static修饰的地址。
定义形式:
int *func(参数列表);
练习:编写一个指针函数,输入一个10进制的数,转换为2进制输出。
#include <stdio.h>
char *ten_to_two(char bit_32[],int number);
void prit(char bitss[]);
int main(int argc, char *argv[])
{
int num;
char bit[32]={0};
scanf("%d",&num);
ten_to_two(bit,num);
prit(bit);
return 0;
}
char *ten_to_two(char bit_32[],int number)
{
int bits=8*sizeof(int);
while(bits >=0)
{
bit_32[--bits]=(number & 1) +'0';
number >>=1;
}
return bit_32;
}
void prit(char bitss[])
{
int i;
int nulkk=0;
for(i = 0 ;i < 32;i++)
{
printf("%c",bitss[i]);
nulkk++;
if(nulkk %4 ==0)
{
printf(" ");
}
}
}
②函数指针
本质:是指针,特殊之处在于指向函数的指针。
定义形式:
<数据类型> (*<函数指针名称>)(<参数说明列表>);
*
*int (*****p)(参数);
数据类型是指针所指向函数的返回值类型。
参数说明列表要和指针所指向函数的参数列表要相同。
eg:
#include <stdio.h>
int add(int x,int y);
int main(int argc, char *argv[])
{
int x=5,y=7;
int (*p)(int x,int y)=add;
printf("%d\n",(*p)(x,y));
return 0;
}
int add(int x,int y)
{
return x+y;
}
③函数指针数组:
本质:数组,数组里面存放的是函数指针。
定义形式:
<数据类型> ( * <函数指针数组名称> [<大小>] ) ( <参数说明列表> );
int (*p[4])(int x,int y);
eg:
#include <stdio.h>
int add(int x,int y);
int sub(int x,int y);
int main(int argc, char *argv[])
{
int x=5,y=7;
int (*p[4])(int x,int y)={add,sub};
printf("%d %d\n",(*p[0])(x,y),(*p[1])(x,y));
return 0;
}
int add(int x,int y)
{
return x+y;
}
int sub(int x,int y)
{
return x-y;
}
指针函数 | 函数指针 | ||
---|---|---|---|
本质 | 函数 函数的返回值是指针 | 指针 指向函数的指针 | 数组 存放的是函数指针 |
理解 | func1是函数,函数的返回值为 int *型 | 指向func3型函数的指针 | func2是一个数组,数组袁术为3个指向函数的指针, 指针的返回值为 int型 |
定义形式 | int *func1(int tx,int y); | int (*func3)(int x,int y); | int (fun2p[3])(int x,int y) |
图 | ![]() |
④递归函数:
递归函数是指在改函数体中直接调用,或者间接调用了该函数本身的函数。
eg:
#include <stdio.h>
int func(int x);
int main(int argc, char *argv[])
{
int a;
scanf("%d",&a);
int sum=func(a);
printf("%d\n",sum);
return 0;
}
int func(int x)
{
if(x <=2)
{
return x;
}
else
return x*func(x-1);
}
练习:有n层阶梯,一次可以走1一个阶梯或者两个阶梯,问一共有多少种走法。
#include <stdio.h>
int func(int num);
int main(int argc, char *argv[])
{
int n;
scanf("%d",&n);
int sum=func(n);
printf("%d\n",sum);
return 0;
}
int func(int num)
{
if(num <=2)
{
return num;
}
else
return func(num-1)+func(num-2);
}
⑤回调函数:
定义:回调函数就是通过函数指针调用的函数。
#include <stdio.h>
int Callback_1() // Callback Function 1
{
printf("Hello, this is Callback_1\n ");
return 0;
}
int Callback_2() // Callback Function 2
{
printf("Hello, this is Callback_2\n ");
return 0;
}
int Callback_3() // Callback Function 3
{
printf("Hello, this is Callback_3\n ");
return 0;
}
int Handle(int (*Callback)())
{
printf("Entering Handle Function\n ");
Callback();
printf("Leaving Handle Function\n ");
}
int main()
{
printf("Entering Main Function\n ");
Handle(Callback_1);
Handle(Callback_2);
Handle(Callback_3);
printf("Leaving Main Function\n");
return 0;
}
//结果
Entering Main Function
Entering Handle Function
Hello, this is Callback_1
Leaving Handle Function
Entering Handle Function
Hello, this is Callback_2
Leaving Handle Function
Entering Handle Function
Hello, this is Callback_3
Leaving Handle Function
Leaving Main Function
理解
void 做面条(int x)//回调函数
{
做x碗面条;
}
void 做米线(int x)//回调函数
{
做x碗米线;
}
void 做蛋炒饭(int x)//回调函数
{
做x碗蛋炒饭;
}
//吃饭函数里面内容不可见,只知道可以实现做几碗我需要的饭
viod 吃饭( int x, void (*做饭)(int) )
{
摆桌子();//吃饭的公有功能函数
做饭(x);
洗碗();//吃饭的公有功能函数
}
void mian(void)
{
吃饭(2,做米线);
玩();
睡觉();
}
回调函数的意义在于,中间函数(库函数)的公有部分可以不必拆出来写到每一个子函数。就上面例子来讲:对于吃饭来说
操作流程都是一样的,没有必要全部把公有部分( 摆桌子()、洗碗() )单独拿出来写到3个不同的吃饭函数。也可以对
应说是中间数吃饭()里面的内容对我们不可见,我们只能将具体做饭函数放入到中间函数去执行。
(4).联合体:union(共用体)
功能:用来节省空间,开发中使用较少。
注意:
- 1.共用体使用同一片内存空间。
- 2.共用体空间的大小是最大的数据类型的大小。
- 3.因为共用一个空间,所以改变一个变量的值会影响其他变量。
- 4.采用内存覆盖技术,同一时刻只能保持一个变量的值,新赋值的变量的值会覆盖前面的变量。
定义形式:
union 类型名{
变量类型 变量名;
变量类型 变量名;
变量类型 变量名;
};
eg:
#include <stdio.h>
union stu{
char a;
int b;
double c;
};
int main(int argc, char *argv[])
{
union stu stu1;
stu1.a='A';
stu1.b=4;
stu1.c=3.14;
printf("%c %d %f\n",stu1.a,stu1.b,stu1.c);
printf("%ld\n",sizeof(stu1));
return 0;
}
(5).枚举:enum
enum 类型名{
变量1,
变量2,
变量,
};
enum week{
mon,
tue,
wend,
thy,
fri,
sta,
sun,
};
枚举变量没有赋值的话,默认是从0开始向后递增(每次加1)。
注意:
mon,tue等都是常量只能将他们赋值给其他变量,不能对他们进行赋值。
eg:
#include <stdio.h>
enum week{
mon=1,
tue,
wen=6,
sfat,
};
int main(int argc, char *argv[])
{
enum week day;
int day1=(int)day;
scanf("%d",&day1);
switch(day1)
{
case mon:printf("a\n");break;
case tue:printf("b\n");break;
case wen:printf("c\n");break;
case sfat:printf("d\n");break;
}
return 0;
}
typedef:重定义(取别名)
typedef int INT 将int改名为INT,所以INT可以表示int
int a 等价于 INT a
eg:
#include <stdio.h>
typedef int INT;
typedef int * INTF;
int main(int argc, char *argv[])
{
INT a=5; //int a=5;
INTF p=&a; //int *p=&a;
printf("%d %d\n",a,*p);
return 0;
}
(6).结构体:
结构体定义类型:
struct 类项名{
变量类型 变量名;
变量类型 变量名;
变量类型 变量名;
};
1.
struct student{
char name[5];
int age;
double score;
};
struct student stu1; //struct student是数据类型
strcpy(stu1.name,"zs");
stu1.age=4;
stu1.score=3.14;
printf("%s %d %f\n",stu1.name,stu1.age,stu1.score);
2.
struct student{
char name[5];
int age;
double score;
}stu1;
strcpy(stu1.name,"zs");
stu1.age=4;
stu1.score=3.14;
printf("%s %d %f\n",stu1.name,stu1.age,stu1.score);
3.
typedef struct student{
char name[5];
int age;
double score;
}STU;
STU stu1; //STU等价于struct student
strcpy(stu1.name,"zs");
stu1.age=4;
stu1.score=3.14;
printf("%s %d %f\n",stu1.name,stu1.age,stu1.score);
结构体的大小:
64位的操作系统默认采用8字节对齐,如果结构体中最大的数据类型超过了默认的字节对齐,那么就采用默认的字节对齐,
如果结构体中最大的数据类型没有超过默认的字节对齐,就采用结构体中最大的数据类型的大小对齐。
修改默认对齐命令:
#pragma pack(4) //将字节默认对齐改为4.
①结构体数组:
直接用结构体类型定义了一个数组。
struct student stu[3];
strcpy(stu[0].name,"lisi");
stu[0].age=16;
stu[0].score=88;
strcpy(stu[1].name,"zs");
stu[1].age=16;
stu[1].score=86;
②结构体指针:
//就是用结构体类型定义了一个指针,这个指针可以指向结构体。
struct student stu1;
struct student *p=&stu1;
strcpy(stu1.name,"zs");
stu1.age=4;
stu1.score=3.14;
printf("%s %d %f\n",p->name,p->age,p->score);
6.Makefile
1.Makefile基础
1.make
命令工具,解释Makefile中的命令或规则
2.工作步骤
当前目录下寻找“Makefile”或"makefile"文件
寻找文件中的第一个目标
检查目标依赖关系,一层一层向下寻找。
生成想要的目标,若存在多目标,则在执行是需加上需求目标
3.Makefile
一个文件对项目进行管理
特点:项目工程变得自动化,无需每次手动输入参数
时间戳
makefile:
all:
@gcc -E lianxi1.c -o lianxi1.i //加上@可不显示执行过程
gcc -S lianxi1.i -o lianxi1.s
gcc -c lianxi1.s -o lianxi1.o
gcc lianxi1.o -o lianxi1
.PHONY: clean // 伪指令 防止产生干扰
clean:
rm lianxi1.i lianxi1.o lianxi1.s
2.多文件编程
makefile文件
main:main.o add.o sub.o
gcc main.o add.o sub.o -o main
main.o:main.c
gcc -c main.c -o main.o
add.o:add.c
gcc -c add.c -o add.o
sub.o:
gcc -c sub.c -o sub.o
clean:sub.c
rm *.o
head.h
#ifndef _HEAD_H
#define _HEAD_H
int add(int x,int y);
int sub(int x,int y);
#endif
main.c
#include <stdio.h>
#include "head.h"
int main()
{
int x=10,y=5;
printf("%d\n",add(x,y));
printf("%d\n",sub(x,y));
return 0;
}
add.c
#include<stdio.h>
int add(int x,int y){
return x+y;
}
sub.c
#include <stdio.h>
int sub(int x,int y){
return x*y;
}
3.变量
作用:节省繁复的操作,方便替换
1.变量的定义
CC=gcc = 普通赋值,获取最后一次赋值的结果
:= 直接赋值,不管变量后是否赋值
?= 询问赋值 已赋值的不在赋值,未赋值的则本次赋值成立
2.变量的引用
$(CC) 默认变量
$(RM)
特殊变量
- $@:目标
- $^:所有的依赖
- $<:第一个依赖
- $*:不包括扩展名的目标文件
CC=gcc
GGGG=main
HHHH=main.o add.o sub.o
JJJJ= -c -o
$(GGGG):$(HHHH)
$(CC) -o $@ $^
main.o:main.c
$(CC) $(JJJJ) $@ $^
add.o:add.c
$(CC) $(JJJJ) $@ $^
sub.o:sub.c
$(CC) $(JJJJ) $@ $^
clean:
$(RM) $(HHHH)
13.Shell命令
3.1常用命令
1.pwd:显示当前终端所在工作目录
2.cd:切换路径
3.ls:显示当前路径下的文件及文件夹
参数-a:显示所有的文件及文件夹,包括隐藏文件
参数-l:显示文件及文件夹的详细信息
参数-i:显示索引号
touch:更新时间戳(创建新文件)
gedit:编辑器
cat:查看文件的内容
rm:删除
rm -rf file(慎用-rf)
Linux下文件类型
d:目录文件
-:普通文件(.c文件、二进制文件、文本文件……)
l:链接文件
p:管道文件
C:字符设备文件
b:块设备文件
s:套接字文件
mkdir -p 目录名 递归创建目录
rmdir:删除目录(目录必须是空的目录)
-p 递归删除目录
rm -r:删除目录
su:切换用户
sudo:临时超级用户权限