IT数码 购物 网址 头条 软件 日历 阅读 图书馆
TxT小说阅读器
↓语音阅读,小说下载,古典文学↓
图片批量下载器
↓批量下载图片,美女图库↓
图片自动播放器
↓图片自动播放器↓
一键清除垃圾
↓轻轻一点,清除系统垃圾↓
开发: C++知识库 Java知识库 JavaScript Python PHP知识库 人工智能 区块链 大数据 移动开发 嵌入式 开发工具 数据结构与算法 开发测试 游戏开发 网络协议 系统运维
教程: HTML教程 CSS教程 JavaScript教程 Go语言教程 JQuery教程 VUE教程 VUE3教程 Bootstrap教程 SQL数据库教程 C语言教程 C++教程 Java教程 Python教程 Python3教程 C#教程
数码: 电脑 笔记本 显卡 显示器 固态硬盘 硬盘 耳机 手机 iphone vivo oppo 小米 华为 单反 装机 图拉丁
 
   -> 系统运维 -> 【Linux】相关工具介绍&&在Linux环境下的第一个程序 -> 正文阅读

[系统运维]【Linux】相关工具介绍&&在Linux环境下的第一个程序

包安装器yum

yum的概念

yum就是一个应用商店,里面有经过yum源认证的软件包
如果程序员想用哪个包,可以使用yum搜索和安装
由于是从yum源下载到本地,所以必须要有网络

yum三板斧

yum list

查看yum都有哪些安装包
可以加上管道进行过滤
例如:
yum list | grep “tree”

yum install [-y] [待要安装的软件包名称]

功能:安装某个软件

yum remove [待要卸载的软件包名称]

功能:卸载某个软件

lrzsz与xftp

lrzsz :支持文件的上传和下载

基本操作:
lz: 将win机器的文件上传到Linux操作系统
sz: 将Linux下的文件下载到win机器

注意:lrzsz只支持文件的上传和下载,对于文件夹必须先压缩再上传

xftp:文件上传和下载的工具

与xshell是同源的

编辑器vim

常见的3种模式

正常模式

在这里插入图片描述
控制屏幕光标的移动,字符字或行的删除,移动复制某区段
进出 插入模式 和 底行模式

插入模式

在这里插入图片描述
只有在该模式下,在可以做文字输入
输入完毕后按下Esc 切换到正常模式
一般情况下,写代码是在该模式下完成的

底行模式

在这里插入图片描述
文件保存或退出
也可以进行文件替换,找字符串,列出行号等操作
在命令模式下,输入冒号即可进出该状态

模式之间的切换

我们在编程的过程中,离不开这三种模式,所以三者之间如何切换也是一大重点
具体切换过程以及方式如下图所示:
在这里插入图片描述

7字真言(正常模式下的快捷操作)

移(移动光标)

h j k l

h:光标向左移动
j: 光标向下移动
k:光标向上移动
l: 光标向右移动

上下左右键分别代表光标移动的方向
w:光标移动到下个字的开头
b:光标移动到上个字的开头
gg:进入到文本开始
G:移动到文章的最后
$:移动到光标所在行的行尾
^:移动到光标配所在行的行首

删(删除)

x:每按一次,删除光标所在位置的一个字符

#x:表示删除光标所在位置后的#个字符(包括自身)

X:每按一次,删除光标所在位置的前面一个字符

#X:表示删除光标所在位置前的#个字符

dd:删除光标所在行

#dd:表示从光标所在行开始,删除#行

复(复制)

yy:复制光标所在行到缓冲区

#yy:从光标所在行开始,复制#行到缓冲区

p:将缓冲区的字符粘贴到光标所在位置

注意:所有与y有关的复制命令必须与p配合才能完成复制与粘贴功能

替(替换)

r:替换光标所在处字符
R:替换光标所到之处的字符,直到按下Esc停止

撤(撤销)

u:回到上一个操作,按多次u可以执行多次恢复
Ctrl + r:撤销的恢复

更(更改)

cw:更改光标所在处的字到字尾处

c#w更改#个字:

跳(跳转)

#G:移动光标至文章的#行行首

vimforcpp

