Linux系统基础学习笔记
一、shell
Unix shell Bon
Linux bash
查看shell cat /etc/shell
bash字体放大ctrl+shift++
恢复正常ctrl+0
功能 | 快捷键 | 助记 |
---|---|---|
上 | ctrl+p | |
下 | ctrl+n | |
左 | ctrl+b | |
右 | ctrl+f | |
del | ctrl+d | delete光标之后的 |
Home | ctrl+a | the first letter |
End | ctrl+e | end |
Backspace | backspce | 删除光标之前的 |
二、目录结构
bin:存放二进制可执行文件
boot: 存放开机启动程序
dev: 存放设备文件
home: 存放用户
etc: 用户信息和系统配置文件
lib: 库文件
root: 管理员宿主目录(家目录)
usr: 用户资源管理目录
Linux文件类型:
普通文件:-
目录文件: d
字符设备文件: c
块设备文件:b
软连接:l
管道文件: p
套接字:s
未知文件
三、vim
vim三种模式转换关系如下图所示:
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-xoKaWC2a-1608271664677)(/media/libaisong/学习资料/A工作相关/Linux系统编程图片/vim三种模式转换关系.jpg)]
文本模式下的操作
i: 光标之前拆插入
a: 光标之后插入
o: 光标所在行的下一行行首
I: 光标所在行的行首
A: 光标所在行的行尾
O: 光标所在行的上一行行首
s: 删除一个字符的模式
S: 删除一正行为代价切换工作模式
命令模式下的操作:
h : 左移
j : 下移
k : 上移
l : 右移
跳转到指定行: 88G(命令模式) :88(末行模式)
跳转文件首:g(命令模式) 跳转文件尾 : G(命令模式)
自动格式化程序:gg=G(命令模式)
匹配大括号(小括号)对应:%(命令模式)
光标移动至行首:0;光标移动至行尾:$ (命令模式)
删除单个字符:x(命令模式)
替换单个字符:光标选中代替换的字母,按下,r再输入替换的字母
删除指定区域:按V 切换为“可视模式”,使用hjkl移动光标选择删除区域,再按D删除
整行删除:dd
删除制定N行:光标在删除首行,输入Ndd
删除一个单词:dw
删除光标前的所有字符,并移动光标至行首:d0
删除整行,并移动光标至行尾:D 或 d$
复制粘贴:
yy:复制一行
p : 粘贴到光标所在下一行
P(大写):粘贴到光标所在上一行
粘贴块:按V选择粘贴区域,yy复制。p/P粘贴
查找替换:
-
1、查找设想内容:命令模式 /+查找内容。 n:查找下一个
-
2、查找看到的内容:在命令模式下,将光标置于单词的任意一个字符上,按 # / * 查找。
-
3、单行替换:光标在替换行上,进入末行模式,输入 😒 /原数据/新数据。
-
4、通篇替换:光标在替换行上,进入末行模式,输入 :%s /原数据/新数据,(只会替换每一行的第一个);输入 :%s /原数据/新数据/g
-
5、区域(指定行)替换:%其实行号:终止行号s /原数据/新数据.
-
6、末行模式:ctr+p : 呼出之前的操作命令; ctr+n
-
7、撤销:u(命令模式)、反撤销:ctrl+r
分屏::sp (末行模式分横屏) ctr+ww 在不同屏幕中切换
:vsp (竖屏分)
![](/media/libaisong/学习资料/A工作相关/Linux系统编程图片/分屏操作.png)
跳转至man手册:
- 蒋光标置于代查看的函数单词上,使用 K(命令模式) 跳转,可以指定具体第几卷,3K
- 查找宏定义:[d (命令模式)
在末行模式执行shell命令:
:!命令 :!ls -l
配置头文件
-
切换至root账户:sudo su
-
切换到vim文件夹,打开vimrc配置文件
cd /etc/vim
- 打开vimrc配置文件
vim vimrc
-
"添加头文件 """"""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""" """""新文件标题"""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""" "新建.c,.h,.sh,.java文件,自动插入文件头 autocmd BufNewFile *.[ch],*.hpp,*.cpp exec ":call SetTitle()" "加入注释 func SetComment() call setline(1,"/*===============================================================") call append(line("."), "* Copyright (C) ".strftime("%Y")." All rights reserved.") call append(line(".")+1, "* ") call append(line(".")+2, "* 文件名称:".expand("%:t")) call append(line(".")+3, "* 创 建 者:李柏松") call append(line(".")+4, "* 创建日期:".strftime("%Y年%m月%d日")) call append(line(".")+5, "* 描 述:") call append(line(".")+6, "*") call append(line(".")+7, "* 更新日志:") call append(line(".")+8, "*") call append(line(".")+9, "================================================================*/") endfunc "定义函数SetTitle,自动插入文件头 func SetTitle() call SetComment() if expand("%:e") == 'hpp' call append(line(".")+10, "#ifndef _".toupper(expand("%:t:r"))."_H") call append(line(".")+11, "#define _".toupper(expand("%:t:r"))."_H") call append(line(".")+12, "#ifdef __cplusplus") call append(line(".")+13, "extern \"C\"") call append(line(".")+14, "{") call append(line(".")+15, "#endif") call append(line(".")+16, "") call append(line(".")+17, "#ifdef __cplusplus") call append(line(".")+18, "}") call append(line(".")+19, "#endif") call append(line(".")+20, "#endif //".toupper(expand("%:t:r"))."_H") elseif expand("%:e") == 'h' call append(line(".")+10, "#pragma once") elseif &filetype == 'c' call append(line(".")+10,"#include <stdio.h>") call append(line(".")+11,"#include <stdlib.h>") call append(line(".")+12,"#include <sys/types.h> // 基本数据类型的头文件") call append(line(".")+13,"#include <sys/stat.h> //文件状态所在的伪标准头文件") call append(line(".")+14,"#include <unistd.h> //有read\\write等函数") call append(line(".")+15,"int main(int argc, char* argv[])") call append(line(".")+16,"{") call append(line(".")+17," ") call append(line(".")+18," ") call append(line(".")+19," return 0;") call append(line(".")+20,"}") elseif &filetype == 'cpp' call append(line(".")+10, "#include \"".expand("%:t:r").".h\"") endif "新建文件后,自动定位到文件末尾 autocmd BufNewFile * normal G endfunc
四、gcc
gcc编译四阶段
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-0Z3ett19-1608271664680)(/media/libaisong/学习资料/A工作相关/Linux系统编程图片/gcc编译程序4步骤.png)]
-
gcc常用命令参数
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-zGeKrEQP-1608271664683)(/media/libaisong/学习资料/A工作相关/Linux系统编程图片/gcc常用命令参数.png)]
gcc常用命令:
- -I: 指定头文件所在目录
- -c:只做预处理、编译、汇编,不链接。得到二进制文件。
- -o:-o filename 生成名字为filename的可执行文件,如果不指定名字,则默认为a.out
- -g:编译时添加调试语句,主要支持gdb调试
- -Wall:显示所有警告信息
- -D: 向程序中”动态“注册宏定义
五、动态库和静态库
1、区别
静态库实际上是将该库复制到使用该库的函数中,因此占用空间大。在使用时才动态绑定
静态库:对空间要求较低,对时间要求较高的核心程序中。
动态库:对空间要求较高,对时间要求较低的核心程序中。
2、静态库
2.1 制作静态库步骤
ar rcs/rs libmylib.a xxx.o xxx.o
- 1、编译自定义的函数
//加法静态库 add.c
int add(int a, int b)
{
return a+b;
}
//减法静态库 sub.c
int add(int a, int b)
{
return a - b;
}
- 2、将.c函数编译为 .o文件
gcc -c add.c -o add.o //将add.c文件编译为.o文件
gcc -c sub.c -o sub.o //将sub.c文件编译成.o文件
这儿也可以使用gcc -c add.c
,直接生成add.o
- 3、使用
ar rs libxxx.a xx.o xx.o...
:将.o文件制作成静态库
ar rcs libmyMath.a add.o sub.o dev1.o
- 4、使用静态库(编译静态库到可执行文件中)
gcc testStaticlib.c libMyMath.a -o test; //编译
./test //执行
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-xatePmiU-1608271664686)(/media/libaisong/学习资料/A工作相关/Linux系统编程图片/静态库执行结果.png)]
上图中的implicit警告信息,是因为编译器在碰到函数时需要知道函数的声明或定义,否则编译器就会做隐士声明。
==但是编译器只能声明 返回值为int类型的函数。==如果是其他类型则会出现错误,而不是warning
所以使用一个.h包含文件声明
头文件守卫:防止头文件被重复包含
#ifndef \_MYMATH_H_
#define \_MYMATH_H_
int add(int,int);
int sub(int, int);
#endif
3、动态库
制作动态库的步骤:
- 1、将 .c 生成为 .o 文件(生成与位置无关的代码 -fPIC)
gcc -c add.c -o add.o -fPIC
- 2、使用 gcc -shared 制作动态库
gcc -shared -o lib库名.so add.o sub.o div1.o
- 3、编译可执行程序时,指定使用的动态库
- -l: 指定库名
- -L: 指定库路径
- -I(大写字母i):指定头文件 .h 路径
gcc test.c -o a.out -lmyMath -L
gcc testDayLib.c -o a.out -lmyMath -L./lib -I./inc
-
4、运行 a.out出错:./a.out: error while loading shared libraries: libmyMath.so: cannot open shared object file: No such file or directory. ldd a.out查看错误信息
- 原因(动态链接器未找到库):
- 链接器:工作于链接阶段,工作需要 -l -L 指定库名和库文件路径
- 动态链接器:工作与程序运行阶段,工作时需要提供动态库所在目录的位置
- 链接器和动态链接器没有关系
- 解决方法:
【1】通过环境变量改变,使其找到动态可所在目录的位置。
-
export LD_LIBRARY_PATH=./lib/
-
再次运行 ./a.out成功 (临时生效。这只是单次生效,重启终端后失效)
【2】更改 ~/.bashrc文件使其上面的操作永久生效。
1.vi ~/.bashrc 打开bashrc文件
- 写入 export LD_LIBRARY_PATH=./lib/ 保存
- (1) . .bashrc; (2) source.bashrc; (3) 重启终端 (让其生效的三种方法),让修改后的bashrc文件生效。
- 运行./a.out成功
【3】将自定义库拷贝到 /lib (系统c库)
【4】修改配置文件
- sudo vi /etc/ld.so.conf
- 写入动态库绝对路径
- sudo ldconfig -v 使配置文件生效
- ./a.out 成功 可以使用 ldd a.out查看详细信息
- 原因(动态链接器未找到库):
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-FMt9XIoL-1608271664687)(/media/libaisong/学习资料/A工作相关/Linux系统编程图片/内存分布.png)]
地址回填:
六、gdb
七、makefile项目管理
八、文件操作
man 2 函数名字:查看函数具体的使用
1. open()函数
//SYNOPSIS
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
//函数原型
int open(const char *pathname, int flags); //打开已有文件
int open(const char *pathname, int flags, mode_t mode); //打开已有文件,如果不存在则创建,指定文件的访问权限
int creat(const char *pathname, mode_t mode);
int openat(int dirfd, const char *pathname, int flags);
int openat(int dirfd, const char *pathname, int flags, mode_t mode);
int open(const char *pathname, int flags, mode_t mode);
/*
pathname:文件路径
flags:
主类:O_RDONLY, O_WRONLY, or O_RDWR
副类:O_CLOEXEC, O_CREAT(不存在就创建), O_DIRECTORY, O_EXCL, O_NOCTTY, O_NOFOLLOW, O_TMPFILE, O_TRUNC(如果文件已存在则删除原文件中原有数据), O_APPEND(以追加的方式打开)
mod:参数2指定了O_CREAT,取8进制数,设置文件的访问权限。
但是注意:创建文献的最终权限 = mode & ~umask(umask默认为0022(八进制),取反之后为 0111 1101 1101)
返回值:成功返回对应的文件描述符。失败返回-1
*/
#include<stdio.h>
#include<stdlib.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
int main()
{
int fd1 = open("./test01.txt", O_RDONLY|O_CREAT,0777);
printf("fd1 = %d\n",fd1);
return 0;
}
2. read()函数
#include<stdio.h>
#include<stdlib.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include<unistd.h>
int main()
{
//函数原型:ssize_t read(int fd, void *buf, size_t count);
//ssize_t: 表示有符号整型,size_t表示无符号整型
//buf: 存数据的缓冲区
//count: 缓冲区的大小,一般为1024或2048
//返回值:ssize_t类型,
// 失败的返回-1, 0表示读到文件末尾, 其他整数为读取数据的大小
//返回-1 , 并且errno = EAGIN或 EWOULDBLOCK 说明不是read失败,而是read在以 【非阻塞方式】 读一个设备文件或网络文件,并且文件无数据
int fd1 = open("./open.c",O_RDONLY|O_CREAT,0742);
char buf[1024]; //缓冲区一般定义为1024或2048个字节大小
int fd = read(fd1, buf, 1024);
printf("读取字节数为:fd1 = %d\n",fd);
close(fd1);//关闭文件
return 0;
}
3. write()函数
#include<stdio.h>
#include<stdlib.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include<unistd.h>
#include<string.h>
int main()
{
//函数原型:ssize_t write(int fd, const void *buf, size_t count);
//fd:文件描述符
//buf:缓冲区
//count:写入的字节数
//返回值:写入的字数节,-1为错误
char buf[1024]; //缓冲区
int n = 0; //n为每次写入的字节数
int fd1 = open("./open.c",O_RDONLY); //read
int fd2 = open("./test03.c",O_RDWR|O_CREAT|O_TRUNC,0664); //write,注意权限,要设置未可以write,即RDWR
while((n = read(fd1,buf,1024)) != 0)
{
int res = write(fd2,buf,n);
if(res == -1){ //如果为-1,则出现错误
perror("open error"); //perror为系统函数,自动打印错误信息
exit(1); //退出
}
printf("写入的字节数为:res = %d\n",res);
}
close(fd1); //不要忘记关闭文件
close(fd2);
return 0;
}
4.文件描述符
4. 1 预读入缓输出
- strace命令查看具体执行过程,可以查看到fputs默认4096k数据,才切换到内核态写入、读取数据。而read、write函数时系统函数,指定buf的大小为多少,就固定多少字节数据切换一次用户态到内核态读取、写入数据
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-g3wzPqwd-1608271664688)(/media/libaisong/学习资料/A工作相关/Linux系统编程图片/预读入缓输出.png)]
4.2 文件描述符
- PCB进程控制块,本质是结构体
- 结构体成员对应的是文件描述符表
- 文件描述符:0/1/2/3/…/1023。使用原则是使用文件描述符中最小能够使用的
- 0—STDIN_FIFENO; 1—STDOUT_FIFENO; 2—STDERR_FIFENO
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-Wr0FGLcA-1608271664689)(/media/libaisong/学习资料/A工作相关/Linux系统编程图片/PCB文件描述符.png)]
5.阻塞、非阻塞
产生阻塞的场景:读设备文件和网络文件(读常规文集爱你无阻塞概念)
/dev/tty —终端文件
阻塞、非阻塞是设备文件的属性
6. fcntl修改文件属性
#include <unistd.h>
#include <fcntl.h>
//函数原型
int fcntl(int fd, int cmd, ... /* arg */ );
int flags = fcntl(fd, F_SETEL);
flag |= O_NONBLOCK;
fcntl(fd, F_SETEL, flag);
//获取文件状态:F_GETFL
//设置文件状态:F_SETFL
7. lseek()函数
#include <sys/types.h>
#include <unistd.h>
//函数原型
off_t lseek(int fd, off_t offset, int whence);
- 参数:
fd:文件描述符号
offset:偏移量
whence:从何处开始偏移,取值 SEEK_SET/SEEK_CUR/SEEK_END 如下所示:
SEEK_SET
The file offset is set to offset bytes.
SEEK_CUR
The file offset is set to its current location plus offset bytes.
SEEK_END
The file offset is set to the size of the file plus offset bytes. - 返回值:
成功:校起始偏移位置的偏移量
失败:-1 errno - 应用场景:
- 文件的“读”、“写”使用同一偏移位置
- 使用lseek获取文件大小
- 使用lseek扩展文件大小:要想使文件大小真正扩展,必须引起IO操作
- 使用truncate函数,直接扩展文件
8. 传入传出参数
1. 传入参数
- 指针作为函数参数
- 通常由const关键字修饰
- 指针指向有效区域,在函数内部**做读操作**
starcpy:
2. 传出参数
- 指针作为函数参数
- 在函数调用之前,指针指向的空间可以无意义,但必须有效
- 在函数内部,做写操作
- 函数调用结束后,充当函数返回值
strcpy(): char *strcpy(char *dest, const char *src);
3.传入传出参数
- 指针作为函数参数
- 在函数调用之前,指针指向的空间有实际意义
- 在函数内部,先做读操作,后做写操作
- 函数调用结束后,充当函数返回值
9. stat()函数
函数原型:int stat(const char *path, struct stat *buf)
参数:
- path: 文件路径
- buf: (传出参数)存放文件属性
返回值
- 0: 成功
- -1: 失败,errno
#include <sys/types.h>
#include <sys/stat.h>
#include <unistd.h>
#include<stdio.h>
#include<stdlib.h>
int main(int argc, char* argv[])
{
struct stat subuf;
int ret = stat(argv[1], &subuf);
if(ret == -1)
{
perror("stat error");
}
printf("file size: %ld\n",subuf.st_size);
// printf("file mode");
return 0;
}
-
获取文件大小:buf.st_size
-
获取文件类型: buf.st_mode
-
获取文件权限: buf.st_model
-
符号穿透:stat有符号穿透问题, lstat无
10. 目录权限
文件与目录权限的区别
r | w | x | |
---|---|---|---|
文件 | 文件的内容可以被查看:cat、more、 less… | 内容可以被修改: vi、>…. | 可以运行产生一个进程: .文件名 |
目录 | 目录可以被浏览: ls、tree… | 创建、删除、修改文件: mv、touch、mkdir | 可以被打开、进入 |
- 目录操作函数:opendir() readdir() closedir()