vimtutor
vimtutor (小写的)进入学习教程,这是英文版本的
vimtutor zh_CN这个进入是中文版本的
:set nu (冒号 set nu)显示行号
hjkl 光标左下上右移动,w下个单词,b上个单词
:q! (冒号q感叹号)不保存退出
x 删除指定位置字母
小写i进入编辑,esc退出,从光标当前位置开始添加 大写I行首
a进入编辑,esc退出,从光标右边开始添加,大写A行尾
控制台输入 vim 文件名,可以进入编辑代码状态,通过插入编辑完之后,用:wq保存退出。
当前文件夹就可以保存刚刚输入的内容。
直接在要删除的词上面 dw (无回显) 删除一个词
d$删除至末尾 d~删除至行首 dG删除至文档尾,d1G删除到文档首
0到行首,w到下个字母首,e到下个字母尾、
d2w删除2个单词
2dd删除2行
u撤销一下,大写U恢复该行修改前,Ctrl+R恢复被撤销
dd先删除(其实是剪切),ecx退出之后用p命令在光标所在位置会粘贴刚刚dd删除的内容
光标移动到要修改字母的位置,输入r再输入想要的字母就可以替换
cw修改一个词错误的地方(会自动帮忙删除光标所在位置到词尾)
c$整行
大写G到文件最后一行,小写gg到文件第一行,CTRL+G会显示当前行号,行号(无回显)+G跳转到行号的位置
/字符串,向下找字符串。之后,按小写“n”是再来一次
?字符串 ,向上找字符串。之后,按大写“N”是再来一次
Ctrl+o回到未跳之前光标
Ctrl+i相对ctrl+o
% 放匹配符号上(括号等)会自动匹配
在一行内替换头一个字符串 old 为新的字符串 new,请输入 :s/old/new 在一行内替换所有的字符串 old 为新的字符串 new,请输入 :s/old/new/g 在两行内替换所有的字符串 old 为新的字符串 new,请输入 :#,#s/old/new/g 在文件内替换所有的字符串 old 为新的字符串 new,请输入 :%s/old/new/g 进行全文替换时询问用户确认每个替换需添加 c 标志 :%s/old/new/gc
在写代码的时候,直接输入:外部命令。可以直接使用外部的命令
: w test 保存文件 saveas 另存为
部分保存:移动到某个位置。然后按v会进入高亮显示。然后选择的内容:w test保存起来。
读取文件内容,跟保存操作一样
输入小写o在光标所在行下面开始输入,大写O在上面
大写R。连续替换
v配合y复制。然后再p粘贴
:set hls is高亮,:nohlsearch取消高亮
输入 :set xxx 可以设置 xxx 选项。一些有用的选项如下: 'ic' 'ignorecase' 查找时忽略字母大小写 'is' 'incsearch' 查找短语时显示部分匹配 'hls' 'hlsearch' 高亮显示所有的匹配短语
Vim 的功能特性要比 Vi 多得多,但其中大部分都没有缺省启用。为了使用更多的 特性,您得创建一个 vimrc 文件。
开始编辑 vimrc 文件,具体命令取决于您所使用的操作系统: :edit ~/.vimrc 这是 Unix 系统所使用的命令 :edit $VIM/_vimrc 这是 MS-Windows 系统所使用的命令
接着读取 vimrc 示例文件的内容: :r $VIMRUNTIME/vimrc_example.vim
保存文件,命令为: :write
下次您启动 Vim 时,编辑器就会有了语法高亮的功能。 您可以把您喜欢的各种设置添加到这个 vimrc 文件中。 要了解更多信息请输入 :help vimrc-intro
输入一个字母。ctrl+D会显示可以补全的。然后tab可以选择不全的那个单词
GCC/G++
c/c++语言的编译器
-o : 指定生成的文件的名字
-S -masm=intel : 生成源文件对应的汇编文件(使用intel格式的汇编)
-m32 : 编译成32为的程序
-c : 只编译不链接
-static : 静态编译
-share : 动态编译
-shared : 编译成共享库(so文件,就是动态链接库)
-g : 生成调试信息
fun.c
#include <stdio.h>
int fun()
{printf("fun ");}
main.c
#include <stdio.h>
int fun();
int main()
{printf("hello world ");
fun();}
输入gcc main.c fun.c -o hello 生成hello文件 输入 ./hello 运行
跟C语言对比的话,默认就是直接导出函数,加了static的不导出。
make
make是一个源码组织工具(组织项目的编译链接)
它使用Makefile来描述一个项目的编译和链接方法
Makefile的规则:
目标 : 依赖项
生成命令
执行流程:
1. 检查目标是否存在.
2. 如果不存在则检查依赖项是否存在.
3. 如果依赖项存在, 则调用生产命令来通过依赖项生成目标.
4. 如果依赖项不存在, 则将依赖项作为目标向下扫描文件内容,找到生成方法.
例如:
a.out : main.o fun.o
gcc main.o fun.o -o a.out
main.o : main.c
gcc main.c -c -o main.o
fun.o : fun.c
gcc fun.c -c -o fun.o
clean:
rm *.o a.out
使用Makefile的时候, 只需要在Makefile文件所在的目录下执行make
命令即可. 执行make命令的时候, 也可以通过命令行参数,来指定生成哪个目标: make clean
高级make工具
make工具对于项目源码组织已经目录复杂项目的要求了.
当前已经有了很多更简单, 更强大的make工具, 这些工具原理实际还是根据一些脚本自动生成Makefile ,最后调用make来执行Makefile脚本.
这些工具有: automake , qmake , cmake
gdb
调试器
开始调试
gdb 被调试的文件路径
开始调试的时候, 如果希望能够进行源码调试, 需要编译程序时, 加上-g
选项
gcc main.c fun.c -o hello -g
常用命令
运行
r
- 直接运行程序s/n
源码级别的单步步入/单步步过c
继续运行si/ni
汇编级别的单步步入/单步步过
断点设置
b 函数名/行号/*地址
注意, 如果是一个地址,需要加上
*
信息查看
查看反汇编 :
disassemble
设置反汇编的格式: `set disassembly-flavor intel
查看断点:
i b
查看变量的值:
print 变量名
查看内存:
x /10bx 地址
10总共显示10个单位
b表示按字节显示, w按字显示, d按双字显示
x表示以16进制显示, d表示以十进制显示
layout
layout src
查看源码layout split
查看源码和汇编
改阿里源为Ubuntu 18.04默认的源
备份/etc/apt/sources.list #备份 cp /etc/apt/sources.list /etc/apt/sources.list.bak
在/etc/apt/sources.list文件前面添加如下条目 #添加阿里源 deb http://mirrors.aliyun.com/ubuntu/ bionic main restricted universe multiverse deb http://mirrors.aliyun.com/ubuntu/ bionic-security main restricted universe multiverse deb http://mirrors.aliyun.com/ubuntu/ bionic-updates main restricted universe multiverse deb http://mirrors.aliyun.com/ubuntu/ bionic-proposed main restricted universe multiverse deb http://mirrors.aliyun.com/ubuntu/ bionic-backports main restricted universe multiverse deb-src http://mirrors.aliyun.com/ubuntu/ bionic main restricted universe multiverse deb-src http://mirrors.aliyun.com/ubuntu/ bionic-security main restricted universe multiverse deb-src http://mirrors.aliyun.com/ubuntu/ bionic-updates main restricted universe multiverse deb-src http://mirrors.aliyun.com/ubuntu/ bionic-proposed main restricted universe multiverse deb-src http://mirrors.aliyun.com/ubuntu/ bionic-backports main restricted universe multiverse
最后执行如下命令更新源 ##更新 sudo apt-get update sudo apt-get upgrade
SSH
sudo apt install openssh-server
安装步骤 按照如下安装步骤进行安装
步骤 命令 说明 步骤1 sudo su 切换至root用户,ubuntu缺省下root用户有所限制,使用sudo su可以使用当前管理用户的密码切换至root用户,也可以在需要安装权限的命令前加sudo 步骤2 apt install openssh-server 安装openssh-server 步骤3 ssh -V 确认openssh-server版本 步骤4 /etc/init.d/ssh status 确认openssh-server状态 步骤5 /etc/init.d/ssh restart 重新启动 openssh-server 步骤6 从终端使用ssh命令连接确认 步骤7 ifconfig 查看IP地址,用来VS建立调试用。
vs创建linux项目
Visual Studio Installer
修改
使用C++的Linux开发
新建项目-跨平台-linux
F5运行生成后。再虚拟机这个位置可以找到生成的文件
ubuntu@vmware-machine:~/projects/Project1/bin/x64/Debug
PROC
步骤一cd /proc
步骤二 ls 查看下有什么进程
步骤三cd 进程ID就能进入进程
如何查看源代码
步骤一 which ps
步骤二 dpkg -S /bin/ps
步骤三 sudo apt-get source procps
(过程安装了这个)sudo apt-get install dpkg-dev
成功后会自动下载到
/home/ubuntu
下载Linux命令的源码
获取命令的路径:
which 命令名
, 例如:which ps
一般会的到命令的文件路径:
使用
dpkg -S 命令的路径
获取命令源码包使用
sudo apt source 源码包名
下载源码包
CLION
步骤一 file-open-打开刚刚下载的源文件夹
步骤二 edit-find-find in path
输入List of process IDs must follow --pid()
步骤四,根据关键字找到相关函数
步骤五,根据函数名右键-Find Usages找到main函数,然后进去分析。
使用共享库
编译共享库
gcc 的编译选项:
-FPIC -shared
`gcc -fPIC -shared testso.c -o libtestso.so
生成的文件, 必须以
lib
开头, 必须以.so
结尾, 有些时候, 文件后缀中会出现一些数字, 这些数字其实是so文件版本号
在共享库中导出函数
在源码中, 没有加
static
函数都是默认被导出的
在其他工程中调用共享库的导出函数
声明函数原型
直接调用
在编译时, 需要指定链接对应的so文件
使用
-L
选项来指定so所在的目录使用
-l
选项来指定要连接的so文件的名字(名字不能加上lib
和so
后缀)例如:
gcc -L/usr/lib -ltestso main.c
将so文件拷贝到
/usr/lib
目录, 否则程序运行时是找不到这个so文件的.
Linux编程
文件操作
遍历文件
void enum_file(const char* dir_name)
{
DIR* dir = opendir("/home/ez");
struct dirent* ent;
while( ent = readdir(dir))
{
if(strcmp(ent->d_name,".") == 0
|| strcmp(ent->d_name,"..")==0)
{
continue;
}
if(ent->d_type & 4){
// 文件夹
// 递归遍历
char buff[266];
sprintf(buff,"%s/%s",dir_name,ent->d_name);
//printf("buff=%s ",buff);
// enum_file(buff);
}
printf("%s %08X ", ent->d_name, ent->d_type);
}
closedir(dir);
}
进程操作
1进程遍历
#include <iostream>
#include <dirent.h>
#include <cstring>
int main() {
// 遍历进程
DIR *dir = opendir("/proc");
if(dir == NULL){
printf("打开目录失败,错误:%s ",
strerror(errno));
return 0;
}
struct dirent *ent = NULL;
while (ent = readdir(dir)) {
if (ent->d_name[0] < '1'
|| ent->d_name[0] > '9') {
continue;
}
char buff[266];
sprintf(buff, "/proc/%s/status",
ent->d_name);
FILE *f = fopen(buff, "r");
if(f == NULL){
printf("打开文件失败,错误:%s ",
strerror(errno));
continue;
}
fscanf(f, "Name: %s", buff);
printf("pid=%s name=%s ",
ent->d_name,
buff);
fclose(f);
}
return 0;
}
读写其它进程的内存
windows : ReadProcMemory/WriteProcMemory
linux : 以读写文件的方式,读写内存
在/proc/XX/mem
该文件是不能直接查看, 这个文件是代表一个进程的虚拟内存. 如果修改了这个文件内容, 那么对应的进程的内存也会被直接修改. 读取文件的内容, 其实就读取出进程的内存.
#include <cstdio>
#include <unistd.h>
#include <string.h>
#include <fcntl.h>
int main()
{
int pid;
char* p = NULL;
printf("请输入PID:");
scanf("%d", &pid);
printf("请输入要修改的内存地址:");
scanf("%p", &p);
printf("请输入修改的内存数据:");
char buff[100];
scanf("%s", buff);
// 开始修改
// 修改/proc/pid/mem的文件就相当于修改了内存
char path[266];
sprintf(path, "/proc/%d/mem", pid);
int fd = open(path, O_CREAT|O_RDWR, 0);
// 读取出原始的内存
//1. 设置文件读写位置
lseek64(fd,(__off64_t)p, SEEK_SET);
read(fd, path, 100);
printf("%p : %s ", p, path);
lseek64(fd, (__off64_t)p, SEEK_SET);
write(fd, buff, strlen(buff) + 1);
printf("写入完毕 ");
close(fd);
return 0;
}
进程创建
execl(char* path)
- 在当前进程中运行一个可执行程序. 函数不会创建新的进程, 而是将路径中指定的可执行程序直接加载到本进程的空间, 覆盖掉调用者的进程. 从而去运行新的代码(实际就是新的进程)
fork
- 创建一个新的进程, 但是新的进程代码是完全拷贝自身的.
创建新进程:
int pid = fork();
if(pid == -1){ // 如果是子进程,函数会返回-1, 如果是父进程,函数返回是子进程的pid
execl("新进程的路径");
return 0;
}
ptrace
函数和调试有关