一个为用户提供良好编程环境的软件~~
安装方式:
在想要安装的用户命令行下输入
curl -sLf https://gitee.com/HGtz2222/VimForCpp/raw/master/install.sh -o ./install.sh && bash ./install.sh
回车等待安装完毕,重启终端

多行注释&&多行去注释

多行注释

1、Ctrl + v
2、选中需要注释的行,使用h j k l移动光标
3、shift + i :进入插入模式
4、输入注释符号
5、Esc
demo
注释12–15行内容
在这里插入图片描述
Ctrl + v
在这里插入图片描述

选中需要注释的行,使用h j k l移动光标
在这里插入图片描述
shift + i :进入插入模式
在这里插入图片描述
输入注释符号
在这里插入图片描述
Esc
在这里插入图片描述

多行去注释

1、Ctrl + v
2、选中需要去注释的行当中的注释字符,使用h j k l 移动光标
3、按下x 删除即可
demo
在上例的结果下去掉刚才注释的部分
1、2、两步结果
在这里插入图片描述
3、按下x删除
在这里插入图片描述

替换

  1. 单行首个目标字符串替换
s/[待替换的字符串]/[替换成为该字符串]/
  1. 单行全部目标字符串的替换
s/[待替换的字符串]/[替换成为该字符串]/g
  1. 全文替换
%s/[待替换的字符串]/[替换成为该字符串]/g
  1. 指定行替换
num1,num2 s/[待替换的字符串]/[替换成为该字符串]/g

结论
g:表示替换当前所有行
%:代表当前所有行

swp文件没有正常关闭应该如何处理

前提引入
试想一下当你正在写代码时,你的设备突然断网了,然后你查看原因后重新接入网络,这时候你再去打开刚在你编写的文件时,就会莫名其妙的出现无法打开的错误提示:
在这里插入图片描述
此时,怎么办?不必慌张,这就是非正常关闭设备而出现的swp文件。
那什么是swp文件呢?
这是vim在创建文件时创建的一个副本文件,它主要保存用户修改原文件之前的文件,用户的撤销等操作依赖于该副本文件。

好了,遇到这种情况该怎么办?

  1. 复制报错信息第一行双引号下的路径
  2. 按q,退出到命令行模式下
  3. rm + 复制的路径
    在这里插入图片描述
    回车之后。重新执行打开文件的命令,错误消失!

编译器gcc/g++

gcc与g++的区别

一般来说,gcc用来编译c语言的代码,也就是.c文件
g++用来编译c++的代码
但是g++也可以编译c语言的代码,即向下兼容

编译的四个过程

预处理

做什么事情?
宏替换、头文件展开、去注释、条件编译
执行语句

gcc -E [source file] -o [xxx].i

其中选项
-E:让gcc在预处理结束后停止编译过程
-o:目标文件
.i文件表示已经过预处理的C原始程序

e.g
这是源代码
在这里插入图片描述
经过预处理后
在这里插入图片描述
test.i中有好多代码我们并没有编写,如下图,这些代码就是头文件展开的内容
在这里插入图片描述
我们通过G跳转到代码的尾部,找到了我们自己编写的代码,但是与当时写的还是有点出入
在这里插入图片描述
以上就是预处理所做的事情

编译

将源文件生成汇编代码

gcc -S test.c/test.i -o [xxx].s

e,g
对上例生成的test.i文件进行编译,让其由C原始程序变为汇编程序
在这里插入图片描述
查看test.s文件,我们可以发现程序已经变成汇编代码了
在这里插入图片描述

汇编

将汇编代码转换成为二进制代码

gcc -c test.c/test.i/test.s -o test.o

e.g
对上例中生成的test.s进行汇编操作
在这里插入图片描述
查看test.o文件,我们发现里面的内容好像有点上头,完全看不懂是什么含义
在这里插入图片描述
其原因就是:此时代码已经是最底层的机器语言了,也就是有若干个0与1组成的序列,我们在用vim打开时,系统默认的将这些01代码转换为字符,所以我们看到的就是上图这种情况。

链接

若干个二进制代码(.o文件)或者库文件链接起来生成可执行程序或者库文件

gcc test.c/test.i/test.s/tesi.o -o mytest

