文章目录
Linux终端快捷键
快捷键 | 含义 |
---|---|
Tab | 输入一部分命令按可以自动补齐 |
Ctrl+shift+ + | 终端文字放大 |
Ctrl + - | 终端文字缩小 |
Ctrl+L | 清屏 |
一、文件管理
一些通用符号含义
./ | 当前目录(不打点也是当前目录,如cd ./a和cd a) |
../ | 上一级目录(相对路径) |
/ | 根目录(绝对路径) |
* | 所有文件(用于删除、复制、移动等) |
-l | 详细信息(显示目录等) |
文件操作常用命令
命令 | 含义 | 含义 |
---|---|---|
clear | 清屏 | |
pwd | 显示当前所在路径 | |
ls | 查看当前文件夹目录 | |
ls -a | 查看所有文件,包括隐藏文件 | |
ls / | 查看根目录内容 | |
ls -l / | 查看根目录详细信息 | |
ls -l | 查看目录详细信息 | |
ls -l查看的信息中,第一个字母含义:- 普通文件 d 文件夹,b 设备文件(块设备) c设备文件(字符设备) i连接文件 s 套接字文件 p 管道文件 | ||
cd | 跳转目录 | |
cd ~ | 当前用户目录 | |
cd a/b | 跳转到当前目录里a目录下的b目录 | |
cd / | 根目录 | |
cd - | 上一次访问的目录 | |
cd .. | 上一级目录 | |
touch | 创建文件 | |
touch 路径和名字 | 创建文件 | |
touch test | 当前目录创建test文件 | |
touch test/a | 在该目录下的test目录下创建a文件 | |
touch test/a b | 在当前文件的test文件夹下创建a文件,当前文件下创建b文件 | |
mkdir | 创建文件夹 | |
mkdir aaa | 在当前目录下创建aaa目录,相对路径 | |
mkdir -v aaa | ||
mkdir ./bbb | 在当前目录下创建bbb目录,相对路径 | |
mkdir /ccc | 在根目录下创建ccc目录,绝对路径 | |
mkdir -p /home/a/b | 在home下创a,a下创b(需要加-p) | |
mkdir test/{a,b} | 在当前母的的test文件夹创建a,b文件夹 | |
mkdir -pv test/{a/{b,c},d} | 在test下创a,d,在a下创b,c | |
cp | 复制 | |
cp /home/a/b/c /home/a/ | 复制文件 | |
cp -r /home/a/b/c /home/a/ | 复制文件夹(文件夹需要加-r) | |
c -r /home/a/b/* /home/a/ | 复制b下的所有文件到a | |
MV | 移动 | |
MV a/b/c a | a中的b中的c移动到a中去 | |
MV a/b/c a/d | a中的b中的c移动到a中去并改名为d(前提是a中没有d文件夹,有d文件这则移动到a中的d文件夹内) | |
MV a/b a/c | 将a中的b改名为c(前提是a中没有c) | |
rm | 删除 | |
rm -rf a/* | 删除文件a内的所有文件夹和文件 | |
rm -rf a/b* | 删除文件a内的所有b开头的文件夹和文件 | |
rm -rf a/*b | 删除文件a内的所有b结尾的文件夹和文件 | |
rm -rf a/a a/b | 删除a里面的a和b | |
rm -rf bbb | 强制删除当前目录下的bbb目录 | |
rm -r bbb | 询问是否删除bbb目录 | |
rm -rf a.java | 强制删除当前目录下的a.java文件 | |
find | 查找文件 | |
find -name a | 查看a文件夹 | |
find -name a* | 查看a开头的文件或文件夹 | |
find deirectory -name a | 指定目录中查找 | |
cat | 查看文件内容 (重点) | |
cat a.txt | 查看a.txt文件 | |
more | 查看文件内容 (翻页) | |
more a.txt | 查看a文件(按回车键一行一行进行查看, 按空格键一页一页进行查看,q退出) | |
tail | 查看文件后几行 | |
tail -f a.java | 查看文件后10行内容 | |
tail -n 5 a.java | 查看后5行内容 | |
head | 查看文件前几行 | |
head a.java | 查看文件前10行内容 | |
head -n 5 a.java | 查看前5行内容 | |
grep | 过滤,查找内容 | -i忽略大小写,-n标出显示行的列数 |
grep c a.txt | 查看文件a.txt内的包含c的内容 | |
grep -nr “Ubuntu” / | 在整个系统里面查找Ubuntu(包括文件内) | |
> 文件名 | 覆盖写入文件 | ls > a.txt 将查询的结果写入a.txt中 |
>> 文件名 | 追加写入文件 | |
ls > a.txt | 将查询目录的结果写入a.txt中(>前面的内容一定是正常的指令,可有输出的) | |
geidt | 文本编辑器 | |
gedit a.txt | 编辑a.txt | |
du | 文件夹大小 | (-h人类可读的方式显示)du -h --max-depth=1(只显示一级目录文件大小) |
df | 列出文件系统的整体磁盘使用量 | (包含大小,已用,可用等数据) |
| | 管道(将管道左边命令的输出结果作为管道右边命令的输入) | ls -l | more 将显示的内容分屏 |
二、其他指令
命令 | 含义 | 含义 |
---|---|---|
uname | 查看系统信息(加-a详细信息) | |
sudo | 切换用户身份,提权 | |
su | 切换用户 | |
ifconfig | 显示网络配置信息 | |
ifconfig 网卡名 down | 关闭网卡 | |
ifconfig 网卡名 hw enter 00:AA:BB:CC:DD:EE | 修改MAC地址 | |
ifconfig 网卡名 up | 启动网卡 | |
ifconfig 网卡名:ws arp | 启动ARP | |
ifconfig 网卡名:ws -arp | 关闭ARP | |
ifconfig 网卡名 mtu 1500 | 设置最大传输单元 | |
reboot | 重启 | |
poweroff | 关机 | |
man | 系统帮助 | |
man printf | 查看printf含义 | |
sync | 数据同步写入磁盘 | |
df | 磁盘空间检查 | |
ps | 当前系统进程查看命令 | -aux显示所有行程,-au显示较详细咨询 |
top | 进程实时运行状态 | |
file | 文件类型查看 | |
echo | 输出内容 | echo $PATH输出路径 |
三、Ubuntu文件结构
文件路径 | 含义 |
---|---|
/bin | 存放二进制可执行文件,这些指令在单用户模式下也能够使用,可以被root和一般的账号使用 |
/boot | Ubuntu 内核和启动文件,比如 vmlinuz-xxx。gurb.引导装载程序 |
/dev | 设备驱动文件(ls sd*可以查看U盘,从这进行装载) |
/etc | 存放一些系统配置文件,比如用户账号和密码文件,各种服务的起始地址 |
/home | 系统默认的用户主文件夹,一般创建用户账户的时候,默认的用户主文件夹都会放到此目录下 |
/lib | 存放库文件 |
/media | 此目录下放置可插拔设备,比如 SD 卡,或者 U 盘就是挂载到这个目录中 |
/mnt | 用户可使用的挂载点,如果要挂载一些额外的设备,那么就可以挂载到此处 |
/opt | 可选的文件和程序存放目录,给第三方软件放置的目录 |
/root | root 用户目录,也就是系统管理员目录。 |
/sbin | 和/bin 类似,也是存放一些二进制可执行文件。sbin下面的一般是系统开机过程中所需要的命令。 |
/srv | 服务相关目录。比如网络服务 |
/sys | 记录内核信息,虚拟文件系统 |
/tmp | 临时目录 |
/var | 存放一些变化的文件,比如日志文件 |
/usr | usr 不是 user 的缩写,而是 UNIXSoftware Resource 的缩写,存放于系统用户有关的文件,会占用很大的存储空间!“ |
/proc | 虚拟文件系统,数据放置到内存中,存放系统运行信息 |
四、用户基本信息
指令 | 作用 |
---|---|
cat | 显示文件内容 |
cat /etc/passwd | 查看用户基本信息 |
cat /etc/shadow | 查看用户密码信息 |
cat /etc/group | 查看组信息 |
cat user01 /etc/passwd | 查看user01用户基本信息 |
ls /home/ | 查看用户,创建了user01就有user01文件 |
id user01 | 用户user01存在则显示详细信息,不存在则提示没有 |
ls /var/spool/mail/user01 | 用户邮件 |
whoami | 查看当前账户 |
grep hr /etc/group | 查看组名包含hr的信息 |
用户基本信息
文件:cat /etc/passwd
,被冒号分成七列,同户名:x:uid:gid:描述:HOME:shell
,每一行是一个用户信息
列数 | 含义 |
---|---|
x | 密码占位符 |
uid | 用户的身份证号(系统约定:RHEL7,uid:0特权用户,uid:1~499系统用户,uid:1000+普通用户) |
gid | 组号 |
描述 | 解释 |
HOME | 家目录,登入系统时,所在的目录 |
shell | 登入shell,命令解释器 |
用户密码信息
(经过了加密)文件:cat /etc/shadow
,被冒号分成九列,最后一列没意义
列数 | 意义 | 含义 |
---|---|---|
1 | 用户名 | |
2 | 密码加密值 | *表示被锁定,双汉号表示密码过期,$6$开头表示用SHA-512加密,$1$用MD5解密,$2$用Blowfish加密,$5$用SHA-256加密 |
3 | 最后一次修改时间 | 从某个时间至今天数 |
4 | 最小间隔 | 3表示过3天可改密码 |
5 | 最大时间间隔 | 密码有效期 |
6 | 警告时间 | 提示还有多久密码过期了 |
7 | 不活动时间 | 用户不登入系统天数,超过时间没登入则禁用 |
8 | 失效时间 | 账户的有效期,到了失效时间账户失效 |
9 | 保留 | 什么意思都没有 |
组信息
文件:cat /etc/group
,被冒号分成四列,root: x:0:
,组名:组密码:组ID:组成员
4.1 用户管理
图形化创建要安装:sudo apt-get install gnome-system-tools
(这里不介绍图像化操作)
用户在这个组,可以访问这个组内信息文件,可以共用空间,但不能访问其它组内信息文件(不在此组)。每个用户可以属于多个不同的组
#开头是超管用户(root用户),才可以创建用户等操作,$为普通用户没创建用户等操作能力
用户
指令 | 作用 |
---|---|
finger user01 | 用户查询 |
useradd user01 | 创建user01用户(-u指定组,-d /user01指定家目录为user01,) |
adduser user01 | 创建user01用户(设置密码等信息) |
passwd | 修改当前账户密码(普通用户只能修改自己的,超管可以改其他账户) |
passwd user01 | 修改user01用户密码(密文输入,输入看不到,无显示) |
userdel -r user01 | 删除用户user01(不加-r删除后还保存文件) |
usermod -s /sbin/nologin user01 | 修改用户属性,用户不能登入 |
usermod -s /bin/bash user01 | 修改用户属性,用户可以登入 |
组
一个用户有一个基本组(随用户而创建,一般组名用用户名),可以有多个额外加入的组为附加组(用户额外加入的组)
指令 | 作用 |
---|---|
groups user01 | 查看user01用户在哪些组里面(显示格式:用户:组名 ) |
usermod -g user01 group01 | 修改user01的基本组 |
usermod -G group01 user01 | 修改user01的附加组(加-a添加不替换 ) |
usermod -a -G group01 user01 | 给用户user01添加group01组 |
groupadd hr | 创造hr组(创建成功提示var/spool/mail/root中有邮件)(-u指定用户UID,-g指定用户的基本组,-G指定用户的附加组) |
groupdel hr | 删除组 |
gpasswd -d A GROUP | 把用户A从GROUP组内移除 |
groupmod -g 1001 | 修改组ID |
su - root | 提权(进入root后exit退出root账户)(像root一样使用命令,但不是root) |
sudo useradd user01 | 提权(在普通用户下加个sudo才可以拥有root的权限执行命令,否则不能) |
# 举例
用户AA,基本组1508,附加组空
用户BB,基本组1509,附加组空
组CC,组号1510,和谁都没关系
usermod AA -g CC
执行上述指令后,用户AA,基本组1510,附加组空
usermod BB -G CC
执行上述指令后,用户BB,基本组1509,附加组1510
CC组有两个成员,一个AA,一个BB
案例
先创建个用户user01,user02
adduser user01,adduser user02
cat /etc/passwd
创建用户后会自动生成两个组,指令格式:groups 用户名
,显示格式:用户名:组名
再创建个用户组group01,group02,此时里面都没有用户
addgroup group01,addgroup group02
cat /etc/group
将用户user01从user01组移动到group01组,显示格式:用户名:组名
给用户user01添加个附加组,如果没有则添加,如果有则替换(加-a参数则是添加,不是替换,即usermod -a -G group01 user01)(刚开始没有附加组,直接添加,后来有附加组,没加-a参数,则替换,后来加了-a参数,再添加个附加组)
将用户user01从group02中移除
使用指令sudo deluser user01
删除用户user01
使用指令sudo delgroup group01
删除用户组group01
五、文件所属与权限
5.1 文件权限
文件状态:r为可读(r=4),w为可写(w=2),x为可执行(x=1)
(可执行文件
在命令行中运行./文件名就可以运行,比如,编写一个hello.c文件,运行gcc hello.c -o hello
就会生成一个可执行文件,然后运行./hello即可运行)
使用ll查看文件,可以在左边看到文件的权限,左边方框内有10列,第一列表示文件类型,后面分为三个三组,第一组(2-4)用户权限
,第二组(5-7)用户组内成员权限
,第三组(8-10)其他用户权限
比如某文件显示如下 - rw-
rw-
r--
:表示当前用户可读写无可执行,组内其他用户可读写无可执行,其他用户可读无可执行
上面方框后面数字后的两个a,第一个表示a用户,第二个表示a用户组
文件权限修改
可以用二进制形式修改文件权限,可读为4(100),可写为2(010),可执行为1(001)
指令格式:chmod 参数 文件名
比如我们将b.txt权限改为可读可写可执行,则运行chmod 777 b.txt
指令,如下图
也可以用字母形式修改权限
字母 | 含义 |
---|---|
r | 可读权限 |
w | 可写权限 |
x | 可执行权限 |
a | 所有用户 |
u | 归属用户 |
g | 归属组 |
o | 其他用户 |
= | 具备权限 |
+ | 添加权限 |
- | 移除权限 |
格式:chmod u/g/o/a+/-/=rwx
一定要注意格式顺序,先用户群体,再添加或删除,最后权限
比如我们将a.txt文件禁止组内其他用户编写,组内其他用户则是g(第二组),写为w,移除为-,则组合就是chomd g-w a.txt
5.2 修改文件所属用户
比如我们将a用户下的a.txt改到root用户当中sudo chown root a.txt
将a.txt的用户组有a改为root用户组sudo chown .root a.txt
同时修改a.txt属与a用户和a用户组sudo chown a.a a.txt
如果要将某文件内所有文件修改所属用户与用户组,则执行如下指令sudo chown -R 用户.用户组 文件夹名
六、软件安装
1、在应用商店下载
2、使用指令安装
(apt工具):
sudo apt-get install 包名,如:sudo apt-get install git,再如sudo apt-get install mplayer(视频播放工具)
3、使用deb安装
:
首先在某网站官网下好安装包,即deb文件,相当于Windows下的exe,然后执行上面指令(在windows下,安装的是.exe文件,在Ubuntu中,安装的是.deb文件)
然后执行下面指令使用deb安装:sudo dpkg -i xxx.deb
(卸载:sudo dpkg -r xxx
)
桌面上没有图标,我们在usr/share/applications目录下可以看到应用程序的桌面图标
4、自己下载源码编译
以tree为例,在网址下载:mama.indstate.edu/user/ice/tree
下载之后,该文件里面有操作步骤文档(install文件)
终端进入该文件夹
首先执行make,然后执行sudo make install下载完成
(执行不带sudo会提示permission没权限,需要嗲sudo)
(ubuntu里面要拥有make,gcc工具,没有则要下载)
安装好了之后,可以运行tree查看
七、磁盘管理(U盘)
/dev/sd*文件,此类文件是磁盘设备文件,并不能直接访问磁盘,必须要将磁盘挂载到某一个目录下才可以访问
插上U盘后,可以在dev中查看U盘,在插U盘前后分别查看cd /dev,ls sd*,如下图可以看到有sdb和sdb1,sdb表示U盘,sdb1表示U盘的第一个分区
注:U盘要用FAT32格式的(在右击属性中可以查看),linux大部分系统都不支持NDFS格式的U盘
U盘挂载与卸载
插上U盘后,如果没有默认挂载,可以查看到文件,但是cd进不去(如上cd sdb1),需要挂载之后才可以进去,这种情况下需要我们手动挂载
先在/media/a里面创建一个udisk用于挂载U盘
然后执行sudo mount -o iocharset=utf8 /dev/sdb1 /media/a/udisk进行U盘挂载
,挂载成功后,media/a/udisk里面就有U盘的内容(-o iocharset=utf8防止中文乱码)
执行sudo umount /media/a/udisk进行U盘卸载
,后面是磁盘路劲,卸载后,此处就没有U盘内容
磁盘分区格式化
显示磁盘分区:sudo fdisk -l
sudo fdisk /dev/sdb,然后输入m获取帮助,然后按提示可以创建分区、删除分区(U盘处于挂载状态无法删除)等操作,操作完成之后输入w进行保存
使用sudo mkfs -t vfat /dev/sdb1进行格式化
八、压缩与解压
linux下常用的压缩格式有.tar,.tar.bz2,.tar.gz。因为linux下很多文件是.bz2,.gz的压缩文件,因此需要在windows下安装7.ZIP软件
指令 | 含义 | |
---|---|---|
gzip压缩工具 | 负责压缩和解压缩.gz格式的压缩包 | |
gzip xxx | 压缩文件(压缩后原文件没了 ) | |
gzip -d xxx.gz | 解压缩 | |
gzip -r xxx | 压缩文件夹(批量对文件夹里的文件压缩,并不是将这个文件夹打包压缩成一个 ) | |
gzip -rd xxx.gz | 解压文件夹 | |
bzip2 | 和gzip类似(效果一样),只负责压缩和解压bz2格式文件 | |
bzip2 -z xxx | 压缩文件(压缩后原文件没了 ) | |
bzip2 -d xxx.gz | 解压 | |
tar | 提供打包服务,多个文件打包成一个(-c打包,-x提取,-j使用bzip2压缩格式,-z使用gzip格式,-v打印压缩过程) | |
tar -vcf a.tar a | 将文件夹a打包成a.tar | |
tar -vxf a.tar | 解压 | |
tar -vxjf xxx.bz2 | 解压 | |
tar -vcjf xxx.bz2 xxx | 压缩 | |
tar -vxzf xxx.tar.gz | 解压 | |
tar -vczf xxx.tzr.gz xxx | 压缩 | |
rar | 安装:sudo apt-get install rar | |
rar x xxx.rar | 解压缩(加x参数) | |
rar a xxx.rar x | 压缩(加参数a) | |
zip | zip格式(-r文件夹压缩,-v显示过程) | |
zip -rv xxx.zip zip | 压缩 | |
unzip xxx.zip | 解压 |
九、连接文件(硬连接、软连接)
连接方式分为符号连接(软连接)和硬连接,符号连接类似于Windows下的快捷方式,硬连接通过文件系统的inode连接来产生新的文件名,而不是产生新文件。
inode:记录文件属性,一个文件一个inode。inode相当于文件ID,查找文件的时候要先找到inode,然后才能读取文件内容
ln命令
ln命令用户创建链接文件
命令格式:ln [选项] 源文件 目标文件
选项:-s创建符号连接(软连接)
-f强制创建链接文件,如果目标存在,那么先删除目标文件,然后再建立文件
硬连接
硬连接是多个文件都指向同一个 inode,硬连接知识点:
1、具有相同inode 的多个文件互为硬连接文件,创建硬连接相当于文件实体多了入口
2、对于硬连接文件,只有删除了源文件以及对应的所有硬连接文件,文件实体才会被删除
3、根据硬链接文件的特点,我们可以通过给文件创建硬连接的方式来防止文件误删除
4、不论修改源文件还是连接文件,另一个文件的数据都会被改变。
5、硬连接不能跨文件系统。
6、硬连接不能连接到目录
举例
:
原先只有一个hello可执行文件,利用ln hello hello1
和ln hello hello2
建立两个硬连接(ll -i
查看inode),运行./hello
、./hello1
、./hello2
都可以运行
此时我们将源文件hello
删除,./hello1
和./hello2
通用可以正常运行,删除原文件对其毫无影响,如果要删除,需要把连接和原文件都删除,即hello
,hello1
,hello2
再如,我们对hello.c建立连接,查看内容是一样的
我们对hello.c进行修改保存,可以发现hello1.c也跟着发生了变化
符号连接(软连接)
符号连接类似Windows 下的快捷方式
,符号链接也叫做软连接,软连接要用的多。符号连接相当于创建了一个独立的文件,这个文件会让数据读取指向它连接的哪个文件的文件名。软连接的特点:
1、可以连接到目录。
2、可以跨文件系统。
3、删除源文件以后,软连接文件也就打不开了。
4、符号连接文件通过->来指示具体的连接文件。
5、符号连接要使用绝对路径,否则连接可能会出问题(拷贝cp(-d保留连接))
举例
:
我们用相对路径(容易出问题)和绝对路径分别举例,先建立连接,可以看到建立的链接文件比hello小很多
现在三个文件都可以正常运行,可以看到暂时没什么问题
当我们进行复制的时候,会出现问题,相对路径的就不能运行
当删除源文件的时候,可以发现建立的连接无法使用了
十、vim文本编辑器
安装:sudo apt-get install vim
vim | 文本编辑器 | |
vim a.txt | 编辑a.txt(进入一般模式),进入后按i 或a 才可以编辑文件,进入编辑模式后要退出先按esc ,然后输入:和字母,比如:wq 表示保存退出,:q! 不保存退出。,:set nu 设置行号,:set list 显示控制字符,:set nonu 取消设置行号,:w 只保存不退出,:1,5 s/333/666/g 一到五行的333换成,:w /tmp/a.txt 另存为tmp下的a.txt | |
vim只进入,没有进入编辑,一些字母含义,yy 复制(前面可以先按数字),p 粘贴,d 删除,u 后退一步(撤销),v 可视化(等于鼠标选择,选择后按Y可以复制),0 行首,$ 行尾,G 最后一行,gg 第一行,6G 第六行,/adm 查找adm(enter查找,n跳转下一个,N上一个) | ||
临时文件:vim未正常关闭产生的文件(如vim编辑a.txt未正常关闭产生.a.txt.swap),再次编辑是报错 | 解决方案:查看影藏文件:ls -a,删除临文件 |
十一、C编程
vim默认TAB键为8空格,需要将其改为4空格,在/etc/vim/vimrc
文件添加set ts=4
(需要加sudo),添加set nu
显示行号
使用vim helo.c
编写一个hello.c文件,内容如下
使用指令gcc hello.c -o hello
(或者分两步,gcc -c hello.c
生成hello.o
文件,执行gcc hello.o -o hello
链接成hello可执行文件
)编译C程序,编译结束之后会生成一个hello可执行文件
,运行./hello
即可运行(-o指定输出文件名,-v显示编译过程)
如果程序有误,使用gcc编译会报错,比如将hello.c修改缺少一个冒号,如下
此时使用gcc编译会报错
十二、make工具和makefile
当源码文件比较多的时候就不适合通过直接输入gcc命令来编译,这时候就需要一个自动化的编译工具。
make工具
可以完成自动编译
工作,如果修改了几个源文件,则侧重编译这几个修改的源文件;如果某个头文件修改了,则从新编译所有包含该头文件的源文件。make一般用于将源代码文件编译为可执行的二进制文件
。make 工具编译的时候需要 Makefile 文件提供编译文件。
Makefile是make 工具所使用的文件,Makefile
指明了编译规则
。
makefile规则
目标...: 依赖文件集合...
命令1
命令2
...
比如下面这条规则:
main: main.o input.o calcu.o
gcc -o main main.o input.o calcu.o
这条规则的目标是main,main.o、input.o和calcu.o是生成main的依赖文件,如果要更新目标main,就必须要先更新它的所有依赖文件,如果依赖文件任何一个有更新,那么目标也必须更新,更新就是执行一遍规则中的命令列表(命令列表中的每条命令必须以TAB键开始,不能使用空格
)
make命令会为makefile中的每个以TAB开始的命令创建一个shell进程去执行
完整的指令:如下要生成main,需要依赖main.o,input.o,calcu.o,如果都存在,则执行命令gcc -o main main.o input.o calcu.o
生成main
,如果某个更新的依赖没有,则从下面找哪个指令生成的目标是这个依赖,然后执行生成依赖
main: main.o input.o calcu.o
gcc -o main main.o input.o calcu.o
main.o: main.c
gcc -c main.c
imput.o: input.c
gcc -c input.c
calcu.o: calcu.c
gcc -c calcu.c
clean:
rm *.o
rm main
举例
:
首先创建文件main.c,内容如下:
#include<stdio.h>
#include "input.h"
#include "calcu.h"
int main(int argc, char *argv[])
{
int a, b, num;
input_int(&a, &b);
num = calcu(a, b);
printf("%d + %d = %d\r\n", a, b, num);
return 0;
}
再创建文件input.c,内容如下:
#include<stdio.h>
#include "input.h"
void input_int(int *a, int *b)
{
printf("input tow num:");
scanf("%d %d", a, b);
printf("\r\n");
}
再创建文件calcu.c,内容如下:
#include<stdio.h>
int calcu(int a, int b)
{
return (a + b);
}
创建头文件input.h内容如下:
#ifndef __INPUT_H
#define __INPUT_H
void input_int(int *a, int *b);
#endif
创建头文件calcu.h文件如下:
#ifndef __CALCU_H
#define __CALCU_H
void calcu(int a, int b);
#endif
总共5个文件
如果我们用gcc编译,则需要将所有的.c文件都输入,即指令为:gcc main.c calcu.c input.c -o main
生成可执行文件
,然后./main
运行程序
这里使用gcc编译需要输入所有的.c文件,且会全部重新编译,耗时费力不方便。使用make
可以方便很多,make只会对修改过的文件进行编译,不会全局编译,这里我们编写Makefile文件
编写完之后,然后执行make
指令编译,会生成对应的.o
文件和可执行文件,运行./main
即可执行
如果要清除那些.o文件和可执行文件,运行make clean
即可(上面makefile中编写了clean)
这里如果修改一个文件,从新执行make,就会对修改过的文件进行编译,不会执行未修改的文件
十三、Makefile基本语法
Makefile可以定义变量,如下面语句可以定义一个变量等于main.o input.o calcu.o,简化书写过程
main: main.o input.o calcu.o
gcc -o main main.o input.o calcu.o
简化成如下
#Makefile变量使用
bojects = main.o input.o calcu.o
main: $(objects)
gcc -o main $(objects)
=
赋值,在原变量发送变化后,被该变量赋的值也会变化(如下面的curname)
在Makefile里面编写如下内容
运行make print得到如下结果(echo前面没加@输出了编译过程)
echo前面加个@,就不输出过程,只输出结果,没有命令这行
:=
赋值,原变量发生变化,被赋值的变量不发送改变,curname等于原始的aa,不随name的改变而改变,而=
赋值会跟着发送变化,代码如下
?=
表示如果前面没有被赋值,则赋值该值,如果前面赋值了,则使用之前的值,比如name1先赋值为aa,然后?=bb,由于原先赋值了,这里就打印原先的值,name2没有赋值,则值为cc,代码如下:
+=
追加内容,原先name内容为aa,后来使用+=符号追加bb,然后打印出来为aabb,代码如下:
main: main.o input.o calcu.o
gcc -o main main.o input.o calcu.o
main.o: main.c
gcc -c main.c
imput.o: input.c
gcc -c input.c
calcu.o: calcu.c
gcc -c calcu.c
clean:
rm *.o
rm main
上面这个是一般规则,使用起来需要全部写上去,这里可以使用模式规则
进行简化,在规则的目标定义中要包含%,%表示对文件名的匹配,%表示任意长度的字符串,比如%.c表示所有以.c结尾的文件,a.%.c表示所有以a.开头,以.c结尾的文件,目标中%所代表的值决定了依赖中的%值,上面的指令可以简化为如下(指令简化的gcc命令中运用到了自动化变量
):
自动化变量 | 描述 |
---|---|
$@ | 规则中的目标集合,在模式规则中,如果有多个目标的话,“$@”表示匹配模式中定义的目标集合。 |
$% | 当目标是函数库的时候表示规则中的目标成员名,如果目标不是函数库文件,那么其值为空。 |
$< | 依赖文件集合中的第一个文件,如果依赖文件是以模式(即“%”)定义的,那么“$<”就是符合模式的一系列的文件集合。 |
$? | 所有比目标新的依赖目标集合,以空格分开。 |
$^ | 所有依赖文件的集合,使用空格分开,如果在依赖文件中有多个重复的文件“s^”会去除重复的依赖文件,值保留一份。 |
$+ | 和“s^”类似,但是当依赖文件存在重复的话不会去除重复的依赖文件。 |
$* | 这个变量表示目标模式中"%"及其之前的部分,如果目标是 test/a.test.c,目标模式为 a.%.c,那么“$*”就是 test/a.test。 |
伪目标
当没有定义伪目标的时候,Makefile里面有如下内容
在外面运行make print就会有输出结果
如果在该文件夹里面存在print文件,则运行make print就不能正常使用
这是需要将Makefile里面对print使用伪目标(.PHONY:print
),这时候就可以正常使用make print指令
条件关键字:ifeq,ifneq,ifdef,ifndef
ifeq和ifneq用来判断是否相等,ifeq用来判断是否相等,ifneq判断是否不相等(下面指令用来表示参数1与参数2是否会相同
ifeq (<参数1>, <参数2>)
ifeq '<参数1>', '<参数2>'
ifeq "<参数1>", "<参数2>"
ifdef和ifndef用法如下
ifndef<变量名>
如果变量名的值非空,则表达式为真,否则为假
Makefile函数使用
不支持我们自定义函数,使用方法如下
$(函数名 参数集合)
或者
${函数名 参数集合}
参数集合是函数的多个参数,参数之间用逗号隔开,函数名与参数之间用空格隔开,函数调用以$开头,常用函数如下
函数 | 含义 | |
---|---|---|
subst | 字符串替换 | $(subst <from>,<to>,<text>) 将text中的from内容替换为to,函数返回替换后的字符串 |
patsubst | 模式字符串替换 | $(patsubst <pattern>,<replacement>,<text>) 查找text中的单词是否符合模式pattern,如果匹配就用replacement来替换,如$(patsubst %.c,%.o,a.c b.c c.c) 将o,a.c b.c c.c中符合%.c的字符串替换为%.o |
dir | 获取目录 | $(dir </src/a.c>) 获取/src/a.c目录部分,也就是/src |
notdir | 去除文件中的目录部分 | $(notdir </src/a.c>) 获取/src/a.c非目录部分,也就是a.c |
foreach | 完成循环 | $(foreach <var>,<list>,<text>) 把list中的单词逐一取出放到var中,然后再执行text所包含的表达式,每次text都会返回一个字符串,循环过程中,text中所包含的每个字符串会以空格隔开 |