Linux系统编程
学习课程:
基础部分
Shell
命令解释器,格局输入的命令执行相应的命令。查询当前操作系统有哪些shell:
cat /etc/shells .s查询当前系统正在使用的shell:
echo $SHELL终端
Computer terminal,是一系列输入输出的总称。常见的输入终端有,键盘,话筒,摄像头,常见的输出终端有屏幕、打印机、扬声器。在Ubuntu上的终端程序,就是一个模拟的终端系统。
Shell家族
/bin/sh 被/bin/bash取代
/bin/bash linux默认shell
/bin/ksh Kornshell 有AT&T Bell lab.发展出来的,兼容bash
/bin/tcsh 战争和c shell,提供更的功能
/bin/csh 被/bin/tcsh取代
/bin/zsh 基于ksh发展的更为强大的shellBash
Unix shell的一种,在1987年由布莱恩·福克斯为了GNU计划而编写。1989年发布第一个正式版本,原先是计划用在GNU操作系统上,但能运行于大多数类Unix系统的操作系统之上,包括Linux与Mac OS X v10.4起至macOS Mojave都将它作为默认shell,而自macOS Catalina,默认Shell以zsh取代。
Bash是Bourne shell的后继兼容版本与开放源代码版本,它的名称来自Bourne shell(sh)的一个双关语(Bourne again / born again):Bourne-Again SHell。
Bash是一个命令处理器,通常运行于文本窗口中,并能执行用户直接输入的命令。Bash还能从文件中读取命令,这样的文件称为脚本。和其他Unix shell 一样,它支持文件名替换(通配符匹配)、管道、here文档、命令替换、变量,以及条件判断和循环遍历的结构控制语句。包括关键字、语法在内的基本特性全部是从sh借鉴过来的。其他特性,例如历史命令,是从csh和ksh借鉴而来。总的来说,Bash虽然是一个满足POSIX规范的shell,但有很多扩展。
命令和路径补齐
在bash下敲命令时,Tab键可以补全已经巧了一部分的文件名、命令名、目录名。在Ubuntu系统下默认启用bash completion:
将此行加入到 ~/.bashrc 启动脚本中,即可启动补全功能。
主键盘快捷键
功能快捷键助记上Ctrl-p下Ctrl-n左Ctrl-b右Ctrl-fdelete 光标后面的DelCtrl-dHomeCtrl-afirst letterEndCtrl-eendBackspaceBackspacedelete光标前面的单个字符清除整行Ctrl-u删除光标到行末Ctrl-k显示上滚Shift-PgUp显示下滚Shift-PgDn增大终端字体Ctrl-Shift-+减小终端字体Ctrl- –新打开一个终端Ctrl-Alt-T清屏Ctrl-l
Linux命令大致可以分为三类:
文件目录类命令
进程控制类命令
用户及权限管理类命令
命令格式:
隐藏终端提示符
vi ~./bash 打开使用的shell环境配置文件,末尾添加 PS1=$ 保存退出,重启终端即可。注意 PS1 变量就是提示符的定义,可以根据需要修改。
目录和文件
类Uninx系统目录结构
Linux没有盘符的概念,只有一个根目录,所有文件都在 / 根目录下:
相对路径与绝对路径
从根 / 目录开始的路径名为绝对路径,如:
从当前位置开始描述的路径为相对路径:
. 和 ..
linux八种文件类型
普通文件: –
目录文件:d
字符设备文件:c
块设备文件:b
软连接:l
管道文件:p
套接字:s
未知文件
cd 切换目录
命令英文原意:change directory
ls 浏览目录文件
命令英文原意:list
pwd 展示当前所在的路径
命令英文原意:print working directory
mkdir 创建目录
命令英文原意:make directory
rmdir 删除空目录
命令英文原意:remove directory
touch 创建空文件
rm 删除文件
英文原意,remove
cp 拷贝文件或者目录
英文原译, copy
mv 移动文件和目录
cat 查看文件
命令英文原意:concatenate and display files, 连接文件并打印到标准输出设备上
tac 查看文件反向
与cat命令功能类似,但是是反向打印
more 分页显示文件内容
less 分页显示文件内容
head 显示文件前几行的内容
tail 显示文件后几行的内容
tree 查看目录结构树
ln 软连接和硬链接
软连接就像windows的快捷方式
对file文件执行操作与对file.s软连接文件执行操作,效果相同。
软连接文件的大小取决于源文件所在路径的长度。
Linux下的软链接行为和windows下的快捷方式差不多,但是如果是用相对路径创建的软链接,在软链接移动之后就会失效,无法访问。这一点和windows快捷方式不同,windows快捷方式随便放哪里都行。
所以在创建软连接是,需要使用绝对路径,这样对软连接移动不会失效
软连接的权限,默认为 rwxrwxrwx 软连接的权限仅仅代表软连接文件的权限,默认是所有权限,文件权限的控制最终仍然由源文件决定。
硬链接就是同步文件,对硬链接修改,源文件与与源文件相关的硬链接都会被同步修改, 这是因为他们拥有相同的Inode节点。
用户与用户组
whoami 查看当前登录用户
adduser 添加用户
passwd 修改密码
addgroup 添加用户组
su 切换用户
deluser 删除用户
delgroup 删除用户组
chmod 修改权限
change mode
第一栏
第1位代表普通文件
第2、3、4 分别代表用户的读、写、执行三个权限的状态,如果是 – ,则代表没有该权限
第5、6、7分别代表所有者所在的用户组的读、写、执行三个权限的状态
第8、9、10分别代表其他用户的读、写、执行三个权限的状态
第三栏:
文件所有者
第四栏:
文件所有者所在组
文字设定法
数字设定法
三个组的权限都用二进制编号,比如要设置当前用户对文件的读写和执行权限,则当前用户的操作权限为
4(读)
2(写)
1(执行)
所以,
6 代表角色拥有读写权限
5代表角色拥有读取和执行权限
3代表角色拥有写入和执行权限
7代表拥有所有的权限
chown 更改文件所有者
change own:
同时修改文件所有用户与用户组:
chgrp 修改文件所属组
查找
wich 查看指定命令所在路径
whereis 查询安装的命令信息
用于搜索命令所在的路径以及帮助文档所在的位置,不能搜索用户自己创建的文件等信息。
不能看到shell命令(自带的命令,比如cd命令),只能看到外部安装的命令(环境变量中的命令)
-b:只查找可执行文件
-m:只查找帮助文件
find 文件搜索
find [搜索范围] [搜索条件]
按照文件类型搜索
-type 按文件类型搜索 d/p/s/c/b/l/f:文件
按照文件名搜索
指定搜索深度
应作为第一个参数出现
指定文件大小范围
按文件大小搜索. 单位:b(512字节,是一个磁盘块)、c(bytes)、w(two bytes)、k、M、G
指定时间范围
操作标志:
a 访问时间(access time),指的是文件最后被读取的时间,可以使用touch命令更改为当前时间;
c 变更时间(change time),指的是文件本身最后被变更的时间,变更动作可以使chmod、chgrp、mv等等;
m 修改时间(modify time),指的是文件内容最后被修改的时间,修改动作可以使echo重定向、vi等等;
时间标志:
time 天
min分钟
搜索结果并执行 -exec
将find搜索的结果集执行某一指定命令
搜索 /usr/ 路径下名称含有tmp的文件
搜索完毕后,对这些命令执行
rm -rf 搜索的文件名称,将删除含有这些文件{} 代表搜索文件结果
\代表转移字符,;代表结束
搜索结果并执行 交互方式 -ok
在执行删除之前会提示是否删除
grep 寻找文件内容
使用管道搜索结果集:
xargs 结果集分段处理
两者差别在于当结果集合很大的时候,xargs会对结果进行分片处理(分为多个片段 一个个处理),所以性能好些。但xargs也有缺陷,xargs默认用空格来分割结果集,当文件名有空格的时候,会因为文件名被切割失效。
解决xargs问题:
因为xargs对结果集默认使用空格拆分,所以我们可以使用别的作为拆分依据,就不会出现这类问题,这里使用0作为拆分依据:
软件包管理
debian分支 apt-get
debian分支 deb包
rpm包管理
参考: https://www.linuxprobe.com/rpm-redhat.html
打包和压缩
tar 打包
gzip 压缩解压
gzip 不支持压缩多个文件以及文件夹
tar 打包并压缩
因为gzip 以及 bzip2都是只能对单个文件进行压缩,一来不能压目录,二来不能打包。所以通常使用tar和压缩命令配合的方式压缩文件:
先将文件使用tar打包
在使用压缩命令压缩
zip 压缩
rar 压缩
进程管理
who 查看当前线上和用户情况
ps 查看进程
查看与当前用户交互的进程
查看所有进程的详细信息
jobs 查看当前shell下后台运行的作业
kill 杀死进程
env 查看当前进程的环境变量
top 文字版任务管理器
网络管理
ifconfig
ping
netstat
常用服务器构建
ftp
nfs
ssh
scp
telnet
其他命令
man 帮助命令y
共有七章帮助分别为:
可执行程序或者Shell
系统调用(内核提供的函数)
库调用(程序库中的函数)
特殊文件(通常位于 /dev)
文件格式规范,如 /etc/passwd
游戏
杂项(包括宏包和规范)
系统管理命令 (通常只针对root用户)
内核历程[非标准
alias 命令别名
ll 命令是ls命令的别名,就是通过alias命令设置的:
查看当前系统中已经设置的别名:
date 显示系统时间
vi
三种工作模式

进入编辑模式
i 进入编辑模式,光标前插入字符
a 进入编辑模式,光标后插入字符
o 进入编辑模式,光标所在行的下一行插入
I 进入编辑模式,光标所在行的行首插入
A 进入编辑模式,光标所在行的行末插入字符
O 进入编辑模式,光标所在行的上一行插入字符
s 删除光标所在字符并进入编辑模式
S 删除光标所在行并进入编辑模式
光标移动
h 左移
j 下移
k 上移
l 右移
左下上右
gcc
安装
ubuntu:
编译4个步骤
预处理,生成预编译文件(.i文件), 展开宏、头文件,替换条件编译,删除注释、空行、空白
gcc –E hello.c –o hello.i编译,生成汇编代码文件 (.s文件),消耗时间、系统资源最多
gcc –S hello.i –o hello.s汇编,生成目标文件(.o文件),将汇编指令翻译成机器指令
gcc –c hello.s –o hello.o链接,生成可执行文件,数据段合并、地址回填
gcc hello.o –o hello
gcc常用参数
-I,指定头文件所在的位置-g,编译时添加调试语句,增加gdb调试支持-Wall,显示所有警告信息-D,向程序中动态注册宏定义
静态库与共享库
静态库
静态库在文件中静态展开,所以有多少文件就展开多少次,非常吃内存,100M展开100次,就是1G,但是这样的好处就是静态加载的速度快

共享库又称为动态库,使用动态库会将动态库加载到内存,10个文件也只需要加载一次,然后这些文件用到库的时候临时去加载,速度慢一些,但是很省内存。

静态库制作以及使用
静态库名字以lib开头,以.a结尾。例如: libmylib.a。静态库生成指令:
add.c:
sub.c:
div1.c:
test.c:
添加隐式声明
再次编译,就不会报错了。这种方法缺点很明显,需要库的使用者知道库里的函数,并且需要将定义一个个加入到代码中。
静态库头文件
在日常开发中,库一般是从网络上down下来的。我们没法知道库中的函数。所以通常在每个库中会额外包含一个头文件,在头文件中生命了这个库中所有函数的隐式声明。
定义mymath.h:
ifndef 用来防止头文件多次展开,如果第一次include没有
_MYMATH_H_宏定义,会展开,下次会通过ifdef判断是否有 ,如果有了不会再次展开。
在test.c中引入头文件:
执行gcc编译链接,使用-I指定头文件路径:
动态库(共享库)
当调用到动态库函数,才会去加载。
写在源代码里的函数,他们的地址相对main函数偏移是一定的,链接时,回填main函数地址之后,其他源代码里的函数也就得到了地址,从而可以通过地址调用函数
而动态库里的函数在链接阶段无法确定,所以动态库中的函数会用一个@plt来标识,当动态库加载到内存时,再用加载进去的地址将@plt替换掉。
制作动态库
生成位置无关的.o文件,使用下面这个参数过后,生成的函数就和位置无关,挂上@plt标识,等待动态绑定
使用 gcc -shared制作动态库
编译可执行程序时指定所使用的动态库:
-L:指定库路径-l:指定库名(注意,如果动态库文件为libmymath.so,那么库名称为 mymath)
执行含有动态库的程序
执行 ./test 报错:
提示,找不到动态库文件。这是因为动态链接器找不到动态库的位置,而不是了链接器(-L 与 -l 是为链接器指定动态库的位置,发生在链接阶段):
连接器: 工作于链接阶段,工作时需要 -l 和 -L
动态链接器: 工作于程序运行阶段,工作时需要提供动态库所在目录位置
动态库加载错误:通过环境变量指定动态库位置
可以通过.bashrc永久生效
动态库加载错误:拷贝动态库到 /lib 路径
Linux的 /lib 路径,是标准C库的所在位置
动态库加载错误:/etc/ld.so.conf 配置库路径
gdb调试工具
TODO,对我来说不重要
makefile项目管理
用途
项目代码编译管理
节省编译项目时间
一次编写终身受益
基本规则
1规则
2个函数
3个自动变量
makefile就像一个脚本,通过执行 make 命令,执行项目根路径下的 Makefile 或者 makefile 脚本文件。
一个规则:
makefile的以来是从上到下的,换句话说就是目标文件是第一句里的目标,如果不满足执行以来就会继续向下执行。如果满足了生成目标的依赖,就不会继续向下执行了。make会自动寻找规则里需要的材料文件,执行规则下面的行为生成规则中的目标。
多文件联合编译:
上面这种编译方式,如果 add.c 有更改,其他c文件也要重新编译,C语言的编译速度很慢,可以改造为多个目标:
注意,上面的方式,test目标必须放在首位,因为makefile以文件中的第一个目标为终极目标,如果想指定终极目标可以使用ALL:
若想生成目标,检查规则中的依赖条件是否存在,则寻找是否有规则用来生成该以来文件
检查规则中的目标是否需要更新,必须先检查他的所有依赖,原来中有人一个被更新,则目标必须更新
分析各个目标和依赖之间的关系
根据依赖关系子弟向下执行命令
根据修改时间比目标新,确定更新
如果目标文件不依赖任何条件,则执行对应命令,以示更新
两个函数:
clean:
clean只有目标,没有依赖,在命令前增加 -,可以避免报错停止
三个自动变量:
$@:在规则命令中,表示规则中的目标$<:在规则命令中,表示规则中的第一个条件,如果将该变量用在模式规则中,它可以将依赖条件列表中的依赖依次取出,套用模式规则$^:在规则命令中,表示规则中的所有条件,组成一个列表,以空格隔开,如果这个列表中有重复项,则去重
使用三个变量修改makefile文件:
规则模式:
上面的makefile的规则模式为:
更改为规则模式为:
一个小型makefile项目的基本结构
系统调用
系统调用是内核提供的函数
库调用是程序库中的函数
文件IO
文件描述符

文件描述符是指向一个文件结构体(file_struct)的指针。PCB 进程控制模块为每一个进程维护一个文件描述符表,这个表最大长度为1024个,也就是说,每个进程最多可以打开1024个文件,其中有三个文件描述符 0 ,1 ,2 默认打开:
0 – STDIN_FILENO 标准输入
1 – STDOUT_FILENO 标准输出
2 – STDERR_FILENO 错误输出
并且,进程新打开的文件描述,整数值总是最小的。
open/close
作用: 以各种方式打开文件
返回值: 返回打开的文件句柄,-1 打开失败
函数说明 参数pathname 指向欲打开的文件路径字符串 , 既可以是相对路径也可以是绝对路径。 flags 参数有一系列常数值可供选择,可以同时选择多个常数用按位或运算符连接起来,所以这些常数的宏定义都以 O_ 开头,表示or
下列是参数flags 所能使用的旗标:
必选项:以下三个常数中必须指定一个,且仅允许指定一个。
O_RDONLY 以只读方式打开文件
O_WRONLY 以只写方式打开文件
O_RDWR 以可读写方式打开文件。上述三种旗标是互斥的,也就是不可同时使用,但可与下列的旗标利用OR(|)运算符组合。
以下可选项可以同时指定0个或多个,和必选项按位或起来作为flag参数。
O_CREAT 若欲打开的文件不存在则自动建立该文件。
O_EXCL 如果O_CREAT 也被设置,此指令会去检查文件是否存在。文件若不存在则建立该文件,否则将导致打开文件错误。此外,若O_CREAT与O_EXCL同时设置,并且欲打开的文件为符号连接,则会打开文件失败。
O_NOCTTY 如果欲打开的文件为终端机设备时,则不会将该终端机当成进程控制终端机。
O_TRUNC 若文件存在并且以可写的方式打开时,此旗标会令文件长度清为0,而原来存于该文件的资料也会消失。
O_APPEND 当读写文件时会从文件尾开始移动,也就是所写入的数据会以附加的方式加入到文件后面。
O_NONBLOCK 以不可阻断的方式打开文件,也就是无论有无数据读取或等待,都会立即返回进程之中。
O_NDELAY 同O_NONBLOCK。
O_SYNC 以同步的方式打开文件。
O_NOFOLLOW 如果参数pathname 所指的文件为一符号连接,则会令打开文件失败。
O_DIRECTORY 如果参数pathname 所指的文件并非为一目录,则会令打开文件失败。
第三个参数mode指定文件权限,可以用八进制数表示,比如0644表示-rw-r–r–,也可以用S_IRUSR、S_IWUSR等宏定义按位或起来表示,参数mode 则有下列数种组合,只有在建立新文件时才会生效,文件权限由open的mode参数和当前进程的umask掩码共同决定,因此该文件权限应该为(mode-umaks)。
S_IRWXU00700 权限,代表该文件所有者具有可读、可写及可执行的权限。
S_IRUSR 或S_IREAD,00400权限,代表该文件所有者具有可读取的权限。
S_IWUSR 或S_IWRITE,00200 权限,代表该文件所有者具有可写入的权限。
S_IXUSR 或S_IEXEC,00100 权限,代表该文件所有者具有可执行的权限。
S_IRWXG 00070权限,代表该文件用户组具有可读、可写及可执行的权限。
S_IRGRP 00040 权限,代表该文件用户组具有可读的权限。
S_IWGRP 00020权限,代表该文件用户组具有可写入的权限。
S_IXGRP 00010 权限,代表该文件用户组具有可执行的权限。
S_IRWXO 00007权限,代表其他用户具有可读、可写及可执行的权限。
S_IROTH 00004 权限,代表其他用户具有可读的权限
S_IWOTH 00002权限,代表其他用户具有可写入的权限。
S_IXOTH 00001 权限,代表其他用户具有可执行的权限。
mkdir
read/write
拷贝演示:
阻塞和非阻塞
阻塞是文件(设备文件、网络文件)的属性。
读取常规文件不会发生阻塞,不管读多少字节,read一定会在有限的时间内回应。从终端设备 或者网络读取则不一定。如果从终端输入的数据没有换行符,调用read读取终端设备就会发生阻塞,比较常见的就是一直等待输入。如果网络上没有收到数据包,调用read读取网络就会发生阻塞,并且阻塞的时间也是不确定的。
fcntl
fcntl用来改变一个【已经打开】的文件的 访问控制属性, 获取文件状态: F_GETFL,设置文件状态: F_SETFL
lseek
更改文件读写位置。
应用场景:
文件的“读”、“写”使用同一偏移位置。(读到100偏移位置,紧接着调用write写,是从101写)
使用lseek获取文件大小
使用lseek拓展文件大小:要想使文件大小真正拓展,必须引起IO操作。
使用 truncate 函数,直接拓展文件。 int ret = truncate("dict.cp", 250);
目录项和inode

一个文件主要由两部分组成,dentry(目录项)和inode:
inode本质是结构体,存储文件的属性信息,如:权限、类型、大小、时间、用户、盘快位置…也叫做文件属性管理结构
大多数的inode都存储在磁盘上。少量常用、近期使用的inode会被缓存到内存中。
所谓的删除文件,就是删除inode,但是数据其实还是在硬盘上,以后会覆盖掉。
最后更新于
这有帮助吗?