Linux基本概念
命令行操作
[Tab]
使用Tab键来进行命令补全
[Ctrl+c]
立即停止并恢复到可控状态,可以使用Ctrl+c键来强行终止当前程序(并不会使终端退出)
用户及文件管理权限
一.Linux用户管理
由于 Linux 的 用户管理 和 权限机制 ,不同用户不可以轻易地查看、修改彼此的文件.
who
命令其它常用参数
(3)用户组
方式1.使用groups命令
方式2.查看/etc/group文件
/etc/group文件格式说明:
/etc/group 的内容包括用户组(Group)、用户组口令、GID 及该用户组所包含的用户(User),每个用户组一条记录。格式如下:
group_name:password:GID:user_list
(4)删除用户
二.Linux文件权限
(1)查看文件权限
ls -l
文件类型:
关于文件类型必需时刻牢记Linux 里面一切皆文件,正因为这一点才有了设备文件这一说,还有 socket
和 pipe
.
软链接文件,链接文件是分为两种的,另一种是“硬链接”(不常用).
文件权限:
读权限可以使用 cat <file name>
之类的命令来读取某个文件的内容.
写权限,表示你可以编辑和修改某个文件.
执行权限,通常指可以运行的二进制程序文件或者脚本文件,如同 Windows 上的 'exe' 后缀的文件,不过 Linux 上不是通过文件后缀名来区分文件的类型.
一个目录要同时具有读权限和执行权限才可以打开,而一个目录要有写权限才允许在其中创建其它文件,这是因为目录文件实际保存着该目录里面的文件的列表等信息所有者权限.
所属用户组权限,是指你所在的用户组中的所有其它用户对于该文件的权限,比如,你有一个iPad,那么这个用户组权限就决定了你的兄弟姐妹有没有权限使用它破坏它和占有它.
(2)变更文件所有者
(3)修改文件权限
方式1.二进制数表示
方式2.加减赋值操作
Linux目录文件及文件基本操作
一.Linux目录结构
1.FHS标准
第一层是, / 下面的各个目录应该要放什么文件数据,例如 /etc 应该要放置设置文件,/bin 与 /sbin 则应该要放置可执行文件等等
第二层则是针对 /usr 及 /var 这两个目录的子目录来定义。例如 /var/log 放置系统登录文件、/usr/share 放置共享数据等等
2.目录路径
路径:
使用 cd
命令可以切换目录
在 Linux 里面,使用 .
表示当前目录,..
表示上一级目录(**注意,还记得我们上一节介绍过的,以 .
开头的文件都是隐藏文件,所以这两个目录必然也是隐藏的,你可以使用 ls -a
命令查看隐藏文件), -
表示上一次所在目录,~
通常表示当前用户的"home"目录。使用 pwd
命令可以获取当前所在路径(绝对路径).
绝对路径:
关于绝对路径,简单地说就是以根"/"目录为起点的完整路径,以你所要到的目录为终点,表现形式如: /usr/local/bin
,表示根目录下的 usr 目录中的 local 目录中的 bin 目录
相对路径:
相对路径,也就是相对于你当前的目录的路径,相对路径是以当前目录 .
为起点,以你所要到的目录为终点,表现形式如: usr/local/bin
(这里假设你当前目录为根目录)
二.Linux文件的基本操作
新建目录 创建名为"mydir"的空目录
复制文件 将之前创建的"test"文件复制到"/home/shiyanlou/father/son/grandson"目录中
移动文件 将文件"file1"移动到"Documents"目录mv 源目录文件目的目录
环境变量与文件查找
一.环境变量
1.变量
准确的说应该是 Shell 变量,所谓变量就是计算机中用于记录一个值(不一定是数值,也可以是字符或字符串)的符号,而这些符号将用于不同的运算处理中
通常变量与值是一对一的关系,可以通过表达式读取它的值赋值给其它变量,也可以直接指定数值赋值给任意变量
2.环境变量
环境变量就是作用域比自定义变量要大,如Shell 的环境变量作用于自身和它的子进程
先在 Shell 中设置一个变量temp=shiyanlou
,然后再新创建一个子 Shell 查看temp
变量的值,如下:
二.搜索文件
搜索相关的命令常用的有如下几个:whereis
,which
,find
,locate
文件打包和解压缩
一.文件打包和解压缩
在 Windows 上我们最常见的不外乎这三种*.zip
,*.rar
,*.7z
后缀的压缩文件
而在 Linux 上面常见常用的除了以上这三种外,还有*.gz
,*.xz
,*.bz2
,*.tar
,*.tar.gz
,*.tar.xz
,*tar.bz2
,简单介绍如下
其中zip
,rar
,tar
最为重要.下面会依次介绍这几个命令及对应的解压命令
1.zip压缩打包程序
使用zip打包文件夹:
上面命令将 shiyanlou 的 home 目录打包成一个文件,并查看了打包后文件的大小和类型
第一行命令中,-r
参数表示递归打包包含子目录的全部内容,-q
参数表示为安静模式,即不向屏幕输出信息,-o
,表示输出文件,需在其后紧跟打包输出文件名。后面使用du
命令查看打包后文件的大小(后面会具体说明该命令)
设置压缩级别为9和1(9最大,1最小),重新打包:
这里添加了一个参数用于设置压缩级别-[1-9]
,1表示最快压缩但体积大,9表示体积最小但耗时最久。最后那个-x
是为了排除我们上一次创建的 zip 文件,否则又会被打包进这一次的压缩文件中,注意:这里只能使用绝对路径,否则不起作用
2.使用unzip命令解压缩zip文件
将shiyanlou.zip
解压到当前目录
使用安静模式,将文件解压到指定目录
3.rar打包压缩命令
rar
也是 Windows 上常用的一种压缩文件格式,在 Linux 上可以使用rar
和unrar
工具分别创建和解压 rar 压缩包
从指定压缩包文件中删除某个文件
查看不解压文件
文件系统操作与磁盘管理
一.简单文件系统操作
1.查看磁盘和目录的容量
使用df命令查看磁盘的容量
使用du命令查看目录的容量:
二.简单的磁盘管理
1.创建虚拟磁盘
使用dd命令创建虚拟景象文件
使用mkfs命令格式化磁盘
使用fdisk将磁盘分区
命令执行顺序控制与管道
一.命令执行顺序的控制
1.顺序执行多条命令
合并命令后
2.有选择的执行命令
我们需要能够有选择性的来执行命令,比如上一条命令执行成功才继续下一条,或者不成功又该做出其它什么处理,比如我们使用which
来查找是否安装某个命令,如果找到就执行该命令,否则什么也不做
上面的&&
就是用来实现选择性执行的,它表示如果前面的命令执行结果(不是表示终端输出的内容,而是表示命令执行状态的结果)返回0则执行后面的,否则不执行
在 C 语言里面&&
表是逻辑与,||
表示逻辑或,同样 Shell 也有一个||
,它们的区别就在于,shell中的这两个符号除了也可用于表示逻辑与和或之外,就是可以实现这里的命令执行顺序的简单控制。||
在这里就是与&&
相反的控制效果,当上一条命令执行结果为≠0($?≠0)时则执行它后面的命令:
二.管道
查看/etc
目录下有哪些文件和目录,使用ls
命令来查看
有太多内容,屏幕不能完全显示,这时候可以使用滚动条或快捷键滚动窗口来查看。不过这时候可以使用管道
wc 命令用于统计并输出一个文件中行、单词和字节的数目,比如输出/etc/passwd
文件的统计信息
分别只输出行数、单词数、字节数、字符数和输入文本中最长一行的字节数
文本处理
文本处理命令
1.tr命令
tr 命令可以用来删除一段文本信息中的某些文字。或者将其进行转换
使用方式:
2.col命令
col 命令可以将Tab
换成对等数量的空格建,或反转这个操作
使用方式:
3.join命令
用于将两个文件中包含相同内容的那一行合并在一起
使用方式:
4.paste命令
paste
这个命令与join
命令类似,它是在不对比数据的情况下,简单地将多个文件合并一起,以Tab
隔开
使用方式:
正则表达式
一.正则表达式
1.简单的说形式和功能上正则表达式和我们前面讲的通配符很像,不过它们之间又有很大差别,特别在于一些特殊的匹配字符的含义上
2.基本语法
选择:|竖直分隔符表示选择,例如"boy|girl"可以匹配"boy"或者"girl"
优先级:优先级为从上到下从左到右,依次降低
二.grep模式匹配命令
grep命令用于打印输出文本中匹配的模式串,它使用正则表达式作为模式匹配的条件。grep支持三种正则表达式引擎,分别用三个参数指定:
常用参数:
三.sed流编译器
sed工具在 man 手册里面的全名为"sed - stream editor for filtering and transforming text ",意即,用于过滤和转换文本的流编辑器。
sed 命令基本格式:
四.awk文本处理语言
简单的说,awk是一种用于处理文本的编程语言工具
awk所有的操作都是基于pattern(模式)—action(动作)对来完成的,如下面的形式:
awk命令基本格式
Vim
1.三种常用模式的切换
vim启动进入普通模式,处于插入模式或命令行模式时只需要按Esc
或者Ctrl+[
(这在vim课程环境中不管用)即可进入普通模式。普通模式中按i
(插入)或a
(附加)键都可以进入插入模式,普通模式中按:
进入命令行模式。命令行模式中输入wq
回车后保存并退出vim。
2.进入vim
使用vim命令进入vim界面:
vim后面加上你要打开的已存在的文件名或者不存在(则作为新建文件)的文件名。 打开Xfce终端,输入以下命令
$ vim practice_1.txt
直接使用vim也可以打开vim编辑器,但是不会打开任何文件。
$ vim
进入命令行模式后输入:e 文件路径
同样可以打开相应文件。
游标移动:
在进入vim后,按下i
键进入插入模式。在该模式下您可以输入文本信息,下面请输入如下三行信息:
12345678
abcdefghijk
shiyanlou.com
按Esc
进入普通模式,在该模式下使用方向键或者h
,j
,k
,l
键可以移动游标。
按键 |
说明 |
|
左 |
|
右(小写L) |
|
下 |
|
上 |
|
移动到下一个单词 |
|
移动到上一个单词 |
3.插入模式
在普通模式下使用下面的键将进入插入模式,并可以从相应的位置开始输入
命令 |
说明 |
|
在当前光标处进行编辑 |
|
在行首插入 |
|
在行末插入 |
|
在光标后插入编辑 |
|
在当前行后插入一个新行 |
|
在当前行前插入一个新行 |
|
替换从光标所在位置后到一个单词结尾的字符 |
5.保存文档
命令行模式下保存文档:
保存文档从普通模式输入:
进入命令行模式,输入w
回车,保存文档。输入:w 文件名
可以将文档另存为其他文件名或存到其它路径下
6.退出vim
命令行模式下退出vim:
从普通模式输入:
进入命令行模式,输入wq
回车,保存并退出编辑
以下为其它几种退出方式:
命令 |
说明 |
|
强制退出,不保存 |
|
退出 |
|
强制保存并退出 |
|
另存为 |
|
另存为 |
|
保存并退出 |
|
保存并退出 |
2.普通模式下退出vim
普通模式下输入Shift+zz
即可保存退出vim
7.删除文本
1.普通模式下删除vim文本信息
进入普通模式,使用下列命令可以进行文本快速删除:
命令 |
说明 |
|
删除游标所在的字符 |
|
删除游标所在前一个字符 |
|
同 |
|
删除整行 |
|
删除一个单词(不适用中文) |
|
删除至行尾 |
|
删除至行首 |
|
删除到文档结尾处 |
|
删至文档首部 |
除此之外,你还可以在命令之前加上数字,表示一次删除多行,如:
2dd
表示一次删除2行
Vim文档编辑
一、vim重复命令
1.重复执行上次命令
在普通模式下.
(小数点)表示重复上一次的命令操作
拷贝测试文件到本地目录
$ cp /etc/protocols .
打开文件进行编辑
$ vim protocols
普通模式下输入x
,删除第一个字符,输入.
(小数点)会再次删除一个字符,除此之外也可以重复dd
的删除操作
2.执行指定次数相同的命令
进入普通模式输入N<command>
,N表示重复后面的次数,下面来练习以下:
打开文件文件进行编辑
$ vim protocols
下面你可以依次进行如下操作练习:
10x
,删除10个连续字符3dd
,将会删除3行文本在普通模式下,你还可以使用dw
或者daw
(delete a word)删除一个单词,所以你可以很容易的联想到dnw
(n替换为相应数字)表示删除n个单词
二、游标的快速跳转
普通模式下,下列命令可以让光标快速调转到指定位置,我们分别讨论快速实现行间跳转和行内跳转
1.行间跳转
命令 |
说明 |
|
游标移动到第 n 行(如果默认没有显示行号,请先进入命令模式,输入 |
|
游标移动到到第一行 |
|
到最后一行 |
小技巧:你在完成依次跳转后,可以使用Ctrl+o
快速回到上一次(跳转前)光标所在位置,这个技巧很实用,比如当你在写代码时,忽然想起有个bug,需要修改,这时候你跳过去改好了,只需要按下Ctrl+o
就可以回到你之前的位置。vim中会用很多类似的小技巧就等着你去发掘。
2.行内跳转
普通模式下使用下列命令在行内按照单词为单位进行跳转
命令 |
说明 |
|
到下一个单词的开头 |
|
到下一个单词的结尾 |
|
到前一个单词的开头 |
|
到前一个单词的结尾 |
|
到行头 |
|
到行尾 |
|
向后搜索<字母>并跳转到第一个匹配的位置(非常实用) |
|
向前搜索<字母>并跳转到第一个匹配的位置 |
|
向后搜索<字母>并跳转到第一个匹配位置之前的一个字母(不常用) |
|
向前搜索<字母>并跳转到第一个匹配位置之后的一个字母(不常用) |
三、复制粘贴和剪切
1.复制及粘贴文本
y
复制yy
复制游标所在的整行(3yy
表示复制3行)y^
复制至行首,或y0
。不含光标所在处字符。y$
复制至行尾。含光所在处字符。yw
复制一个单词。y2w
复制两个单词。yG
复制至文本末。y1G
复制至文本开头。p
粘贴p
(小写)代表粘贴至光标后(下)P
(大写)代表粘贴至光标前(上)$ vim protocols
2.剪切及粘贴
查找替换
一、字符的替换及撤销(Undo操作)
1.替换和撤销(Undo)命令
替换和Undo命令都是针对普通模式下的操作
命令 |
说明 |
|
将游标所在字母替换为指定字母 |
|
连续替换,直到按下 |
|
替换整行,即删除游标所在行,并进入插入模式 |
|
替换一个单词,即删除一个单词,并进入插入模式 |
|
替换游标以后至行末 |
|
反转游标所在字母大小写 |
|
撤销一次或n次操作 |
|
撤销当前行的所有修改 |
|
redo,即撤销undo的操作 |
打开文件进行编辑:
$ vim practice_2 # 输入以下文本 www.shiyanlou.com
然后依次进行如下操作
11G
,跳转到11行a
字符r
,并且输入b,a字符被b字符替换(实用)R
替换字符,输入新字符串,输入完按ESC回到普通模式(实用)cc
替换整行字符,输入新字符串,输入完按ESC回到普通模式cw
替换一个英文字(word),输入完按ESC回到普通模式(实用)~
,翻转游标所在字符的大小写C
替换至行尾,即游标所在处以后的字都会被替换,输入完按ESC回到普通模式u
撤销上一次的操作二、快速缩进
1.使用命令进行快速调整缩进操作
这一小节学习如何在vim中进行快速缩进,缩进操作均在普通模式下有效
打开文件进行编辑
$ vim protocols
15G
,跳转到15行>>
整行将向右缩进(使用,用于格式化代码超爽)<<
整行向左回退:
进入命令行模式下对shiftwidth
值进行设置可以控制缩进和回退的字符数2.shiftwidth命令
shiftwidth
命令是指上一节>>
命令产生的缩进(可以简写成sw
) 普通模式下输入:
进入命令行模式下对shiftwidth
值进行设置可以控制缩进和回退的字符数 获取目前的设定值
:
set shiftwidth?
设置缩进为10个字符
:
set shiftwidth=10
输入ESC
回到普通模式,再次尝试>>
看缩进量是否变化
3.调整文本位置
命令行模式下输入:ce
(center)命令使本行内容居中
:ce
命令行模式下输入:ri
(right)命令使本行文本靠右
:ri
命令行模式下输入:le
(left)命令使本行内容靠左
:le
三、查找
1.快速查找
普通模式下输入/
然后键入需要查找的字符串 按回车后就会进行查找。 ?
与/
功能相同,只不过?
是向上而/
是向下查找。 进入查找之后,输入n
和N
可以继续查找 n
表示继续查找,N
反向查找
2.快速查找练习
使用vim打开文件进行编辑
$ vim protocols
/icmp
查找字符串icmpn
查找下一个icmp?tcp
向上查找字符串tcpN
查找上一个出现的tcp3.高级查找
\*
寻找游标所在处的单词\#
同上,但 \*
是向前(上)找,#则是向后(下)找g\*
同\*
,但部分符合该单词即可g\#
同\#
,但部分符合该单词即可以上查找n
,N
的继续查找命令依然可以用
其他高级功能
一、多文件编辑
1.使用vim编辑多个文件
编辑多个文件有两种形式,一种是在进入vim前使用的参数就是多个文件。另一种就是进入vim后再编辑其他的文件。 同时创建两个新文件并编辑
$ vim 1.txt 2.txt
默认进入1.txt
文件的编辑界面
:n
编辑2.txt文件,可以加!
即:n!
强制切换,之前一个文件的输入没有保存,仅仅切换到另一个文件:N
编辑1.txt文件,可以加!
即:N!
强制切换,之前文件内的输入没有保存,仅仅是切换到另一个文件2.进入vim后打开新文件
:e 3.txt
打开新文件3.txt:e#
回到前一个文件:ls
可以列出以前编辑过的文档:b 2.txt
(或者编号)可以直接进入文件2.txt编辑:bd 2.txt
(或者编号)可以删除以前编辑过的列表中的文件项目:e! 4.txt
,新打开文件4.txt,放弃正在编辑的文件:f
显示正在编辑的文件名:f new.txt
,改变正在编辑的文件名字为new.txt3.恢复文件
如果因为断电等原因造成文档没有保存,可以采用恢复方式,vim -r
进入文档后,输入:ewcover 1.txt
来恢复
$ vim -r 1.txt
二、可视模式
1.可视模式命令简介
v
(小写),进入字符选择模式,就可以移动光标,光标走过的地方就会选取。再次按下v会后就会取消选取。Shift+v
(小写),进入行选择模式,按下V之后就会把整行选取,您可以上下移动光标选更多的行,同样,再按一次Shift+v
就可以取消选取。Ctrl+v
(小写),这是区域选择模式,可以进行矩形区域选择,再按一次Ctrl+v
取消选取。d
删除选取区域内容y
复制选取区域内容2.可视模式命令练习
拷贝练习文件到当前目录
$ cp /etc/protocols .
打开练习文件
$ vim protocols
9G
跳转到第9行,输入Shift+v
(小写V),进入可视模式进行行选择,选中5行,按下>>
缩进,将5行整体缩进一个shiftwidth
Ctrl+v
(小写v),进入可视模式进行矩形区域选择,选中第一列字符然后x
删除整列三、视窗操作
1.视窗操作简介
:sp 1.txt
打开新的横向视窗来编辑1.txt:vsp 2.txt
打开新的纵向视窗来编辑1.txtCtrl-w s
将当前窗口分割成两个水平的窗口Ctrl-w v
将当前窗口分割成两个垂直的窗口Ctrl-w q
即 :q 结束分割出来的视窗。如果在新视窗中有输入需要使用强制符!即:q!Ctrl-w o
打开一个视窗并且隐藏之前的所有视窗Ctrl-w j
移至下面视窗Ctrl-w k
移至上面视窗Ctrl-w h
移至左边视窗Ctrl-w l
移至右边视窗Ctrl-w J
将当前视窗移至下面Ctrl-w K
将当前视窗移至上面Ctrl-w H
将当前视窗移至左边Ctrl-w L
将当前视窗移至右边Ctrl-w -
减小视窗的高度Ctrl-w +
增加视窗的高度四、文档加密
1.创建加密文档
$ vim -x file1
输入您的密码 确认密码 这样在下一次打开时,vim就会要求你输入密码
五、在vim执行外部命令
在命令行模式中输入!
可以执行外部的shell命令
:!ls
用于显示当前目录的内容:!rm FILENAME
用于删除名为 FILENAME 的文件:w FILENAME
可将当前 VIM 中正在编辑的文件另存为 FILENAME 文件六、帮助系统
1.vim中的查看帮助
F1
打开vim
自己预设的帮助文档:h shiftwidth
打开名为shiftwidth
的帮助文件:ver
显示版本及参数七、功能设定
1.vim的功能设定
可以在编辑文件的时候进行功能设定,如命令行模式下输入:set nu
(显示行数),设定值退出vim后不会保存。要永久保存配置需要修改vim配置文件。 vim的配置文件~/.vimrc
,可以打开文件进行修改,不过务必小心不要影响vim正常使用
2.获取目前的设定
:set
或者:se
显示所有修改过的配置:set all
显示所有的设定值:set option?
显示option的设定值:set nooption
取消当期设定值3.set功能的说明
:set autoindent(ai)
设置自动缩进:set autowrite(aw)
设置自动存档,默认未打开:set background=dark
或light
,设置背景风格:set backup(bk)
设置自动备份,默认未打开: set cindent(cin)
设置C语言风格缩进其他知识点
1.man命令
man
是manul的缩写,我们可以通过man man来查看man
的帮助
man
有一个-k
选项用起来非常好,这个选项让你学习命令,编程时有了一个搜索引擎,通过一个例子来说明,比如数据结构中学过排序(sort),我不知道C语言中有没有完成这个功能的函数,可以通过“man -k sort”来搜索,因为是找C库函数,我们关注带3的,qsort好像是个好选项,如下图
结合后面学习的grep 命令和管道,可以多关键字查找:
3.其他核心命令
和查找相关的核心命令还有find
,locate
,grep
,whereis
,which
,其中:
上面的命令包括man -k有一个共同特点就是基于“搜索”
:set nu 显示行号
:set ai 自动缩行
:set ts=4 设置一个 TAB 键等于几个空格
[[ 转到上一个位于第一列的"{"
]] 转到下一个位于第一列的"{"
{ 转到上一个空行
} 转到下一个空行
gd 转到当前光标所指的局部变量的定义
3.gcc
GCC编译代码的过程如下
我们可以把编译过程分成四步,以编译hello.c生成可执行文件hello为例
编译过程比较难记,我们简化一下,前三步,GCC的参数连起来是“ESc”,相应输入的文件的后缀是“iso”,这样记忆起来就容易多了。
4.gdb
建议使用CGDB,比GDB好用,熟悉VC的调试方式,可以使用DDD。 注意使用GCC编译时要加“-g”参数。 参考gdb参考卡GDB最基本的命令有:
(1)模式
三种模式:命令行模式,插入模式,底行模式
命令行模式:最初进入的模式,可以上下移动光标进行“删除字符”或“整行删除”“复制”“粘贴”,但不能编辑文字
插入模式:可以文字编辑,Esc可回到命令行模式
底行模式:光标位于模式的底行,可以文件保存或退出,也可以设置编辑环境如寻找字符串,列出行号
(2)基本流程
进入vi,命令行下输入“vi hello”进入命令行模式,光标位于屏幕上方
命令行输入i进入插入模式,可输入文字
插入模式中按Esc转入命令行模式,底行中输入“:wq”(存盘退出)进入底行模式
(看模式,注意屏幕最下方即可)
启动:命令行输入“emacs”或者从“编程”emacs打开
(1)修改/etc/ld.so.conf文件
(2)修改LD_LIBRARY_PATH环境变量
(3)将库文件直接复制到/lib或/usr/lib目录下
静态库将需要的部分直接编译入可执行文件中,动态库只有当使用它的程序执行时才被链接使用
一个动态库可以被多个程序使用故可称为共享库,静态库会整合到程序中因此程序执行时不用加载静态库
链接到动态库会使用户的程序轻便,易于升级但难以部署
通过“-On”控制优化代码的生成:
-O1:线程调准和延迟退栈
-O2:还有处理指令调度
-O3:还包括循环展开和其他与处理器特性相关的优化工作
调试时不优化,最终发行时优化
(1)gdb使用流程
-g:使编译出的可执行代码中包含调试信息
启动gdb进行调试:
gdb调试的是可执行文件不是.c源代码
查看文件:在gdb中键入“l”就可以查看载入的文件
设置断点:在“b”后加上对应行号,运行到该行之前暂停
查看断点情况:info b
在断点键入“bt”即可查到调用函数(堆栈)的情况
运行代码:键入“r”默认从首行开始运行;r后加行号指定从该行开始运行
查看变量值:键入“p”加变量值
单步运行:“n”或“s”(s会进入函数而n不会进入函数)
恢复程序运行:“c”
gdb基本命令
修改运行参数相关命令:set 变量=设定值
基本调试命令:
display 跟踪变量值的改变
until 跳出循环
finish 跳出函数
help 帮助
make格式: make target
模式规则:规则中的相关文件前必须用“%”标明
程序的机器级表示
X86 寻址方式经历三代:
1 DOS时代的平坦模式,不区分用户空间和内核空间,很不安全
2 8086的分段模式
3 IA32的带保护模式的平坦模式
对于机器级编程来说,其中两种抽象尤为重要
1 机器级程序的格式和行为,定义为指令集体系结构(ISA),它定义了处理器状态,指令的格式,以及每条指令对状态的影响
2 机器级程序使用的存储器地址是虚拟地址,提供的存储器模型看上去是一个非常大的字节数组
数据格式:由于是从16位体系结构扩展成32位,intel用术语字(word)表示16位数据类型,因此32位为双字(double words),64位数为4字(quad words)
对一个IA32 CPU包含一组8个存储32位值的寄存器,用以存整数数据和指针:eax,ecx,edx,ebx,esi,edi,esp,ebp.大多数情况下前六个都用作通用寄存器,eax,ecx,edx的存储和恢复惯例不同于ebx,edi,esi(前三者为被调用者保存,后三者为调用者保存,详见3.7.3);最后两个用于存储指针,由于在过处理中非常重要,分别指向栈帧的顶部和底部,必须保持
IA机器代码和原始的C代码差别很大
1 程序计数器(PC)指令将要执行的下一条指令在存储器中的地址
2 整数寄存器文件包含8个命名的位置,分别存储32位的值
3 一些浮点寄存器存放浮点数据
gcc -S xxx.c -o xxx.s 获得汇编代码,也可以用objdump -d xxx 反汇编
注意: 64位机器上想要得到32代码:gcc -m32 -S xxx.c
MAC OS中没有objdump, 有个基本等价的命令otool
Ubuntu中 gcc -S code.c (不带-O1) 产生的代码更接近教材中代码(删除"."开头的语句)
二进制文件可以用od 命令查看,也可以用gdb的x命令查看。 有些输出内容过多,我们可以使用 more或less命令结合管道查看,也可以使用输出重定向来查看
od code.o | more
od code.o > code.txt
当一个源文件生成了'.o'的目标二进制文件后,无法直接查看。
但是还是有个查看目标代码文件内容的方法,就是对'.o'目标文件使用反汇编器。它的输出还是二进制文件,但是,反汇编器将这些二进制按照指令进行了分段。让我们知道哪一段是一个指令(格式上与汇编器产生的汇编文件一样,分行的)
表中不同数据的汇编代码后缀
C声明 |
Intel数据类型 |
汇编代码后缀 |
字节 |
char |
字节 |
b |
1 |
short |
字 |
w |
2 |
int |
双字 |
l |
4 |
long int |
双字 |
l |
4 |
long long int |
----- |
- |
4 |
char * |
双字 |
l |
4 |
float |
单精度 |
s |
4 |
double |
双精度 |
l |
8 |
long double |
扩展精度 |
t |
10/12 |
数据传送指令有三个变种:movb(传送字节)movw(传送字)movl(传送双字)
寄存器:
esi edi可以用来操纵数组
esp ebp用来操纵栈帧
对于寄存器,特别是通用寄存器中的eax,ebx,ecx,edx,要理解32位的eax,16位的ax,8位的ah,al都是独立的,通过下面例子说明:
假定当前是32位x86机器,eax寄存器的值为0x8226,执行完addw $0x8266, %ax指令后eax的值是多少?
解析:0x8226+0x826=0x1044c, ax是16位寄存器,出现溢出,最高位的1会丢掉,剩下0x44c,不要以为eax是32位的不会发生溢出
操作数的三种类型:立即数、寄存器、存储器
立即数:即常数值
寄存器:表示某个寄存器内容
存储器:根据计算出来的地址(通常称有效地址)访问某个存储器位置
因此寻址方式也有多种,如:立即数寻址、寄存器寻址、绝对寻址、间接寻址、变址寻址、伸缩化 的变址寻址……
有效地址的计算方式 Imm(Eb,Ei,s) = Imm + R[Eb] + R[Ei]*s
区分MOV,MOVS,MOVZ三个命令
MOV相当于C语言的赋值”=“
MOVS将作了符号扩展的字节传送到字
MOVZ将作了零扩展的字节传送到字
(不能从内存地址直接MOV到另一个内存地址,要用寄存器中转一下)
mov族(mov指令还有很多兄弟指令如movb、movw、movsb、movzb)、pop、push
movsb、movzb分别为符号扩展、零扩展,它们只拷贝一个字节,源操作数均为单字节,并设置目的操作数中其余的位,效果如下:
初始假设:%dh=8D %eax=98765432
1 movb %dh,%al ;%eax=9876548D
2 movsbl %dh,%eax ;%eax=FFFFFF8D(目的操作数高24位设为源字节最高位,在这里为很显然为1,所以前24位为全F)
3 movzbl %dh,%eax ;%eax=0000008D(目的操作数高24位被设为0)
pushl指令等价于:
subl $4,%esp
movl %ebp,(%esp) //注意这里的括号引起的差别
popl指令等价于:
movl (%esp),%eax
addl $4,%esp
栈顶元素的地址是所有栈中元素地址中最低的
1.指针其实是地址,间接引用指针就是将该指针放在一个寄存器中 ,然后在间接存储器引用中引用这个寄存器
2.局部变量通常保存在寄存器中,而不是存储器(个人猜测应该是局部变量属于动态分配,局部变量因此被动态置入寄存器,而非存储器)
例如调用exchange:
int a = 4;
int b = exchange(&a,3);
printf("a=%d,b=%d\n",a,b);
打印出a=3,b=4
(&(取址)创建一个指针,在本例中,该指针指向保存局部变量a的位置.然后函数exchange用3覆盖存储在a中的值,但是返回4作为函数的值)
算术和逻辑操作
移位操作 :sall==shll(填0) sarl(算术右移,填符号位) shrl(逻辑右移,填0)
特殊算术操作:imull(有符号64位乘法) mull(无符号64位乘法) cltd(转换为四字) idivl(有符号除法) divl(无符号除法)
使用gcc –S –o main.s main.c -m32命令编译成汇编代码
处理器体系结构
Y86程序中的每条指令都会读取或修改处理器状态的某些部分,称为程序员可见状态
Y86的处理器状态类似于IA32。有八个程序寄存器:%eax %ebx %ecx %edx %esi %edi %esp %ebp。处理器的每个程序寄存器存储一个字。寄存器%esp被入栈,出栈,调用和返回指令作为栈指针。在其他情况中,寄存器没有固定的含义或固定值。有三个一位的条件码:ZF SF OF,他们保存最近的算术或逻辑指令所造成影响的有关信息。程序计数器(PC)存放当前正在执行指令的地址
存储器:从概念上来说就是一个很大的字节数组,保留着程序和数据。Y86程序用虚拟地址来引用存储器位置。硬件和操作系统软件联合起来将虚拟地址翻译成实际或物理地址,指明数据实际保存在存储器中哪个地方
关于Y86:
1.IA32的movl指令分成了4个不同的指令:irmovl,rrmovl,mrmovl,rmmovl,分别显式的指名源和目的的格式。源可以是立即数(i)寄存器(r)或存储器(m)。指令名字的第一个字母就表明了源的类型。目的可以是寄存器(r)或存储器(m)。指令名字的第二个字母指明了目的类型
2.有4个整数操作指令addl,subl,andl,xorl
3.7个跳转指令jmp,jle,jl,je,jne,jge,jg
4.6个条件传送指令cmovle,cmovl,cmove,cmovne,cmovge,cmovg
5.call指令将返回地址入栈,然后跳到目的地址。ret指令从这样的过程调用中返回
6.pushl和popl指令实现了入栈和出栈
7.halt指令停止指令的执行
指令集的一个重要性质就是字节编码必须有唯一的解释
值 |
|
名字 |
含义 |
1 |
|
AOK |
正常操作 |
2 |
|
HLT |
处理器执行halt指令 |
3 |
|
ADR |
遇到非法地址 |
4 |
|
INS |
遇到非法指令 |
Y86状态码(在我们的设计中,任何AOK以外的代码都会使处理器停止)
pushl指令会把栈指针减4,并将一个寄存器值写入存储器中。因此,当执行pushl%esp指令时,处理器的行为是不确定的,因为要入栈的寄存器会被同一条指令修改.通常有两种约定(1)压入%esp的原始值 (2)压入减去4的%esp的值
对于popl%esp指令也类似。可以将%esp置为从存储器中读出的值,也可以置为加上4后的栈指针
|
HCL(硬件控制语言)表达式 |
C语言 |
AND |
&& |
& |
OR |
|| |
| |
NOT |
! |
~ |
不用C语言的符号是因为逻辑门只对单个位的数进行操作,而不是整个字
假设我们想设计一个逻辑电路来找一组字A,B,C中的最小值,用HCL来表达就是:
int Min3 =[
A <= B && A <= C : A;
B <= A && B <= C : B;
1 : C;
];
两类存储器设备:时钟寄存器,随机访问存储器
处理一条指令包括很多操作(实现所有Y86指令所需要的计算可以组织成的六个基本阶段):
1.取指
2.译码
3.执行
4.访存
5.写回
6.更新PC
处理器从来不需要为了完成一条指令的执行而去读由该指令更新了的状态
存储器层次结构
第六章存储器层次结构
6.1 存储技术
三种常见存储技术:RAM/ROM/磁盘;
RAM有SRAM和DRAM,特点和应用;
随机访问存储器(RAM)分为两类:静态的和动态的.静态RAM(SRAM)比动态RAM(DRAM)更快,但也更贵.SRAM用来作为高速缓存存储器,既可以在CPU芯片上,也可以在片下.DRAM用来作为主存以及图形系统的帧缓冲区.典型的,一个桌面系统的SRAM不会超过几兆字节,但是DRAM却有几百或几千兆字节
(1)SRAM:SRAM将每个位存储在一个双稳态的存储器单元里,他可以无限期的保存在两个不同的电压配置或状态之一.其他任何状态都是不稳定的,从不稳定状态开始,电路会迅速的装移到两个稳定状态中的一个,类似于钟摆.原则上,钟摆也能在垂直的位置无限期的保持平衡,但这个状态是亚稳态的
由于SRAM存储器单元的双稳态特性,只要有电,它就会永远的保持它的值.例如电子噪音
(2)DRAM
DRAM将每个位存储为对一个电容的充电.这个电容非常小.DRAM因此可以制造的非常密集,每个单元由一个电容和一个访问晶体管组成.但与SRAM不同,DRAM存储器单元对干扰非常敏感.数码照像机和摄像机中的传感器本质上就是DRAM单元的阵列
ROM有PROM,EPROM,E2PROM,FLASH;
如果断电,DRAM和SRAM会丢失他们的信息,从这个意义上说,他们是易失的.另一方面,非易失性存储器即使是在关电后,也仍然保存着他们的信息
虽然ROM中有的类型既可以读也可以写,但是他们整体上都称为只读存储器(ROM).ROM是以他们能够被重编程(写)的次数和对他们进行重编程所用的机制来区分的
(1)PROM(可编程ROM)只能被编程一次
(2)ERROM(可擦写可编程ROM)
(3)EERROM(电子可擦除PROM):闪存是一类非易失性存储器,基于EERROM,是一种重要的存储技术
磁盘结构:盘片、磁道、扇区、间隙、柱面;磁盘驱动器
磁盘是由盘片组成的。每个盘片有两面或称为表面,表面覆盖着磁性记录材料。盘片中央有一个可以旋转的主轴,它使得盘片以固定的旋转速率旋转
下图展示了一个典型的磁盘表面的结构。每个表面是由一组称为磁道的同心圆组成的。每个被划分为一组扇区。每个扇区包含相等数量的数据位(通常512字节),这些数据编码在扇区上的磁性材料中。扇区之间由一些间隙分隔开,这些间隙中不存储数据位。间隙存储用来标识扇区的格式化拉
磁盘是由一个或多个叠放在一起的盘片组成的,他们被封装在一个密闭的包装里。整个装置通常称为磁盘驱动器,简称磁盘或旋转磁盘以使之区别于闪存的固态硬盘(SSD),SSD是没有移动的部分的
磁盘容量
一个磁盘上可以记录的最大位数称为它的最大容量,简称容量
磁盘容量是由以下技术因素决定的
下面公式给出了一个磁盘的容量
访问时间:寻道、旋转、传送
通过沿着半径轴前后移动传动臂,驱动器可以将读写头定位在盘面上的任何磁道上,这样的机械运动称为寻道
任何时刻,所有的读写头都位于同一个柱面上
磁盘以扇区大小的块来读写数据,对扇区的访问时间有三个主要的部分:
逻辑磁盘块:这个很重要,内存可以看成字节数组、磁盘可以看成块数组
总线
I/O总线比系统总线和存储器总线慢,但是它可以容纳种类繁多的第三方I/O设备
CPU使用一种称为存储器映射I/O的技术来向I/O设备发出命令
数据总线、控制总线、地址总线
系统总线、存储总线、I/O总线
6.2 局部性
局部性原理:时间局部性、空间局部性
一个编写良好的计算机程序常常具有良好的局部性,也就是说,他们倾向于引用邻近于其他最近引用过的数据项的数据项,或者最近引用过的数据项本身。这种倾向性,称为局部性原理,是一个持久的概念
(1)时间局部性:在一个具有良好时间局部性的程序中,被引用过一次的存储器位置很可能在不远的将来再被多次引用
(2)空间局部性:在一个具有良好空间局部性的程序中,如果一个存储器位置被引用了一次,那么程序很可能在不远的将来引用附近的一个存储器位置
有良好局部性的程序比局部性差的程序运行的更快
数据引用局部性
取指令局部性
6.3 存储器层次结构
6.4 高速缓存存储器
高速缓存结构(S,E,B,m):高速缓存组、高速缓存行、块
抽取出被请求的字的过程:组选择,行匹配,字抽取
考题重点
填空:Linux Bash中,Ctrl+a快捷键的作用是(将光标移至输入行头,相当于Home键)。
填空:在 Linux 里面可以使用使用(groups)命令知道自己属于哪些用户组。
填空:在 Linux 里面可以使用使用(chmod)命令修改文件的权限。
填空:Linux中没有C盘,D盘,其文件系统的目录是由(FHS)标准规定好的。
判断:Linux Bash中,cd - 命令可以切换到'home'目录。 x 应该是cd ~ , cd -切换到上一个目录
填空:Linux Bash中,强制删除test文件的命令是(rm -f test )。
填空:Linux Bash中,查找home目录中前天创建的文件的命令是(find ~ -ctime 2)
填空:Linux Bash中,zip命令使用(-e)参数可以创建加密压缩包。
填空:Linux Bash中,ls . | sort 命令的功能是( 显示当前目录内容并排序 )
填空:Linux Bash中,使用grep查找当前目录下*.c中main函数在那个文件中的命令是( grep main *.c )
填空:Linux Bash中,使用wc统计hello.c共有几行代码的的命令是( wc -l hello.c )
判断:col 命令的-h参数可以将Tab换成对等数量的空格建。x , 空格换tab
填空:Linux Bash中,把ls命令显示当前目录的结果存入ls.txt的命令输出重定向命令是(ls > ls.txt)
填空:Linux Bash中,(tee )命令可以同时重定向到多个文件
man -k 填空: 数据结构中有线性查找算法,C标准库中没有这个功能的函数,但Linux中有,这个函数是(lfind或lsearch)
find 填空:查找当前目录下所有目录的find命令是(find . -type d)
grep 填空:查找宏 STDIN_FILENO 的值的命令是(grep -nr XXX /usr/include)
CH01填空:操作系统中最基本的四个抽象是(虚拟机、进程、虚拟存储器、文件)。
CH07填空:链接器的两个主要任务是(符号解析和重定位)。
CH07选择:教材p449中 swap.c中的bufp1 是( A ) A 全局符号 B外部符号 C本地符号 D以上都不对
CH07 填空:(加载器)将可执行文件的内容映射到存储器,并运行这个程序。
CH07 选择:Linux中,反汇编.text节中的二进制指令使用的工具是(d)A ar B strings C readelf D objdump
针对如下代码:
1. 在vi中,查看scanf和printf man pages(帮助文档)的命令分别是?(2分)
K 3K
2. 编译和运行以上代码的命令(2分)
gcc *.c -o main
./main
3. 使用GDB调试以上代码:编译代码的命令是?main.c中如何给main函数设置断点?如何在第六行设置断点?(3分)
gcc -g *.c -o main
b main
b 6
4. 除了main.c外,其他4个模块(add.c sub.c mul.c div.c)的源代码不想给别人,如何制作一个mymath.a静态库?main.c如何使用mymath.a?(3分)
gcc -c add.c sub.c mul.c div.c
ar rcvs libmymath.a add.o sub.o mul.o div.o
gcc main.c -o main -L. -lmymath (or gcc main.c ./libmymath.a -o main)
5. 除了main.c外,其他4个模块(add.c sub.c mul.c div.c)的源代码不想给别人,如何制作一个mymath.so共享库?main.c如何使用mymath.so?(4分)
gcc -fPIC -c add.c sub.c mul.c div.c
gcc -shared -o libmymath.so add.o sub.o mul.o div.o
gcc -o main main.c -L. -lmymath
libmymath.so 要拷贝到/lib or /usr/lib
6. 写出编译上面代码的makefile,编译出来的目标文件为testmymath, 只用显式规则就可以.(4分)
testmymath: main.o add.o sub.o mul.o div.o
gcc main.o add.o sub.o mul.o div.o -o testmymath
main.o: main.c head.h
gcc -c main.c
add.o: add.c head.h
gcc -c add.c
sub.o: sub.c head.h
gcc -c sub.c
mul.o: mul.c head.h
gcc -c mul.c
div.o: div.c head.h
gcc -c div.c
man -k 填空:Linux中显示文件(file )属性(status)的命令是( stat )
cheat 填空:使用du命令对当前目录下的目录或文件按大小排序 的命令是( du -sk *| sort -rn )
grep 填空:~/test 文件夹下有很多c源文件,查找main函数在哪个文件中的命令( grep main *.c )
vi 填空: vi中查看函数qsort的帮助文档的快捷键为(K)
ch01 选择:并行的三个层次不包含(C)。A 线程级并发 B指令级并行 C进程级并发 D SIMD
ch07 填空:gcc -f PIC xxx.c 中的PIC的意思是(位置无关的代码 or Position-Independent Code)
2.21 判断:C语言中: -2147483647-1U < -2147483647 ( ok )
CH06 判断:EEPROM可以用紫外线进行擦除。(x)
CH06 判断:程序访问一个向量,步长越大空间局部性越好。(x)
CH06 判断:程序中的循环语句具有良好的时间局部性和空间局部性。(ok)
CH06 填空:存储层次结构的中心思想是(上层作为下层的缓存)。
CH06 填空:高速缓存结构可以用元组(S,E,B,m)来描述。
6.11 填空:3/4的命中率的如何计算的((32-8)/32,或每4次有一次不命中)
CH06 判断:存储器山中山脊代表空间局部性。(x)
个人体会
Linux操作系统这个名词记得在很早以前就听过,但当时并不知道具体是什么样的操作系统,只知道是一个与嵌入式密切相关的操作系统。而之后对于这门课最大的感想就是学Linux光靠看书是没用的(当然,我并没有像有些比较厉害的同学可以通过自学来掌握,只是借助网络来解决实际操作中遇到的一些问题)。相比于课本,网上有很多新的资料以及解决方法,在解决实际问题的时候比书要好很多,包括老师给的实验楼,很多实验的内容都有详细的介绍。但是,书也有书的好处,书上介绍的很全面,对一个命令或者一个软件的配置都分析了很多,而网上的文章是针对性比较强的。所以,练习的时候要书和课外结合,通过书来学习原理,实际问题解决不了的时候多百度一下。还有就是遇到问题的时候要多用 linux 下的 man 命令来查找帮助。学习Linux最重要的就是熟悉系统的基本操作,Linux的图形界面直观,操作简便,因此有更多的机会来实际练习。其次一定要学好命令,实验中的很多问题都用到了。在实际学习中还有很多其他的方法,比如老师提供的博客园,小组合作完成家庭作业,小组论坛等。其中我认为受益最大的是每节课上课的测试,不仅防止了我们一拖再拖的心理,而且有效的巩固了我们每周所学的知识。反思从开学到现在,我认为我学习这门课最大的障碍就是不会与他人共享问题,小组论坛虽然一直有关注,但有的时候自己遇到了问题不习惯发小组,而是留着等有机会问同学,导致有的问题没有弄清楚就跳过了,所以以后还是要多利用老师提供老师给的资源来结局问题。
课程建议
刚开始的时候感觉这门课的任务太重,要学的知识点太多,毕竟之前没有接触过Linux相关的内容,不过后来渐渐习惯了之后感觉还是蛮有效的,不像有的科目那样只听老师讲而不注重练习,但是还是有个问题就是老师可不可以上课的两个小时上半节课用来复习,下半节课用来讲这周留得任务,自己实践来理解固然好,但是很麻烦,如果老师能大概讲一下再让我们练习就好了。