Linux-02

vimtutor

vimtutor (小写的)进入学习教程,这是英文版本的

vimtutor zh_CN这个进入是中文版本的

1567490981319

:set nu (冒号 set nu)显示行号

  1. hjkl 光标左下上右移动,w下个单词,b上个单词

  2. :q! (冒号q感叹号)不保存退出

  3. x 删除指定位置字母

  4. 小写i进入编辑,esc退出,从光标当前位置开始添加 大写I行首

  5. a进入编辑,esc退出,从光标右边开始添加,大写A行尾

  6. 控制台输入 vim 文件名,可以进入编辑代码状态,通过插入编辑完之后,用:wq保存退出。

    当前文件夹就可以保存刚刚输入的内容。

  7. 直接在要删除的词上面 dw (无回显) 删除一个词

  8. d$删除至末尾 d~删除至行首 dG删除至文档尾,d1G删除到文档首

  9. 0到行首,w到下个字母首,e到下个字母尾、

  10. d2w删除2个单词

  11. 2dd删除2行

  12. u撤销一下,大写U恢复该行修改前,Ctrl+R恢复被撤销

  13. dd先删除(其实是剪切),ecx退出之后用p命令在光标所在位置会粘贴刚刚dd删除的内容

  14. 光标移动到要修改字母的位置,输入r再输入想要的字母就可以替换

  15. cw修改一个词错误的地方(会自动帮忙删除光标所在位置到词尾)

  16. c$整行

  17. 大写G到文件最后一行,小写gg到文件第一行,CTRL+G会显示当前行号,行号(无回显)+G跳转到行号的位置

  18. /字符串,向下找字符串。之后,按小写“n”是再来一次

    ?字符串 ,向上找字符串。之后,按大写“N”是再来一次

    Ctrl+o回到未跳之前光标

    Ctrl+i相对ctrl+o

  19. % 放匹配符号上(括号等)会自动匹配

  20. 在一行内替换头一个字符串 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

  21. 在写代码的时候,直接输入:外部命令。可以直接使用外部的命令

    1567494865913

  22. : w test 保存文件 saveas 另存为

  23. 部分保存:移动到某个位置。然后按v会进入高亮显示。然后选择的内容:w test保存起来。

  24. 读取文件内容,跟保存操作一样

  25. 输入小写o在光标所在行下面开始输入,大写O在上面

  26. 大写R。连续替换

  27. v配合y复制。然后再p粘贴

  28. :set hls is高亮,:nohlsearch取消高亮

  29. 输入 :set xxx 可以设置 xxx 选项。一些有用的选项如下: 'ic' 'ignorecase' 查找时忽略字母大小写 'is' 'incsearch' 查找短语时显示部分匹配 'hls' 'hlsearch' 高亮显示所有的匹配短语

  30. Vim 的功能特性要比 Vi 多得多,但其中大部分都没有缺省启用。为了使用更多的 特性,您得创建一个 vimrc 文件。

    1. 开始编辑 vimrc 文件,具体命令取决于您所使用的操作系统: :edit ~/.vimrc 这是 Unix 系统所使用的命令 :edit $VIM/_vimrc 这是 MS-Windows 系统所使用的命令

    2. 接着读取 vimrc 示例文件的内容: :r $VIMRUNTIME/vimrc_example.vim

    3. 保存文件,命令为: :write

    下次您启动 Vim 时,编辑器就会有了语法高亮的功能。 您可以把您喜欢的各种设置添加到这个 vimrc 文件中。 要了解更多信息请输入 :help vimrc-intro

  31. 输入一个字母。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 运行

1567497100394

跟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

常用命令

  1. 运行

    1. r - 直接运行程序

    2. s/n 源码级别的单步步入/单步步过

    3. c 继续运行

    4. si/ni 汇编级别的单步步入/单步步过

  2. 断点设置

    1. b 函数名/行号/*地址

      1. 注意, 如果是一个地址,需要加上*

  3. 信息查看

    1. 查看反汇编 : disassemble

      1. 设置反汇编的格式: `set disassembly-flavor intel

    2. 查看断点: i b

    3. 查看变量的值: print 变量名

    4. 查看内存: x /10bx 地址

      1. 10总共显示10个单位

      2. b表示按字节显示, w按字显示, d按双字显示

      3. x表示以16进制显示, d表示以十进制显示

    5. layout

      1. layout src 查看源码

      2. 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

1567511744041

1567511828358

F5运行生成后。再虚拟机这个位置可以找到生成的文件

ubuntu@vmware-machine:~/projects/Project1/bin/x64/Debug

1567511918332

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

1567526318268

下载Linux命令的源码

  1. 获取命令的路径: which 命令名, 例如: which ps

    1. 一般会的到命令的文件路径:

  2. 使用dpkg -S 命令的路径获取命令源码包

  3. 使用sudo apt source 源码包名 下载源码包

CLION

步骤一 file-open-打开刚刚下载的源文件夹

步骤二 edit-find-find in path

输入List of process IDs must follow --pid()

1567528006391

1567528293136

步骤四,根据关键字找到相关函数

步骤五,根据函数名右键-Find Usages找到main函数,然后进去分析。

1567528416439

使用共享库

  1. 编译共享库

    1. gcc 的编译选项: -FPIC -shared

      `gcc -fPIC -shared testso.c -o libtestso.so

    2. 生成的文件, 必须以lib开头, 必须以.so结尾, 有些时候, 文件后缀中会出现一些数字, 这些数字其实是so文件版本号

  2. 在共享库中导出函数

    1. 在源码中, 没有加static函数都是默认被导出的

  3. 在其他工程中调用共享库的导出函数

    1. 声明函数原型

    2. 直接调用

    3. 在编译时, 需要指定链接对应的so文件

      1. 使用-L选项来指定so所在的目录

      2. 使用-l选项来指定要连接的so文件的名字(名字不能加上libso后缀)

        例如: gcc -L/usr/lib -ltestso main.c

    4. 将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 函数和调试有关

原文地址:https://www.cnblogs.com/ltyandy/p/11456643.html