Linux指令非常多,全部记忆基本不可能,所以总结文章只选取重要的指令进行总结,其具体的指令上Linux指令查询网:https://www.linuxcool.com/,进一步查询使用
参考教程:虚拟机VMware最详细下载与安装教程
启动栏介绍如图所示
图形界面下两种连接方式
Ubuntu终端指命令行操作界面,打开终端后我们通过输入shell指令来进行操作,下面我们讲解一下常用Shell指令操作(所有Linux版本基本通用)
Shell 命令的格式 如下:
command -options [argument]
command: Shell 命令名称。
options:选项,同一种命令可能有不同的选项,不同的选项其实现的功能不同。
argument:Shell 命令是可以带参数的,也可以不带参数运行。
以ls为例,分别执行如下指令
ls
ls -l
ls /usr
执行结果如下
ls命令用来打印出当前目录下的所有文件和文件夹
ls -l同样是 打印出当前目录下的所有文件和文件夹,但是此命令会列出所有文件和文件夹的详细信息,比 如文件大小、拥有者、创建日期等等。
ls /usr是用来打印出目录“/usr”下的所有 文件和文件夹。
Shell 命令是支持自动补全功能的,要输入命令的前面一部分字 母,然后按下 TAB 键自动补全,如果有多个指令,可以选择全部列出
以上为基本操作
Shell 命令是所有的 Linux系统发行版所通用的,指令在所有版本linux下都通用
文件浏览是最基本的操作了,Shell 下文件浏览命令为 ls,格式如下
ls [选项] [路径]
主要参数有:
-a 显示所有的文件以及子目录,包括以“.”开头的隐藏文件。
-l 显示文件的详细信息,比如文件的形态、权限、所有者、大小等信息。
-t 将文件按照创建时间排序列出。
-A 和-a 一样,但是不列出“.”(当前目录)和“…”(父目录)。
-R 递归列出所有文件,包括子目录中的文件。
注意:Shell 命令里面的参数是可以组合在一起用的,比如组合“-al”就是显示所有文件的详细信 息,包括以“.”开头的隐藏文件
中切换到其它的目录,使用的命令是 cd,命令格式如下
cd [路径]
使用范例
cd / //进入到根目录“/”下,Linux 系统的根目录为“/”,
cd /usr //进入到目录“/usr”里面。
cd .. //进入到上一级目录。
cd ~ //切换到当前用户主目录
pwd 命令用来显示当前工作目录的绝对路径,不需要任何的参数
查看当前系统信息
uname [选项]
可选的选项参数如下:
-r 列出当前系统的具体内核版本号。
-s 列出系统内核名称
-o 列出系统信息
clear 命令用于清除终端上的所有内容,只留下一行提示符(实际上未清除,只是推到最上面了)
sudo 命令可以 使我们暂时将身份切换到 root 用户。当使用 sudo 命令的时候是需要输入密码的,这里要注意输 入密码的时候是没有任何提示的!
sudo [选项] [命令]
选项主要参数如下:
-h 显示帮助信息。
-l 列出当前用户可执行与不可执行的命令
-p 改变询问密码的提示符。
此命令需要 root 身份去运行。命令 格式如下:
adduser [参数] [用户名]
主要参数有:
-system 添加一个系统用户
-home DIR DIR 表示用户的主目录路径
-uid ID ID 表示用户的 uid
-ingroup GRP 表示用户所属的组名
删除用户使用命令“deluser”,命 令参数如下:
deluser [参数] [用户名]
主要参数有:
-system 当用户是一个系统用户的时候才能删除
-remove-home 删除用户的主目录
-remove-all-files 删除与用户有关的所有文件
-backup 备份用户信息
命令“su”可以 直接将当前用户切换为 root 用户,切换到 root 用户以后就可以尽情的进行任何操作了!因为你 已经获得了系统最高权限,在 root 用户下,所有的命令都可以无障碍执行,不需要在前面加上 “sudo”,“su”命令格式如下:
su [选项] [用户名]
常用选项参数如下:
-c –command 执行指定的命令,执行完毕以后恢复原用户身份。
-login 改变用户身份,同时改变工作目录和 PATH 环境变量。
-m 改变用户身份的时候不改变环境变量
-h 显示帮助信息
要切换回原来的用户,使用命令“sudo su 用户名”即可
cat [选项] [文件]
主要参数如下:
-n 由 1 开始对所有输出的行进行编号。
-b 和-n 类似,但是不对空白行编号。
-s 当遇到连续两个行以上空白行的话就合并为一个行空白行。
ifconfig 是一个跟网络属性配置和显示密切相关的命令,通过此命令我们可以查看当前网络 属性,也可以通过此命令配置网络属性,比如设置网络 IP 地址等等
ifconfig interface options | address
主要参数如下:
interface 网络接口名称,比如 eth0 等。
up 开启网络设备。
down 关闭网络设备。
add IP 地址,设置网络 IP 地址。
netmask add 子网掩码。
Ubuntu 提供了一个命令来帮助用户完成这个功能,那 就是“man”命令,通过“man”命令可以查看其它命令的语法格式、主要功能、主要参数说明等, “man”命令格式如下:
man [命令名]
例如,查询ls
man ls
输入指令后会跳出来一个资料文档
直接输入命令“reboot”然后点击回车键即可
输入 命令“poweroff”然后按下回车键即可关闭 Ubuntu 系统
通过APP Store安装
使用apt工具安装软件,需要sudo,也就是root权限。
使用APT工具安装
使用apt包管理工具,apt可以自动下载,配置,安装。
指令:sudo apt-get install + 软件
安装git如下
deb软件包安装
下载.deb软件包
使用dpkg命令安装deb软件包,命令如下:
sudo dpkg -i xxxx.deb
在windows下,我们安装的是.exe文件,在Ubuntu就有一个.deb
安装网易云音乐,
自己下载程序源码编译安装
Make
Make install
其他 安装方法
QT扩展名是.run
安装的软件启动图标位置
以下路径中 usr/share/applications
本小结学习目标:了解"/"根目录下各个文件包含内容的含义
Linux下“/”就是根目录!所有的目录都是由根目录衍生出来的
目录 | 功能 |
---|---|
/bin | 存放二进制可执行文件,这些命令在单用户模式下也能够使用,可以被root和一般的账号使用。 |
/boot | Ubuntu内核和启动文件,比如vmlinuz-xxx。gurb引导装载程序。 |
/dev | 设备驱动文件 |
/etc | 存放一些系统配置文件,比如用户账号和密码文件,各种服务的起始地址。 |
/home | 系统默认的用户主文件夹,一般创建用户账户的时候,默认的用户主文件夹都会放到此目录下。 |
/lib | 存放库文件 |
/media | 此目录下放置可插拔设备,比如SD卡,或者U盘就是挂载到这个目录中。 |
/mnt | 用户可使用的挂载点,如果要挂载一些额外的设备,那么就可以挂载到此处。 |
/opt | 可选的文件和程序存放目录,给第三方软件放置的目录。 |
/root | root用户目录,也就是系统管理员目录。 |
/sbin | 和/bin类似,也是存放一些二进制可执行文件。sbin下面的一般是系统开机过程中所需要的命令。 |
/srv | 服务相关目录。比如网络服务。 |
/sys | 记录内核信息,虚拟文件系统。 |
/tmp | 临时目录 |
/var | 存放一些变化的文件,比如日志文件 |
/usr | usr不是user的缩写,而是UNIX Software Resource的缩写,存放于系统用户有关的文件,会占用很大的存储空间! |
/proc | 虚拟文件系统,数据放置到内存中,存放系统运行信息 |
绝对路径:从根目录“/”算起的路径。
相对路径:相对于目前路径的文件名写法,比如./home/zzk。不是以“/”开头的就行。
“.” 代表当前路径,也可以 用“./”表示
“…” 代表上一层目录,也可以用“…/”表示
“*” 为通配符,表示全部
本小节目标了解Ubuntu下磁盘的管理以及
/dev/sd*文件,此类文件是磁盘设备文件(并不能直接访问磁盘,必须要将磁盘挂载到某一个目录下才可以访问)
指令:定位到磁盘设备目录,显示所有sd开头设备
cd \dev
ls sd*
/dev/sdb 和 /dev/sdb1 是U盘的设备文件。
/dev/sdb表示U盘,/dev/sdb1表示U盘的第一个分区(当前U盘只有一个分区)
df:列出文件系统的整体磁盘使用量。主要查看个整个文件系统的使用量,
du:评估文件系统的磁盘使用量,主要查看单个文件的大小。
两个指令都有各自的进一步衍生指令,指令太多,需要使用时查询即可
磁盘的挂载和卸载
磁盘无法直接进入,需要进行挂载操作后才能进入,使用完毕再卸载
mount(挂载)和umount(卸载)命令
1. mount /dev/sdb1 + 挂载点 #挂载到指定挂载点
2. umount /dev/sdb1 #卸载
挂载到新建的usb文件夹,并进入查看文件
卸载(卸载前先退出usb,不然无法退出)
磁盘分区
fdisk命令
sudo fdisk /dev/sdb
#输入对应指令
#执行
创建一个分区
sudo fdisk /dev/sdb
n
p
2048 #开始扇区
2097152 #(1024*1024*1024+2048)扇区结束长度
sudo fdisk -l /dev/sdb #查询扇区信息
已经创建1G分区
磁盘分区创建好以后就可以格式化磁盘,使用命令mkfs。如:格式化sdb1分区
mkfs -t vfat /dev/sd1
Linux下常用的压缩扩展名有:.tar、.tar.bz2、.tar.gz与windows下的常用压缩包.rar、.zip有较大区别
因为Linux下很多文件是.bz2,.gz结尾的压缩文件,因此需要在windows下安装7ZIP软件(强大的压缩软件):链接
输入输入:工具名称–help 可查询 对应工具有关指令
.gzip工具负责压缩和解压缩.gz格式的压缩包。
gzip xxx #压缩
gzip -d xxx.gz #解压缩
单个文件压缩与解压缩
gzip对文件夹进行压缩
gzip -r xxx #对文件夹进行压缩
gzip -rd xxx.gz #对文件夹进行解压缩
对test文件夹压缩与解压缩
gzip虽然可以对文件夹进行压缩,但是并不能提供打包的服务,只是对文件夹中的所有文件进行了单独的压缩,例如上图中test内文件单独被压缩为.gz文件
输入输入bzip2–help可查询bzip2有关指令
和gzip类似,只是bzip2工具负责压缩和解压缩.bz2格式的压缩包。
bzip2 -z xxx #压缩
bzip2 -d xxx.gz #解压缩
bzip只能对单个文件进行压缩和解压操作
tar常用工具参数: | 参数功能 |
---|---|
-f | 使用归档文件或 ARCHIVE 设备 |
-c | 创建新归档,创建压缩文件 |
-x | 从图档中解出文件,解压缩 |
-j | 使用bzip2压缩格式。 |
-z | 使用gzip压缩格式 |
-v | 显示打包过程、结果 |
tar工具提供打包服务,就是将多个文件打包(参数顺序有要求,注意顺序),比如
tar -vcf test.tar test #将test打包成test.tar
tar -vxf test.tar #解包
打包test文件:
解压test.tar文件:
上面的tar命令只提供了打包和解包的功能,tar在提供打包和解包的同时使用gzip/bzip2进行压缩,实现类似windwos下winRAR软件的命令。
tar -vxjf xxx.tar.bz2 #解压缩
tar -vcjf xxx.tar.bz2 xxx #压缩
tar -vxzf xxx.tar.gz #解压缩
tar -vczf xxx.tar.gz xxx #压缩
以gzip格式压缩test文件
解压缩同理(注意解压后位置,默认为当前文件夹,不要出现重名文件夹)
输入rar可查询rar有关指令
需要先安装rar:sudo apt-get install rar
rar x xxx.rar #解压缩
rar a xxx.rar xxx #压缩
解压缩测试
输入zip可查询zip有关指令
zip格式压缩使用“zip“命令:
zip -rv xxx.zip xxx
zip格式解压缩使用“unzip”命令:
unzip -v xxx.zip
压缩与解压缩
Linux是多用户系统,一个系统不仅仅只针对一个用户,而是多个用户,所以掌握用户与用户组的管理与操作很有必要;
Linux是一个多用户操作系统,不同的用户拥有不同的权限,可以查看和操作不同的文件,Ubuntu有三种用户:
● 初次创建的用户,此可以完成比普通更多功能。 初次创建的用户,此可以完成比普通更多功能。
● root用户,系统管理员中的BOSS拥有至高无上权利。
● 普通用户,安装完操作系统以后被创建的。 普通用户,安装完操作系统以后被创建的。
Linux用户记录在/etc/passwd这个文件内,操作系统通过UID来识别是哪个用户,使用如下指令打开,用户显示方式:名称+UID+用户组GID
sudo vi /etc/passwd #VI打开,退出方式为按下esc后按下shift + q
Linux用户密码记录在/etc/shadow这个文件内,加密过
sudo vi /etc/shadow #VI打开,退出方式为按下esc后按下shift + q
每个用户都有一个ID,叫做UID。
为了方便管理,将用户进行分组。这样就可以设置非本组人员不能访问某些文件。每个用户可以属于多个不同的组。
用户:家里有你、弟弟、妹妹个人,每个人都有自己的房间,你们三个人都是用户,你们都不能随便的乱翻别人的房间。
用户组:你们三个都是一个家庭的,也就是属于同一个用户组,你们三个可以共用厨房,书房等空间。
用户和用户组的存在就是为了控制文件的访问权限的。
注意:每个用户组都有一个ID,叫做GID,用户组信息存储在/etc/group文件中
要使用图形化界面创建用户和用户组的话就需要安装gnome-system-tools这个工具:
sudo apt-get install gnome-system-tools
若出现以下BUG:
E: 无法获得锁 /var/lib/apt/lists/lock - open (11: 资源暂时不可用)
E: 无法对目录 /var/lib/apt/lists/ 加锁
E: 无法获得锁 /var/lib/dpkg/lock - open (11: 资源暂时不可用)
E: 无法锁定管理目录(/var/lib/dpkg/),是否有其他进程正占用它?
解决方法:
sudo rm /var/cache/apt/archives/lock
sudo rm /var/lib/dpkg/lock
然后关掉终端重新打开,再次运行安装指令,安装成功后直接打开安装程序-用户和用户组就能创建和删除用户组了:
添加用户:adduser命令**(备注:下面的添加和删除都需要root权限)**
sudo adduser 用户名
用户查询:finger命令
finger 用户名
修改用户密码:passwd命令,passwd 用户名
删除用户:deluser命令
sudo deluser 用户名
添加用户组:addgroup命令
sudo addgroup 用户组名
显示组内用户名:groups命令,groups 用户组名
删除用户组:delgroup命令
sudo delgroup 用户组名
文件权限是指不同的用户或用户组对某个文件拥有的权限,文件的权限分为三种:
命令字 | 含义 |
---|---|
r | 读 |
w | 写 |
x | 可执行 |
文件权限的描述形式如下:
-rw-r–r--就是文件权限,第一位表示文件类型(例如c开头为字符设备,d开头为块设备),剩下的每三位表示一组权限。分别对应拥有者权限、拥有者所在组权限、其他用户权限。
可以使用二进制表示文件权限
权限 | 二进制数字 | 八进制数字 |
---|---|---|
— | 000 | 0 |
–x | 001 | 1 |
-w- | 010 | 2 |
-wx | 011 | 3 |
r– | 100 | 4 |
r-x | 101 | 5 |
rw- | 110 | 6 |
rwx | 111 | 7 |
1.c的权限就是r=6,w=4,x=4
1.c文件信息:- rw- r-- r–,表示:1.c所属用户拥有读写权限无可执行权限,组内其他用户拥有只读权限,其他用户仅有可读权限。
chmod命令
chmod [权限值] [文件名 /目录名] [参数]
常用参数
参数 | 功能 |
---|---|
-c | 效果类似“ 效果类似“ -v”参数,但仅回显更改的部分 |
-f | 不显示错误信息 |
-r | 递归处理,即指定目录下所有文件以及子文件一起处理 |
-v | 显示指令执行过程 |
改变hollow的可执行权限
chown命令
chown [选项]... [所有者][:[组]] 文件...
eg:
chown root /u 将 /u的所属用户更改为"root"。
Linux有两种连接文件:符号连接(软连接)和硬链接
符号链接(软连接):类似Windows下的快捷方式。
硬链接:通过文件系统的inode连接来产生新文件名,而不是产生新文件。
inode:记录文件属性,一个文件一个inode,inode相当于文件ID,查找文件的时候要先找到inode,然后才能读出文件的内容。
ln命令用于创建连接文件:
ln [选项] 源文件 目标文件
选项:
-s 创建符号链接(软连接)
-f 强制创建连接文件,如果目标存在,那么先删除掉目标文件,然后再建立连接文件。
硬链接是多个文件都指向同一个inode,硬链接知识点:
① 具有相同inode的多个文件互为硬链接文件,创建硬链接相当于文件实体多了入口。
② 对于硬链接文件,只有删除了源文件以及对应的所有硬连接文件,文件实体才会被删除。
③ 根据硬链接文件的特点,我们可以通过给文件创建硬连接的方式来防止文件误删除。
④ 不论修改源文件还是连接文件,另一个文件的数据都会被改变。
⑤ 硬连接不能跨文件系统。
⑥ 硬连接不能连接到目录。
因为以上这些限制,硬链接其实不常用。
显示硬链接详细信息就是显示具体文件的信息
符号连接类似Windows下的快捷方式,符号链接也叫做软连接,软连接要用的多。符号连接相当于创建了一个独立的文件,这个文件会让数据读取指向它连接的哪个文件的文件名。软连接的特点:
① 可以连接到目录。
② 可以跨文件系统。
③ 删除源文件以后,软连接文件也就“打不开了”。
④ 符号连接文件通过->来指示具体的连接文件。
⑤ 符号连接要使用绝对路径,否则连接出问题。
显示软连接详细信息就是显示软链接文件的详细信息,下图中显示的文件信息就是l(链接文件),所有用户都有操作权限!
Linux系统命令行的操作方式与图形化的操作方式不一样,他内部自带了vi编辑器,但是vi编辑器太难用,所以安装vim编辑器,安装命令:
sudo apt-get install vim
vim xxx 使用vim编辑器打开文件。
一般模式(指令模式):默认模式,用vim打开一个软件以后自动进入到此模式。
编辑模式:一般模式中无法编辑文件,要编辑文件就要进入编辑模式,按下“i、I、a、A、o、O、s、r”等就会进入到编辑模式。一般按下“a”进入编辑模式。按下ESC键可退出编辑模式。
命令行模式(底行模式):先进入到一般模式,然后输入’:’、’/’、’?'这三个中的任意一个就可以进入到命令行模式。
常用指令:
命令 | 作用 |
---|---|
x | 删除光标所在处字符 nx 删除光标所在处后n个字符 |
dd | 删除光标所在行,ndd删除n行 |
dG | 删除光标所在行到末尾的内容 |
D | 删除从光标所在处到行尾 |
yy、Y | 复制当前行 |
nyy、nY | 复制当前行以下n行 |
dd | 剪切当前行 |
ndd | 剪切当前行以下n行 |
yy、Y | 复制当前行 |
nyy、nY | 复制当前行以下n行 |
dd | 剪切当前行 |
ndd | 剪切当前行以下n行 |
p、P | 粘贴在当前光标所在行下 或行上 |
r | 取代光标所在处字符 |
R(shift + r) | 从光标所在处开始替换字符,按Esc结束 |
u | undo,取消上一步操作 |
ctrl+r | redo,返回到undo之前 |
常用指令:
命令 | 作用 |
---|---|
a | 在光标后附加文本 |
A(shift + a) | 在本行行末附加文本 行尾 |
i | 在光标前插入文本 |
I(shift+i) | 在本行开始插入文本 行首 |
o | 在光标下插入新行 |
O(shift+o) | 在光标上插入新行 |
常用指令:
命令 | 作用 |
---|---|
:w | 保存修改 |
:w new_filename | 另存为指定文件 |
:w >> a.txt | 内容追加到a.txt文件中 文件需存在 |
:wq | 保存修改并退出 |
shift+zz(ZZ) | 快捷键,保存修改并退出 |
:q! | 不保存修改退出 |
:wq! | 保存修改并退出(文件所有者可忽略文件的只读属性) |
Linux下的编写C代码包括两部分:代码编写和编译,在 Windows 下可以使用 Visual Studio 直接完成这两部分,但在 Linux 下这两部分是分开的,我们先进行代码编写,编写完成以后再使用 GCC 编译器进行编译,其中代码编写工具很多,比如 VIM 编辑器、Emacs 编辑器、VScode 编辑器等等,此处我使用VIM编辑器来编写程序,把 Linux 下 的 C 编程完整的走一遍。
10.1、设置vim编辑器
用vim打开文件 /etc/vim/vimrc
sudo vim /etc/vim/vimrc
设置vim编辑器,一个TAB=4个字节,即在最后面输入如下指令
set ts=4
设置vim编译器,显示行号,最后面加入下面一行代码
set nu
10.2、编写C程序
新建一个1.c文件(不新建C文件也可以,vim会自动创建)
touch 1.c
vim打开C文件
vim 1.c
根据上一小节vim操作输入如下c程序
1 #include <stdio.h>
2
3 int main(void)
4 {
5 printf("Hello World\r\n");
6 return 0;
7 }
保存退出
使用gcc编译器编译C程序。
gcc -o hello 1.c
执行程序
补充GCC编译器介绍
gcc [选项] [文件名字] [源文件]
主要选项如下:
-c:只编译不链接为可执行文件,编译器将输入的.c 文件编译为.o 的目标文件。
-o:<输出文件名>用来指定编译结束以后的输出文件名,如果不使用这个选项的话 GCC 默 认编译出来的可执行文件名字为 a.out。
-g:添加调试信息,如果要使用调试工具(如 GDB)的话就必须加入此选项,此选项指示编 译的时候生成调试所需的符号信息。
-O:对程序进行优化编译,如果使用此选项的话整个源代码在编译、链接的的时候都会进 行优化,这样产生的可执行文件执行效率就高。
-O2:比-O 更幅度更大的优化,生成的可执行效率更高,但是整个编译过程会很慢。
注意gcc编译时,若C语言语法不对会报错显示!
当源码文件比较多的时候就不适合通过直接输入gcc命令来编译,这时候就需要一个自动化的编译工具.
make :一般说GNU Make,是一个软件,用于将源代码文件编译为可执行的二进制文件,make工具主要用于完成自动化编译。make工具编译的时候需要Makefile文件提供编译文件
Makefile :make工具所使用的文件,Makefile指明了编译规则
使用VIM编写多个小型的含有多个.c文件的C程序。
编写主函数main.c文件
1 #include <stdio.h>
2 #include "input.h"
3 #include "calcu.h"
4
5 int main(int argc, char *argv[])
6 {
7 int a, b, num;
8
9 input_int(&a, &b);
10 num = calcu(a, b);
11 printf("%d + %d = %d\r\n", a, b, num);
12 }
输入函数input.c
1 #include <stdio.h>
2 #include "input.h"
3
4 void input_int(int *a, int *b)
5 {
6 printf("input two num:");
7 scanf("%d %d", a, b);
8 printf("\r\n");
9 }
input的头文件input.h
1 #ifndef _INPUT_H
2 #define _INPUT_H
3
4 void input_int(int *a, int *b);
5 #endif
计算函数calcu.c
1 #include "calcu.h"
2
3 int calcu(int a, int b)
4 {
5 return (a + b);
6 }
calcu的头文件calcu.h
1 #ifndef _CALCU_H
2 #define _CALCU_H
3
4 int calcu(int a, int b);
5 #endif
编写文件夹如下:
11.3 使用GCC直接编译
使用GCC直接编译的过程如下
第一次编译使用
gcc [所有文件] -o [目标文件]
之后哪个文件更新了单独编译那个文件后再链接
gcc [更新文件] -c
gcc [所有文件.o] -o [目标文件]
使用如下,先生成所有文件的.o文件,更新直接更新对应.o文件就行,最后再通过gcc的-o来链接所有编译后文件。
gcc的编译方法复杂,尤其在文件数量很多时十分低效,所以引入Makefile来自动化编译,简化流程!
以上面的文件为例子,进行makefile编译!
第一次使用VIM编辑的话,首先修改文件/etc/vim/vimrc,使 TAB 键不用空格形成
set noexpandtab
Vim新建一个Makefile文件(严格按照大小写来)
编写代码如下:(2、4、6、8、11、12处tab进位,必须!)
1 main: main.o input.o calcu.o
2 gcc -o main main.o input.o calcu.o
3 main.o: main.c
4 gcc -c main.c
5 input.o: input.c
6 gcc -c input.c
7 calcu.o: calcu.c
8 gcc -c calcu.c
9
10 clean:
11 rm *.o
12 rm main
保存后,我们在命令行输入make就会默认执行main的程序
使用make clean则会调用清除程序
此处makefile的功能如下:
如果工程没有编译过,那么工程中的所有.c 文件都要被编译并且链接成可执行程序。
如果工程中只有个别 C 文件被修改了,那么只编译这些被修改的 C 文件即可。
如果工程的头文件被修改了,那么我们需要编译所有引用这个头文件的 C 文件,并且 链接成可执行文件。
Makefile由一系列的规则组成的,规则格式如下
[目标]: [依赖]
命令1
命令2
命令3
...
比如上一小结的规则
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.o: main.c
gcc -c main.c
input.o: input.c
gcc -c input.c
calcu.o: calcu.c
gcc -c calcu.c
clean:
rm *.o
rm main
代码中有5条规则,最上面为默认规则,执行时会检查他的依赖文件是不是最新的,如果不是最新的就会向下搜索规则来生成最新的依赖文件,如果我们要直接执行对应规则,命令行输入如下指令就行,第五条规则因为没用依赖文件,默认认为依赖文件是最新的直接执行命令;
make [规则目标]
具体执行流程总结如下:
注意:除了第一条规则顺序有意义,其他规则顺序随意!
Makefile 加入了变量支持,不像 C 语言中的变量有 int、char 等各种类型,Makefile 中的变量都是字符串!类似 C 语言中的宏。使用变量将上面的代码修改,例如
#Makefile 变量的使用
objects = main.o input.o calcu.o
main: $(objects)
gcc -o main $(objects)
先简单的补充一下上面用到的语法
’#‘ 为makfile语法中注释
’objects‘ 为变量名称
’$(变量名称)‘ 为引用变量
‘=’ 为对变量进行赋值
赋值符“=”
变量赋值,其真实值取决于它所引用的变量的最后一次有效值
name = jk
curname = $(name)
name = jeck666
print:
@echo curname: $(curname)
执行后结果,显示最后一次赋值
赋值符“:=”
‘:=’ 与 ‘=’ 号的区别在于,前者不会使用后面定义的变量,只能使用前面已经定义好的,这就是“=”和“:=”两个的区别,我们将代码换成如下代码进行测试
name = jk
curname := $(name)
name = jeck666
print:
@echo curname: $(curname)
可以看到值取的是赋值时的值,不是最后定义的变量值
赋值符“?=”
“?=”使用时如果变量前面没有被赋值,那么此变量就是“?=”后面的值, 如果前面已经赋过值了,那么就使用前面赋的值
变量追加“+=”
有时候我们需要给前面已经定义好的变量添加一些字符串进 去,此时就要使用到符号“+=”,比如如下所示代码
objects = jeck
objects += 666
一开始变量objects为jeck,追加后变为jeck666
模式规则中,至少在规则的目标定定义中要包涵“%”,否则就是一般规则,目标中的“%”表示对文件名的配,“%”表示长度任意的非空字符串,比如“%.c”就是所有的以.c 结尾的 文件,类似与通配符,a.%.c 就表示以 a.开头,以.c结束的所有文件
通过模式规则我们就可以使用一条规则来将所有的.c 文件编译为对应的.o 文件
使用方法如下:
%.o : %.c
命令
上一节代码可修改如下:
main: main.o input.o calcu.o
gcc -o main main.o input.o calcu.o
%.o: %.c
命令
clean:
rm *.o
rm main
此处修了了之后命令也需要修改,因此引入自动化变量
自动化变量 | 变量 |
---|---|
$@ | 规则中的目标集合,在模式规则中,如果有多个目标的话,“$@”表示匹配模 式中定义的目标集合。 |
$% | 当目标是函数库的时候表示规则中的目标成员名,如果目标不是函数库文件, 那么其值为空。 |
$< | 依赖文件集合中的第一个文件,如果依赖文件是以模式(即“%”)定义的,那么 “$<”就是符合模式的一系列的文件集合。 |
$? | 所有比目标新的依赖目标集合,以空格分开。 |
$^ | 所有依赖文件的集合,使用空格分开,如果在依赖文件中有多个重复的文件, “$^”会去除重复的依赖文件,值保留一份。 |
$+ | 和“$^”类似,但是当依赖文件存在重复的话不会去除重复的依赖文件。 |
$* | 这个变量表示目标模式中"%"及其之前的部分,如果目标是 test/a.test.c,目标模 式为 a.%.c,那么“$*”就是 test/a.test。 |
通过自动化变量,我们最终改版的代码如下:
main: main.o input.o calcu.o
gcc -o main main.o input.o calcu.o
%.o: %.c
gcc -c $<
clean:
rm *.o
rm main
Makefile 有一种特殊的目标——伪目标,一般的目标名都是要生成的文件,而伪目标不代 表真正的目标名,使用伪目标主要是为了避免 Makefile 中定义的执行命令的目标和工作目录下的实际文件出 现名字冲突,例如上面的代码中clean规则,如果文件夹内真的存在clean命名的文件,那么clean规则就无法执行!!!因此,可以将 clean 声明为伪 目标,声明方式如下:
.PHONY : clean
上面实例代码进一步修改
main: main.o input.o calcu.o
gcc -o main main.o input.o calcu.o
%.o: %.c
gcc -c $<
.PHONY : clean
clean:
rm *.o
rm main
声明 clean 为伪目标以后不管当前目录下是否存在名 为“clean”的文件,输入“make clean”的话规则后面的 rm 命令都会执行
makefile支持条件判断语法,具体有两种语法:
<条件关键字>
<条件为真时执行的语句>
endif
<条件关键字>
<条件为真时执行的语句>
else
<条件为假时执行的语句>
endif
条件关键字有 4 个:ifeq、ifneq、ifdef 和 ifndef,这四个关键字其实分为两对、ifeq 与 ifneq、ifdef 与 ifndef,ifeq 用来判断是否相等,ifneq 判断是否不 相等,用法如下:
ifeq (<参数 1>, <参数 2>)
ifeq ‘<参数 1 >’,‘ <参数 2>’
ifeq “<参数 1>”, “<参数 2>”
ifeq “<参数 1>”, ‘<参数 2>’
ifeq ‘<参数 1>’, “<参数 2>”
ifdef 和 ifndef 的用法如下:
ifdef <变量名>
如果“变量名”的值非空,那么表示表达式为真,否则表达式为假。“变量名”同样可以是 一个函数的返回值。ifndef 用法类似,但是含义用户 ifdef 相反。
Makefile 中的函数是已经定义好的,我们直接使用, 不支持我们自定义函数。make 所支持的函数不多,但是绝对够我们使用了,函数的用法如下:
$(函数名 参数集合)
或者
${函数名 参数集合}
常用函数:
函数 subst 用来完成字符串替换,调用形式如下:
$(subst ,,)
将字符串中的内容替换为,函数返回被替换以后的字符串
函数 patsubst 用来完成模式字符串替换,调用形式如下:
$(patsubst ,,)
此函数查找字符串中的单词是否符合模式,如果匹配就用来 替换掉,可以使用通配符“%”,表示任意长度的字符串,函数返回值就是替换后的字符串。如果中也包涵“%”,那么中的“%”将是中的那个 “%”所代表的字符串
例如:
$(patsubst %.c,%.o,a.c b.c c.c)
函数 dir 用来获取目录,使用方法如下:
$(dir )
此函数用来从文件名序列中提取出目录部分,返回值是文件名序列的目录部分,/src/a.c的目录部分为/src
此函数用与从文件名序列中提取出文件名非目录部分,也就是提取文件名
$(notdir )
foreach 函数用来完成循环
$(foreach ,,)
此函数的意思就是把参数中的单词逐一取出来放到参数中,然后再执行所 包含的表达式。每次都会返回一个字符串,循环的过程中,中所包含的每个字符串会以空格隔开,最后当整个循环结束时,所返回的每个字符串所组成的整个字符串将会是 函数 foreach 函数的返回值。
通配符“%”只能用在规则中,只有在规则中它才会展开,如果在变量定义和函数使用时, 通配符不会自动展开,这个时候就要用到函数 wildcard
$(wildcard PATTERN…)
例如:
$(wildcard *.c)
获取当前目录下所有的.c 文件
之前我们已经了解到终端下输入的一些常用Shell命令,但是我们都是一条一条输入命令,遇到大量的指令时会很
麻烦,所以我们通过shell脚本一次性执行大量指令!shell脚本类似windows的批处理文件,就是将连续执行的命
令写成一个文件,shell脚本提供数组、循环、条件判断的等功能,shell脚本一般是Linux运维或者系统管理员
要掌握的,作为嵌入式开发人员,我们只需要掌握shell脚本最基础的部分即可。
shell脚本是个纯文本文件,命令从上而下,一行一行的开始执行,shell脚本扩展名为.sh,shell脚本第一行一定要为:
#!/bin/bash
表示使用bash,因为linux里面不仅仅只有bash一个解析器,还有其它的,它们之间的语法会有一些不同,所以加上这一句话,告诉系统要用这个解析器
定义变量时,变量名不加美元符号
name=“666”
name为定义的变量
使用定义过的变量,只要在变量名前面加美元符号$,格式如下
echo $name
echo ${name}
echo 指令用于字符串的输出,使用格式如下
#显示字符串
echo "It is a test"
#显示变量
echo "$name It is a test"
# #号为shell中注释符号
read指令用于读取,可以带有-a, -d, -e, -n, -p, -r, -t, -s八个选项,语法如下
read [-ers] [-a aname] [-d delim] [-i text] [-n nchars] [-N nchars] [-p prompt] [-t timeout] [-u fd] [name ...]
8个参数功能描述
参数 | 功能 |
---|---|
-d | 后面跟一个标志符,其实只有其后的第一个字符有用,作为结束的标志。 |
-p | 后面跟提示信息,即在输入前打印提示信a息 |
-e | 在输入的时候可以使用命令补全功能。 |
-n | 后跟一个数字,定义输入文本的长度,很实用。 |
-r | 屏蔽\,如果没有该选项,则\作为一个转义字符,有的话 \就是个正常的字符了。 |
-s | 安静模式,在输入字符时不再屏幕上显示,例如login时输入密码。 |
-t | 后面跟秒数,定义输入字符的等待时间。 |
-u | 后面跟fd,从文件描述符中读入,该文件描述符可以是exec新开启的 |
shell脚本中数值仅支持整形,数值计算表达式如下
$((表达式))
例如:
#!/bin/bash
a=1
b=2
c=$((a+b))
echo "$a+$b=$c"
注意:shell语法内 ‘=’号的使用前后不能有间隔!
test命令用于查看文件是否存在、权限等信息,可以进行数值,字符,文件三方面的测试。
数值测试
参数 | 说明 |
---|---|
-eq | 等于则为真 |
-ne | 不等于则为真 |
-gt | 大于则为真 |
-ge | 大于等于则为真 |
-lt | 小于则为真 |
-le | 小于等于则为真 |
字符串测试
参数 | 说明 |
---|---|
= | 等于则为真 |
!= | 不相等则为真 |
-z 字符串 | 字符串的长度为零则为真 |
-n 字符串 | 字符串的长度不为零则为真 |
文件测试
参数 | 说明 |
---|---|
-e 文件名 | 如果文件存在则为真 |
-r 文件名 | 如果文件存在且可读则为真 |
-w 文件名 | 如果文件存在且可写则为真 |
-x 文件名 | 如果文件存在且可执行则为真 |
-s 文件名 | 如果文件存在且至少有一个字符则为真 |
-d 文件名 | 如果文件存在且为目录则为真 |
-f 文件名 | 如果文件存在且为普通文件则为真 |
-c 文件名 | 如果文件存在且为字符型特殊文件则为真 |
-b 文件名 | 如果文件存在且为块特殊文件则为真 |
&&和||命令:
**cmd1 && cmd2:**当cmd1执行完并且正确,那么cmd2开始执行,如果cmd1执行完毕错误,那么cmd2不执行。
cmd1 || cmd2: 当cmd1执行完毕并正确,那么cmd2不执行,反之cmd2执行。
根据以上指令编写测试程序
#!/bin/bash
echo "please input two string:"
read -p "first:" str1 #一一对应输入参数
read -p "second:" str2
#运用 && 和 || 判断test结果
test $str1 == $str2 && echo "str1 = str2" || echo "str1 != str2"
测试结果
[ ]为test命令的另一种形式,但要注意:
1.必须在左括号的右侧和右括号的左侧各加一个空格,否则会报错。
2.test命令使用标准的数学比较符号来表示字符串的比较,而用文本符号来表示数值的比较。
3.大于符号或小于符号必须要转义,否则会被理解成重定向。
[ ] 将判断内容框起来,代替test判断结果,使用方法如下
[ "$str1"=="str2" ]
注意:参数必须加""号表示一个整体参数,[]与内容必须间隔一个空格
shell脚本提供许多默认参数,具体如下:
参数 | 作用 |
---|---|
$0 | 输出当前执行脚本的路径 |
$n | 运行脚本时,后面跟的参数,例:./test.sh 1 2 3 那么在test.sh中,$0=./test.sh ,$1=1 ,$2=2,$3=4 |
$# | 命令行参数的个数 |
$@ | 所有参数的值,每个参数用引号包起来 |
$* | 所有参数的值,所有参数用一个引号包起来 |
$? | 判断上一条命令是否执行成功 |
$$ | 获得当前进程进程号 |
$! | 上一个指令的PID |
$_ | 在执行此命令之前的前一个命令 |
主要介绍如下一个:
0 0~ 0 n,表示shell脚本的参数,包括shell脚本命令本身,shlle脚本执行脚本的路径为$0,$1-n则可以在我们运行脚本时直接传入参数,例如以下代码
1 #!/bin/bash
2 echo "input dat=" $1
3 echo "pos of shell=" $0
运行结果
shell脚本支持条件判断,虽然可以通过&&和||来实现简单的条件判断,但是稍微复杂一点的场景就不适合了。shell脚本提供了if then条件判断语句,写法
if [条件判断] ; then
#判断成立要做的事情
fi
还有if then else 语句,写法
if [条件判断] ; then
#条件判断成立要做的事情
else
#条件判断不成立要做的事情。
fi
或:
if [条件判断] ; then
#条件判断成立要做的事情
elif [条件判断]; then
#条件判断成立要做的事情
else
#条件判断不成立要做的事情。
fi
实例代码:
1 #!/bin/bash
2 echo "please input two string:"
3 read -p "first:" str1 #一一对应输入参数
4 read -p "second:" str2
5
6
7
8 if [ "&str1"=="$str2" ] ; then
9 echo "str1=str2"
10 else
11 echo "str1!=str2"
12 fi
执行结果
最后还有case语句
case $变量 in
“第1个变量内容”)
程序段
;; #表示该程序块结束!!
“第2个变量内容”)
程序段
;;
“第n个变量内容”)
程序段
;;
esac
示例代码:
1 #!/bin/bash
2 case $1 in
3 "a")
4 echo "dat A"
5 ;; #表示该程序块结束!!
6
7 "b")
8 echo "dat B"
9 ;;
10
11 *) # *号表示其他所有情况
12 echo "dat other"
13 ;;
14 esac
执行结果:
shell脚本支持自定义函数,函数写法如下:
[ function ] funname [()]
{
#代码段;
[return int;]
}
说明:
可以带function fun() 定义,也可以直接fun() 定义,不带任何参数。
参数返回,可以显示加:return 返回,如果不加,将以最后一条命令运行结果,作为返回值。 return后跟数值n(0-255
实例代码
#!/bin/bash
function help()
{
case $1 in
"-a")
echo "help a"
;;
"-b")
echo "help b"
;;
*) # *号表示其他所有情况
echo "unknow"
;;
esac
}
#执行函数
help -a
help -b
help -c
运行结果
shell脚本也支持循环,比如 while do done,表示当条件成立的时候就一直循环,直到条件不成立,写法如下:
while [条件] #括号内的状态是判断式
do #循环开始
#循环代码段
done
还有另外一种until do done,表示条件不成立的时候循环,条件成立以后就不循环,写法如下:
until [条件]
do
#循环代码段
done
示例循环代码:
1 #!/bin/bash
2 read -p "please input name:" name
3
4 while [ "$name" == "jeck" ]
5 do
6 read -p "please input name:" name
7 done
8 echo "While Over!"
运行结果:
for循环,使用for循环可以知道循环次数,写法:
for var in con1 con2 con3……
do
#循环代码段
done
示例代码:
#!/bin/bash
for var in a b c d e
do
echo $var
done
执行结果,依次输出:
for循环数值处理,写法:
for((初始值; 限制值; 执行步长))
do
#循环代码段
done
示例代码:
#!/bin/bash
for((i=0; i<5; i++))
do
echo $i
done
执行结果如下: