Linux基础和系统编程 上
-Linux系统编程
1.终端是一系列输入输出设备的总称。
2.Linux的终端是虚拟终端,有输入和输出。
3.终端里面内嵌了一个SHELL,是一个命令解析器。
4.cat /etc/shells
输入后会显示当前操作系统支持哪些SHELL。
5.echo $SHELL
查看当前操作系统正在用的SHELL。
6.bash和SHELL有一定差别
7.命令和路径补齐
敲tab可以补齐命令和文件
history
8.主键盘快捷键
Ctrl-p向上
Ctrl-n向下
Ctrl-b向左
Ctrl-f向右
Ctrl-a移到首位
Ctrl-e移到末尾
Ctrl-u清空
类Unix系统目录结构
1.cd ..回到上一级目录
ls查看
pwd查看当前目录
cd 目录 跳转到某一目录
2.根目录下重要的目录
bin存放可执行文件
boot存放开机启动历程
dev存设备,Linux系统所见皆文件
sudo cat mice查看鼠标文件
etc存当前用户相关的配置,比如password
home用户的目录
lib存库路径,如C库libc.so.6
media与磁盘有关
opt与linux编程进程有关
root用户,cd不进去
sudo su cd /root可以进去
user存用户的目录,用户存的第三方应用
3.不要随便用root用户
目录和文件操作
1.相对路径和绝对路径
cd ./home
cd - 返回到上一个目录
cd ~回到家目录
2.在home目录下面创建
mkdir 28_Linux
用绝对路径去28_Linux
cd /home/itcase/28_Linux/
或者
cd ~/28_Linux/
3.touch
新建空文件,或更新时间标记
4.ls -l
显示详细信息
ls -a
显示隐藏文件
ls -d
显示目录
ls -l dir
查看目录
ls -dl dir
查看目录本身
ls -R
递归记录
5.文件第一条为文件权限,第二个是硬链接计数,所有者,所属组,大小,时间,文件名。
6.权限分为:文件类型,所有者权限,同组用户权限,其他人权限。
7.Linux系统文件类型:
普通文件 -
目录文件 d
字符设备文件 c
块设备 b
软连接 l
硬链接是一种普通文件
管道文件 p
套接字 s
未知文件
8.which
查看指定命令所在路径,即命令所在目录位置
9.pwd
查看当前所在路径,即当前的目录位置
10.可以用终端配置取消掉目录显示
11.rmdir
删除空目录,目录非空不能删
12.rm -r可以删除非空目录
(-r意思是递归
13.rm dir -rf(rf意思是强制删除)
强制删除一个目录,有些版本非强制删除会提示
14.cp
拷贝命令,可以拷贝到目录。
15.略过目录dir
cp dir ..拷贝dir到上一级目录下,目录非空时,该命令不成功
cp -r dir ..
cp -a dir ..
cp dir1 dir2 -r
16.cat适合读小文件
查看文件中的内容cat hello.c
cat直接回车,会返回显示
tac 会让文件倒着显示
Linux维护,查看日志文件,用到tac
17.more
more stdio.h
空格翻页
可以分屏显示,适合查看大文件。
Ctrl+C,q终止显示
18.less
Ctrl+C,q终止显示
19.head
显示默认前10行
head -5显示前五行
tail -15 从后边查看
20.tree
不是自带的命令,安装命令是sudo apt-get install tree
把当前目录结构以树状展示
21.wc
统计字数和字节数
-c字节数
-l列数
-w字数
22.od 显示当前文件,指定数据显示格式
23.du查看目录大小
24.df查看磁盘剩余空间
软连接和硬链接
1.创建软连接
ln -s file file.s
给file创建软连接file.s
相当于windows的快捷方式
文件信息文件大小为访问路径大小
创建软连接到某目录用绝对路径,建立后可以用mv进行移动
软连接权限为rwx,不影响源文件权限
2.硬链接
ln file file.h
任意修改一个文件,会影响所有文件
创建修改用户和用户组
1.whoami 查看当前用户
2.chmod 修改一个文件属性
chmod u+x a.c(字母修改)
chmod o-r a.c
数字修改
r为4,w为2,x为1
chmod 471 a.c
chown 修改用户
sudo adduser wangwu
sudo addgroup g88
sudo chown wangwu a.c
sudo chgrp g88 a.c
sudo chown nobody:nogroup a.c
sudo deluser wangwu删除用户
find
1.find ./ -type 'l' 按类型查找
2.find ./ -name '*.jpg' 按文件名字查找
3.find ./ -maxdepth 2 -name '*.jpg' 路径层数
4.find ./ -size +20M -size -50M 按文件大小搜索
find ./ -size +20k -size -50k
find ./ -size +20G -size -50G
5.块是磁盘的最小区域,块为512字节。
6.-atime
-mtime
-ctime
find ./ -ctime 1
按修改时间
7.-exec
find /user/ -name "tmp" -exec ls -l { } \;
find /user/ -name "tmp" -exec rm -r { } \;
find /user/ -name "tmp" -ok rm -r { } \;
8.xargs 当find的搜索结果集执行某一指定命令时,当结果集数量过大时,可以分片映射
9.-print0
grep和xargs
1.grep 根据内容搜索
grep -r 'copy' ./
grep -r 'copy' ./ -n(加-n会出现行号)
ps aux 显示后台进程
ps aux | grep kernel
结合管道搜索后台进程
find -maxdepth 1 -type f | xargs ls -l
2.touch abc xyz 会创建两个文件,想创立一个文件,解决办法是touch 'abc xyz'
touch abc\ xyz
此时用find -maxdepth 1 -type f | xargs ls -l
不会搜到abc xyz,该命令搜索会按空格拆分
find -maxdepth 1 -type f -print0 | xargs -print0 ls -l
可以将拆分依据改为0
xargs加强和awk说明
1.find -maxdepth 1 -type f -print0 | xargs -print0 ls -l
可以简化为
find -maxdepth 1 -type f -print0 | xargs -0 ls -l
2.awk按照列拆分
sed按照行拆分
软件包的安装
1.apt-get更新源服务器列表。
sudo apt-get install tree
2.安装一个程序需要
联网
更新软件资源列表到本地 sudo apt-get update
安装 sudo apt-get install 软件名
卸载 sudo apt-get remove 软件名
3.有安装包时,可以离线安装
ubuntu安装包都以.deb结尾
sudo dpkg -i sl_3.03.deb
sudo apt-get
4.原码安装
cd dir
./configure
make
sudo make install
sudo make distclean
压缩命令gzip和bzip2
1.tar zcvf 要生成的压缩包名 压缩材料
tar不是用来压缩是用来打包
2.gzip 文件名
gunzip 解压缩
只能压缩文件
3.file 文件可以查看文件
4.bzip2不能压缩多个文件和目录
tar jcvf
解压 :将压缩命令中的c替换为x
1.rar需要安装
rar a -r newdir dir
unrar x 文件名
2.sudo apt-get install apititude 安装apititude
sudo aptitude / apt-get install rar/tree/unrar
sudo aptitude show tree 显示是否安装
sudo aptitude install tree 用apititude进行安装
3.zip压缩和zip解压
压缩命令: zip -r 压缩包名称 文件或普通目录
解压命令: unzip 压缩包名称
其他命令
1.who
查看是谁,显示进程
whoami
2.jobs
当前shell下正在运行哪些作业
cat & 让在后台运行
3.fg把指定的后台作业或挂起的作业移到前台
bg把挂起的进程提到后台执行
4.kill杀死进程
5.env 查看当前操作系统所有的环境变量
env | grep SHELL
6.top 文字版的任务管理器
7.sudo passwd itcast
设置密码
8.su 用户 用来切换用户
9.sudo su 变成root用户
设置root密码
passwd
10.删除用户 sudo userdel -r itcast
11.查看网卡信息,当前的IP地址:ifconfig
关闭网卡 sudo ifconfig eth0 down
开启网卡 sudo ifconfig eth0 up
给eth0配置临时IP:sudo ifconfig eth0 IP
12.man 是一个帮助手册 掌握123章
13.clear清屏 可以用Ctrl+L
14.date 显示时间
15.alias 可以给命令起名
例如alias pg='ps aux | grep'
16.umask 指定用户创建文件文件时的掩码
掩码没有执行权限
输入umask出现数字首位是0,是8进制
17.创建终端
创建终端标签Ctrl+Shift+t
切换标签Alt+n(n=1)
新开终端Ctrl+Shift+n
18.关机重启
poweroff直接关机
shutdown
reboot 重启
uname -a 查看内核版本信息
free -m 查看空闲内存
vim的三种工作模式
1.vi有三种工作模式:命令模式,文本模式,末行模式
2.vi hello.c 进入命令模式
i a o,I A O,s S切换到文本模式
文本模式进入末行模式,需要切换成命令(点击ESC),再输入":"进入末行模式
3.末行命令 w保存 q退出
4.可以从命令模式直接退出 ZZ,ZZ是保存退出
5.末行模式按ESC可以回到命令模式,输入w也可以回到命令模式
vim的基本操作-跳转和删字符
1.输入S会删除一行进入文本模式
输入s会删除一个字符进入文本模式
2.h左移
l右移
j下移
k上移
hjkl左下上右
3.跳转到指定行
命令模式输入行号+G
末行模式输入行号可以进入指定行
4.跳转文件首
gg(命令模式)
5.跳转文件尾
G(命令模式)
6.自动格式化程序
gg=G(命令模式)
7.大括号对应
%(命令模式)
8.删除单个字符
x(命令模式)
9.删除一个单词
dw(命令模式,光标置于首字母)(delete word)
10.删除某个字符到结尾
D(命令模式)
d$(命令模式)
11.删除光标模式到行首
d0(命令模式)
12.光标移到行首
0(命令模式)
13.光标移到行位
$(命令模式)
vim基本操作-删除
1.在命令模式下
光标选中字符
按r按要替换的字符可以替换
2.命令模式下按V,用hjkl挪移光标选中要删的部分,按d(delete)
3.dd,删除指定行,光标所在行按dd
4.删n行,光标放在要删的第一行,n(n为要删的行数)dd
vim基本操作—复制粘贴
1.复制一行
yy
复制多行 nyy
2.粘贴
p
会粘贴到光标所在行下一行
P
会粘贴到光标所在行的上一行
3.所有删除的内容都是剪切的内容,可以粘贴
vim基本操作-查找替换
1.找设想内容,
命令模式下按”/“,输入查找的词,回车
使用n检索下一个
2.找看到的内容
把单词选在单词任意一个字符上,按*往后找
按#往前找
3.光标移到要替换的行上
换到末行模式
输入:s /原数据/替换数据
4.通篇替换
进入末行模式
:%s /原数据/替换数据 (只是替换末行第一个)
:%s /原数据/替换数据/g(可以替换每行所有数据)
5.替换某个区域的数据
进入末行模式
:1起始行号,终止行号s /原数据/替换数据/g
6.切换到末行模式
Ctrl+p切换到上一条命令
Ctrl+n切换到下一条命令
vim基本操作-其他
1.命令模式下u,撤销命令
反撤销(撤销撤销命令)Ctrl+r
2.分屏
:sp(末行模式)
切为上下两部分
可以不断分屏
Ctril+ww可以切换光标所在分屏
:q
退出当前分屏
:qall
退出当前所有分屏
:vsp
分竖屏
3.将光标置于要查看单词上面
命令模式按K,指定卷nK
进入man page
4.查看宏定义
{d(命令模式)
查看定义语句
vim基本操作-其他
5.在末行模式下,
:! shell命令
vim配置思路
cd /etc/vim
vi vimrc
上引号开头的是注释
gcc编译四步骤
1.四步骤:预处理,编译,汇编,链接
2.hello.c预处理hello.c
预处理:展开宏,头文件
替换条件编译
删除注释,空行,空白
gcc -E
3.编译得到hello.s
编译:检查语法规范
gcc -S
4.汇编得到hello.o,是一个二进制文件
汇编:将汇编指定翻译成机器指令
gcc -c
5.链接生成a.out
链接:数据段合并,地址回填
6.消耗时间和系统资源最多是编译
gcc编译常用参数
1.头文件和原码不在同一级目录下,需要指定头文件
gcc -I头文件所在目录 hello.c -o hello
-I: 指定头文件所在目录位置
2.-c:只做预处理,编译,汇编,得到二进制文件
3.-g:编译时添加调试语句
gdb调试工具,编写程序时出现的语法错误之外的东西
4.-On n=1~3 编译优化,n越大优化越多
5.-Wall 显示所有的警告信息
6.-D:向当前的程序当中“动态”注册一个宏定义
一般作为开关,需要用到调试语句时打开
动态库和静态库理论对比
1.使用库可以提高编写效率
2.静态库是以静态文件的形式存放
静态库需要和源程序一起编译到可执行文件当中
优点是调用速度快
适用于:对空间要求较低,对时间要求较高的核心程序中
启动程序用到的是静态库
3.动态库(共享库)
适用于:对时间要求较低,对空间要求较高
4.大多数情况下使用动态库
静态库制作
1.静态库编译:
第一步:先将编写的c文件编译
gcc -c 文件名.c -o 文件名.o
第二步:ar rcs lib库名.a file1.o
2.编写程序用到库中的内容时,需要将库与C语言原程序一起编译
gcc 文件名.c lib库名.a -o test
./test
静态库使用及头文件对应
1.gcc 文件名.c lib库名.a -o test -Wall
-Wall会显示所有的警告信息
2.需要有函数定义和函数声明,否则系统会做隐式声明
隐式声明所识别的是int add(int,int);
不是隐式声明的格式会出现错误而不是警告
3.头文件首位
#ifndef MYMATH_H
#define MYMATH_H
#endif
在要执行的C语言原程序中输入
#include "mymath.h"
动态库制作及使用
1.制作过程
第一步:将.a文件生成.o文件(要求生成与位置无关的代码 -fPIC)
gcc -c 文件名.c -o 文件名.o -fPIC
第二步: 使用 gcc -shared 制作动态库
gcc -shared -o lib库名.so 文件名.o(这些原文件与制作静态库的原文件不同,差-fPIC)
第三步:编译可执行程序时,指定所使用的动态库
-l用来指定库
-L指定库路径
gcc test.c -o a.out -l动态库名(要去掉lib和.so) -L./lib
第四步:运行可以执行的程序
./a.out
2.延迟绑定:动态库绑定地址相较静态库要晚
3.LSB表示小端码存储
动态库加载错误原因及解决方式
1.
error while loading shared libraries: libraries.so: cannot open shared object file: No such file or directory
运行可以执行的程序
./a.out 出错!!!!!
原因:链接器: 工作于链接阶段,工作时需要 -l 和 -L
动态链接器: 工作于程序运行阶段,工作时需要提供动态库所在目录位置
2.
解决办法:通过环境变量:export LD_LIBRARY_PATH=./lib(动态库路径)
./a.out
3.
永久生效办法:环境变量是进程概念,关掉终端再次打开环境变量不在生效,应该修改配置文件
.bashrc建议使用绝对路径
第一步:vi ~/.bashrc
第二步:写入export LD_LIBRARY_PATH=./lib 然后:wq
第三步: . .bashrc或者source .bashrc
第四步:重启终端
./a.out
4.C库是动态库
5.ldd a.out
会显示运行程序之后会加载哪些动态库
6.拷贝自定义动态库到/lib(标准C库所在位置)
sudo cp lib库名.so /lib/x86_64-linux-gnu/
不建议使用该方法
7.配置文件法(永久修改)
第一步:sudo vi /etc/ld.so.conf
第二步:写入动态库绝对路径,保存
第三步:sudo ldconfig -v
a.out
改变动态库的绝对路径会使这个方法失效
数据段合并
1.
stack高地址向低地址用
heap低地址向高地址用
@plt位于user
2.text段不能任意改变,只读 ro
rodata存放常量和只读数据 ro
text rodata可以合并
bss和data权限为rw
bss和data可以合并
3.Linux下,一次最少使用4K内存
gdb调试基础指令
1.gcc检查语法错误
2.-g 使用该参数编译可以执行文件,得到调试表
gcc -g main.c -o main(加了-g才能用gdb)
3.gdb检查逻辑错误
4.gcc 文件名.c -o gdbtest
5.gcc 文件名.c -o gdbtest2 -g
6.gcc gdbtest.c -o a.out -g 编译
gdb a.out 进入调试
在(gdb)后面加“l”或者“list”
在(gdb)后面加“list 1”,使得从第一行开始显示十行,再在(gdb)后面再写”l“,会出现后续的行
7.设置断点
在gdb后面输入“break”和“b”
e.g
b 52
8.(gdb)后输入run,执行程序到断点处,断点处语句没有执行
(gdb)后面输入“s”或“step”,下一条命令,不会越过函数
(gdb)后面输入“n”或“next”,下一条命令,会越过函数
9.如果函数是系统函数只能用“n“,不能用”s”
10.until 循环次数 可以退出循环
11.p 变量
print 变量
可以查看变量
12.continue
继续执行断点后续命令
13.quit:退出gdb当前调试
其他命令gdb调试1.用gdb调试查找段错误出现位置
段错误是访问了不可访问的内存
用gdb打开一个程序,直接“run”,程序停下的位置就是段错误的位置
2.start
默认从当前程序第一行开始运行
3.finish 可以结束当前函数调用,回到函数的调用点
4.set args 设置main函数命令行参数
可以有带参数的main函数,在“./文件名”后面加上参数
在(gdb)后面加上“set args 参数 参数”(要设置在start之前),可以加入参数
5.run 参数 参数2,设置main函数参数
6.display
7.info b 查看断点信息
8.条件断点:b 行号 if 变量=数据
e.g b 20 if i=5
一般用于循环
9.ptype 变量 查看变量类型
在子函数中不能查看没有通过参数传入子函数的变量
10.栈里面存放栈帧
栈帧是随着函数调用而在stack上开辟的一片内存空间,用于存放函数调用时时产生的局部变量和临时值
有一个函数调用就会产生一个栈帧,调用结束,栈帧消失
调用子函数main函数的栈帧不会消失,因为main函数没有结束
子函数栈帧中有形参和局部变量,子函数调用结束,子函数栈帧消失
11.利用指针可以在一片栈帧去修改另一片栈帧的值
12.backtrace:查看函数调用的栈帧和层级关系
frame:根据栈帧编号切换栈帧
bt:查看栈帧(#后面的是栈帧号)
frame 栈帧号
13.display 变量 设置跟踪变量
undisplay 变量 取消设置跟踪变量
gdb常见错误说明
常见错误
编译没有加“-g”
用gdb打开文件
list会出现 没有符号被读取,请使用“file”命令
解决方法
1.quit,重新编译
2.file a.out(a.out必须经过gdb调试)
makefile
1.Makefile实际上是一个脚本文件,脚本把一些命令的集合批量放在一个文件里,统一执行。脚本可以干任何事情,Makefile用处单一。
2.Makefile里面内容
gcc hello -o hello
hello:hello.c
gcc hello.c -o hello(必须有一个tab缩进)
3.Makefile重要内容
命名:
1.makefile
2.Makefile
备注:如果是其他名字,则不能使用make命令
一个规则:
目标:依赖条件
(一个tab缩进)命令
1.目标的时间必须晚于依赖条件的时间,否则,更新目录
2.依赖条件如果不存在,找寻新的规则去产生依赖
默认第一个是终极目标,可以写入“ALL:文件名”,规定生成的最终文件
基本规则:1.若想生成目标,检查规则中的依赖条件是否存在,如不存在,则需要寻找是否有规则用来是生成该依赖文件
2.检查规则中的目标是否需要更新,必须先检查它的所有依赖,依赖中有任意一个被更新,则目标必须更新
两个函数:
wildcard函数
src=$(wildcard*.c) :匹配当前工作目录下所有.c文件,将文件名赋值给列表,赋值给变量src
patsubst把src变量里所有后缀为.c的文件替换成.o
obj=$(patsubst %.c,%.o,$(src))将参数3中,包含参数1的部分,替换成参数2
3个自动变量:
$@ 表示规则中的目标,在规则的命令中(在依赖条件中不行),表示规则中目标
$< 表示规则中的第一条件(再规则的命令中)
$^ 表示规则中的所有条件,组成一个列表(再规则的命令中)如果将该变量应用在模式规则中,它可将依赖条件列表中依赖一次取出,套用模式规则
4.Makefile下另一种写法
hello:hello.o
gcc hello.o -o hello
hello.o:hello.c
gcc -c hello.c -o hello.o
5.终端输入命令“make”
得到编译后的文件
6.多个文件生成可执行文件用makefile
a.out:hello.c add.c sub.c div1.c -o a.out
gcc hello.c add.c sub.c div.c -o a.out
7.
a.out:hello.o add.o sub.o div1.c -o a.out
gcc hello.o add.o sub.o div.o -o a.out
hello.o:hello.c
gcc -c hello.c -o hello.o
add.o:add.c
gcc -c add.c -o add.o
sub.o:sub.c
gcc -c sub.c -o sub.o
div.o:div.c
gcc -c div.c -o div.o
8.makefile可以写入
clean: (clean没有依赖条件)
-rm -rf 文件名
‘-’作用是删除不存在文件时,不报错
终端输入
make clean -n
模拟执行
make clean
执行
9.“#”是makefile里面的注释符号
10.模式规则
比如都是.o文件依赖于.c文件
可以写成:
%.o:%.c
gcc -c $< -o $@
系统编程阶段说在前面的话
1.系统调用:
内核是当前操作系统的核心程序,服务于上层应用
Linux2.6有270多个函数
库函数数量很大
操作系统可以粗略看成内核
2.Linux原码没有open函数
3.浅封装
4.内核主要包括驱动程序,每一个驱动程序对应一个硬件设备,比如显卡,声卡,网卡
5.一个普通用户不能进内核,只有用系统调用才能进内核
比如printf函数通过write函数传给sys_write,进入内核,找到驱动
open函数
1.open/close函数
2.open函数有两种,一个有两个参数,一个有三个参数
3.const表示只读
pathname路径名
4.open函数会返回一个整数,打开成功返回-1
5.mode_t八进制的整型
6.fiag取值
O_RDONLY O_WRONLY O_RDWR
O_APPEND(追加) O_CREAT(创建) O_EXCEL(是否存在) O_TRUNC(截断) O_NONBLOCK(非阻塞)
7.#include<unistd.h>包含open
#include<fcntl.h>包含O_RDONLY
8.示例
#include<unistd.h> #include<fcntl.h> #include<stdio.h> int main() { • int fd; • fd=open("./dict.cp",O_RDONLY | O_CREAT,0644); • printf("fd=%d\n",fd); • close(fd); • return 0; }
9.O_TRUNC
#include<unistd.h> #include<fcntl.h> #include<stdio.h> int main() { int fd; fd=open("./dict.cp",O_RDONLY | O_CREAT,0644 | O_TRUNC,0644); printf("fd=%d\n",fd); close(fd); return 0; }
文件若存在,截断成0,文件不存在,创建文件
10.创建文件时,指定文件访问权限,权限同时受umask影响
文件权限=mode&~umask
11.open常见错误
错误一:打开文件不存在:
#include<unisted.h> • #include<fcntl.h> • #include<stdio.h> #include<errno.h> #include<string.h> • int main() • { • int fd; • fd=open("./dict.cp4",O_RDONLY); • printf("fd=%d,errno=%d:%s\n",fd,errno,strerror(errno)); • close(fd); • return 0; • }
输出:fd=-1,errno=2:No such file or dictionnary
errno是内核变量,不需要定义
strerror翻译errno
错误二:以写方式打开只读文件
Permission denied 权限被拒绝
错误三:以只写方式打开目录
fd=-1,errno=21:Is a directory