e.g
在上例的基础上对test.o进行链接操作
在这里插入图片描述
此时mytest就是最终生成的可执行程序
执行结果如图所示
在这里插入图片描述

静态编译与动态编译

这是编译程序两种方式方法

动态编译

gcc test.i -o mytest这条编译命令默认是动态编译的
下面介绍一个命令的含义:file + 可执行文件文件名 可以查看该文件的属性
在这里插入图片描述
紧接着介绍ldd命令:查看一个可执行程序链接的库文件
在这里插入图片描述
那么什么是符号表?符号表又有什么用处呢?
符号表实质上就是在链接过程中二进制文件中使用的库函数与库中对应函数所在位置二者之间形成的一张映射关系表。
可以简单理解为 在执行可执行程序遇到库函数时要先去符号表查对应函数在库中的位置,然后转到该位置执行该库函数。

静态编译

gcc test.i -o mytest -static
给命令后面加上-static,就表示是静态编译
在这里插入图片描述
此时mytest是动态编译的,mytest_static是静态编译的
在这里插入图片描述
在这里插入图片描述
我们发现,二者的大小差距很大,这是为什么呢?
原因是静态编译在编译的过程中将代码需要用到的库函数对应的库文件也编译到可执行文件当中去了。这样就会导致可执行文件比较大。

二者的优缺点

动态编译
优点:更加节省内存,适用于大规模的软件开发
缺点:不具有自完备性,依赖于相关库文件,速度比静态链接慢

静态编译
优点:代码装载速度快,执行速度略快与动态链接。在发布文件的时候不需要考虑用户个人电脑上是否有相关的库文件,因为它自带
缺点:文件体积大

调试器 gdb

debug与release

程序发布的两种方式debug与release
结论:

  1. 在Linux下debug版本的程序在编译的时候需要增加-g命令行参数
  2. 默认不加-g,则为release版本

调试的基础方法

gdb [binfile]
	l: 查看源码,从main函数开始
	l [function name] :查看某个函数的源码
	r:让程序执行起来
	n:逐过程,相当于F10
	s:逐语句,相当于F11
	b [行号]:
	i b:查看断点
	c:继续执行
	delete breakpoints:删除所有断点
	delete breakpoint  n:删除序号为n的断点
	disable breakpoint:禁用断点
	enable breakpoint:启用断点
	info locals:查看当前栈帧局部变量的值
	p [变量名] : 查看变量的值
	bt:展示调用的堆栈
	可以通过调用堆栈来查看代码执行的函数调用关系
	q: 退出

为了验证上述调试的命令,我们提前转备好了待调试代码,具体如下:

 #include <stdio.h>                                                                                                                                                                                                                          
  2 
  3 
  4 void Swap(int *xp,int *yp)
  5 {
  6     int temp = *xp;
  7     *xp = *yp;
  8     *yp = temp;
  9 }
 10 
 11 
 12 int main()
 13 {
 14     int arr[10] = {1,2,3,4,5,6,7,8,9,0};
 15     printf("arr[4] = %d\n",arr[4]);
 16 
 17     int number = 100;
 18     printf("number = %d\n",number);
 19     int *p = &number;
 20     printf("*p = %d\n",*p);
 21 
 22 
 23     int num1 = 158;
 24     int num2 = 167;
 25     Swap(&num1,&num2);
 26 
 27 
 28 
 29     struct Data
 30     {
 31         int age;
 32         int score;
 33     };
 34 
 35     Data d;
 36     d.age = 19;
 37     d.score = 78;
 38     printf("d.age = %d, d.score = %d\n",d.age,d.score);
 39 
 40     Data *Id = &d;
 41     printf("age = %d,score = %d\n",Id->age,Id->score);
 42 
 43     return 0;
 44 }

调试前提(***)

现在开始我们调试命令的测试:
首先,编译生成一个可执行程序
在这里插入图片描述
紧接着调用gdb命令gdb [binfile]进入调试状态
在这里插入图片描述
此时,我们发现无法成功进入调试模式!!!显示没有调试信息。

究其原因,是因为我们上面生成的可执行程序是release版本的,无法调试。
要想调试一个程序,生成的可执行程序版本必须是debug版本~~

因此,我们使用 -g命令选项生成debug版本的可执行程序
在这里插入图片描述
接着调用gdb命令gdb [binfile]进入调试状态
在这里插入图片描述

l / l [函数名] 查看源码

在这里插入图片描述
查看某个函数的源码
在这里插入图片描述

r 让程序执行起来

问题:在执行gdb 【filename】命令后,程序开始执行了吗??
并没有,我们需要执行 r 命令,让程序执行起来。
在这里插入图片描述
此时,我们可以看到程序正常退出了,原因是我们并没有对程序下断点,所以,跑起来后直接执行完毕

b [行号] 打断点

在这里插入图片描述

此时,再让程序跑起来
程序就会在下断点的这行停下来
在这里插入图片描述

逐过程调试(n)&& 逐语句调试(s

n:逐过程,相当于F10,不会进入被调函数的内部
s逐语句:相当于F11,会跳转到函数的内部进行执行
具体看以下示例:
逐过程:
在这里插入图片描述
逐语句:
在这里插入图片描述

查看断点 (i b

在这里插入图片描述

继续执行 c(continue)

在这里插入图片描述

删除断点

删除所有断点 delete breakpoints

在这里插入图片描述

删除某一个序号对应的断点 delete breakpoint 断点序号

1、对代码打两个断点
在这里插入图片描述

2、删除序号为3的断点
在这里插入图片描述

禁用断点 disable breakpoint

禁用断点
在这里插入图片描述
此时我们再让程序跑起来,断点就不会再将程序停止下来,程序会运行到底,直到代码跑完
在这里插入图片描述

启用断点 enable breakpoint

在这里插入图片描述

p [变量名] : 查看变量的值

在这里插入图片描述
现在查看number的值
在这里插入图片描述
我们发现number的值此时是0,由于堆number变量的初始化语句还没有执行,所以number此时存放的是未初始化值。
现通过调试命令,将 int number = 100;这条语句执行之后,再来查看变量number的值
在这里插入图片描述

当然,p也可以查其他类型的变量值,例如指针,结构体,结构体指针等等
比如
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述

info locals:查看当前栈帧局部变量的值

此时可以看到,我们的函数停在第41行处,处于main函数的栈帧
在这里插入图片描述
此时,我们调用命令info locals来查看当前栈帧的局部变量值
在这里插入图片描述
那么我们来看另外以一种情况
当代码执行到Swap函数内部停下来后栈帧内局部变量又是怎样呢?
我们先在代码的30行处下一个断点,随后逐语句调试,进入Swap函数内部
在这里插入图片描述
此时我们来查看函数栈帧的局部变量:
在这里插入图片描述
我们发现,该函数栈帧内的局部变量只有一个,temp。与我们的代码是相对应的。
说明:info locals 展示的一定是当前栈帧的局部变量

当前栈帧是什么意思?
我们知道,函数在被调用时,会在栈上为其开辟一块空间,该快空间就是该函数的栈帧

bt:展示调用的堆栈

可以通过调用堆栈来查看代码执行的函数调用关系
对于函数调用关系,应该从下往上看

在这里插入图片描述
等待Swap函数执行完毕后,再来查看堆栈的调用情况
在这里插入图片描述

此时,只有main函数一个存在,Swap函数对应的栈帧在Swap函数执完毕之后,已经被释放掉了!

q: 退出

当一个程序调试完成后,或者中途用户想要退出调试时,可以通过命令 q实现
在这里插入图片描述

调试的应用场景

1、程序还没执行起来,调试可执行程序
2、调试崩溃程序产生的coredump文件(本小节着重总结)

2.1 coredump文件:核心转储文件,是程序在崩溃的一瞬间内存的映像,相当于案发现场
2.2 ulimit -a
core file size:决定产生的coredump文件最大能够多大
3.3调试命令
gdb 可执行程序 coredump文件

在这里插入图片描述
该行的最后一数字表示核心转储文件的大小

若为0:表示程序崩溃也不会产生coredump文件
unlimited:不限制核心转储文件的大小

如果程序崩溃了,理论上不管coredump文件多大,都会产生

理论上”的含义:由硬盘的大小决定

  1. 若产生的coredump文件小于空闲的磁盘空间,那么可以产生
  2. 若产生的coredump文件大于空闲的磁盘空间,即使core file size的值为unlimited,那也不会生成coredump文件(磁盘空间不足)

那么我们现在现将coredump文件的大小设置为unlimited
在这里插入图片描述
现在,我们提供一个有错误的代码,让其执行后产生coredump文件,我们对其进行一定 的分析

#include<stdio.h>                                                                                  
    2 void Print(int *data)
    3 {
    4     *data = 1;
    5     printf("%d\n",*data);
    6 }
    7 
    8 int main()
    9 {
   10 
   11 
   12     int arr[10] = {1,2,3,4,5,6,7,8,9,0};
   13     printf("%d\n",arr[100]);
   14 
   15     int number = 1000;
   16     int *p = &number;
   17     Print(p);
   18     return 0;
   19 }

示例1

编译执行后发现程序崩溃了
在这里插入图片描述
此时,查看当前目录下的文件
在这里插入图片描述
现在我们通过gdb 可执行程序 coredump文件来查看发生错误的原因
注意:要想通过 gdb+coredump方式进行调试,可执行程序应该也是debug版本

在这里插入图片描述
对于该行代码进行分析:
首先它是一条输出语句,语法正确。那么问题肯定就在参数上

  1. 首先查看输出类型与参数类型是否匹配
  2. arr是否支持下标访问
  3. arr的下标是否合法

本题通过这样的思路方能确定错误源于:数组的越界访问
因此很容易就能根据出错原因修改代码

示例2

下面我将源码的部分内容改动如下
在这里插入图片描述
现在我们再来重新编译一下代码
在这里插入图片描述
重新执行发现,程序还是崩溃了
在这里插入图片描述
那么我们继续来找原因
在这里插入图片描述
很明显,原因是函数的参数并没有保存地址
所以对其解引用找不到一块内存空间来存放数据1

示例3

我们再对代码进行调整
在这里插入图片描述
对其编译并执行
在这里插入图片描述
此时,我们再来查看coredump文件
在这里插入图片描述

在这里插入图片描述
对于这种情况,我们首先找到是在哪里调用了这个函数,也就是找到该参数内的值的来源,找到后,根据程序代码的实际应用场景,来审查该值的合法性。最终确定问题根源所在。

对于coredump文件的分析在日后的编程学习过程中是尤为重要的,我们要熟练地使用gdb+coredump来调试我们的程序。

今天的总结就到此结束了,欢迎各位看官们留下痕迹~~

在这里插入图片描述

  系统运维 最新文章
配置小型公司网络WLAN基本业务(AC通过三层
如何在交付运维过程中建立风险底线意识,提
快速传输大文件,怎么通过网络传大文件给对
从游戏服务端角度分析移动同步(状态同步)
MySQL使用MyCat实现分库分表
如何用DWDM射频光纤技术实现200公里外的站点
国内顺畅下载k8s.gcr.io的镜像
自动化测试appium
ctfshow ssrf
Linux操作系统学习之实用指令(Centos7/8均
上一篇文章      下一篇文章      查看所有文章
加:2022-01-12 00:27:51  更:2022-01-12 00:28:43 
 
开发: C++知识库 Java知识库 JavaScript Python PHP知识库 人工智能 区块链 大数据 移动开发 嵌入式 开发工具 数据结构与算法 开发测试 游戏开发 网络协议 系统运维
教程: HTML教程 CSS教程 JavaScript教程 Go语言教程 JQuery教程 VUE教程 VUE3教程 Bootstrap教程 SQL数据库教程 C语言教程 C++教程 Java教程 Python教程 Python3教程 C#教程
数码: 电脑 笔记本 显卡 显示器 固态硬盘 硬盘 耳机 手机 iphone vivo oppo 小米 华为 单反 装机 图拉丁

360图书馆 购物 三丰科技 阅读网 日历 万年历 2024年11日历 -2024/11/16 6:40:37-

图片自动播放器
↓图片自动播放器↓
TxT小说阅读器
↓语音阅读,小说下载,古典文学↓
一键清除垃圾
↓轻轻一点,清除系统垃圾↓
图片批量下载器
↓批量下载图片,美女图库↓
  网站联系: qq:121756557 email:121756557@qq.com  IT数码