目录
Linux系统是一个开源的、免费的内核版本(ubuntu,centos叫发行版本)
查看linux内核版本的命令
uname -a
1. Linux系统目录结构
目录结构是一颗倒状树
/bin:存放常用命令(即二进制可执行程序)
/etc:存放系统配置文件
/boot:存放内核与系统启动有关文件
/dev:存放系统硬件设备
/lib:存放系统库文件
/proc:虚拟文件系统目录,以进程为单位存储内存的映射
/usr:存放系统在运行中不经常改变的内容
/var:存放系统在运行中经常改变的文件
/home:普通用户的家目录
/root:管理员用户的家目录
/mnt:临时挂载点
/tmp:存放各种临时文件,是所有用户均可访问的地点
/home下的普通用户之间不能相互访问,管理员用户可以访问任何用户
清屏:ctrl+l/clear
2. Linux文件类型和文件权限
- 文件类型
普通文件:‘-’
目录文件:‘d’
管道文件:‘p’
字符设备文件:‘c’
块设备文件:‘b’
链接文件:‘l’
套接字文件:‘s’
- 文件权限
r:读权限 值(4)
w:写权限 值(2)
x:执行权限 值(1)
-:无权限 值(0)
- 修改文件权限 chmod
- 文字设定法
u 表属主 g 同组人 o 其他人 a 所有人 “+”表示增加权限 “-”表示去掉权限
- 数字设定法
采用数字设定法时,权限通常由三位数字组成,每一位数字代表一种角色的权限。每个角色的数值由其所具有的权限对应的数值之和构成,如下图:
3. Linux常用命令
(1)基础命令
- pwd
显示当前位置的绝对路径
- cd
切换目录,cd 后的参数表示要切换到的位置,可以使用绝对路径或相对路径
- ls
显示目录中的文件
- 文件的创建和删除
- touch
创建普通文件
- mkdir
创建目录文件
- rmdir
删除空目录,不能删除非空目录, 非空目录需要使用“rm -r name”删除
- rm
删除文件,删除目录文件时,需要加“-r”
- touch
- 文件的拷贝和移动
- cp
拷贝文件, 拷贝目录文件时,需要加上“-r”
- mv
剪切(移动)文件
文件重命名
- cp
- find
在系统中查找需要的文件
例如
- grep
在文件中过滤出包含指定字符串的行
-c:只输出匹配行的计数
-i:不区分大小写
-n:显示匹配行及行号
-v:显示不包含匹配文本的所有行
示例如下:
不区分大小写
打印行数
打印行号
打印不包含hello的
(2)文件编辑命令
- vi的三种模式介绍
命令行切换到插入模式
命令模式切换到末行模式
vi/vim常用命令
末行模式下的操作
(3)文件查看命令
-
cat
查看文件内容
合并文件
往文件中写入数据,ctrl+d是结束输入
-
more
当一个文件的内容超过一个屏幕能显示的行数,使用 more 可以分屏显示文件内容。使用方式:
more filename
-
less
文本内容查看器,查看文件内容,但是文件内容不会显示到界面上 -
head
显示文件前 n 行的内容
-
tail
显示文件后 n 行的内容
-
awk
形成报表 -
sed
对文件的内容进行修改 -
sort
sort 文件名
对文件内容排序
sort -u 文件名
对文件内容去重并排序
(4)进程管理命令
-
ps
默认显示与当前终端有关的进程信息
-e 显示系统中所有的进程信息
-f 显示更多的进程属性信息(全格式)
-L 显示进程中的线程 ID
-
pstree
-
kill
结束或者挂起一个进程
-9 强制结束进程
-stop 挂起进程
-
&后台运行程序
-
jobs
显示当前终端的任务
-
pkill
结束一组同名的进程
-
top
查看系统资源的使用情况,可以查看cpu的占用率和内存的使用情况。默认5秒刷新一下进程列表,所以类似于 Windows 的任务管理器。
-M
是按内存使用情况排序
-P
根据CPU使用百分比排序
-T
根据时间/累计时间进行排序
(5)用户管理命令
- 系统存储用户信息的文件
/etc/passwd 存储用户基本信息
/etc/group 存储用户组的信息
/etc/shadow 存储用户的密码
- 添加新用户
useradd newname 添加一个新的用户 newname
选项: -g 执行新用户的主组
-G 将新用户添加到副组
-s 指定新用户默认使用的 shell 终端
-d 指定新用户登录默认进入的目录
创建新用户需要管理员身份,创建新用户成功后,会在/home 下生成该用户的家目录。 - 修改用户密码
- 删除用户
userdel 删除用户时,首先确保该用户没有登录。userdel 默认仅删除用户,不会删除家目录及家目录中的文件,若想删除用户的同时移除家目录, 那么使用 userdel -r username。
(6)文件的压缩与解压命令
- tar
将文件打包或者解包
◼ c 创建包文件
◼ f 指定目标为文件而不是设备
◼ v 显示详细过程
◼ t 显示包中的内容而不释放
◼ x 释放包中的内容
◼ z GNU 版本新加的,使得 tar 有压缩和解压的功能
下图为tar包打包过程:
下图为 tar 解包过程:
- gzip
对文件进行压缩或者解压
下图为 gzip 压缩的过程:
下图为 gzip 解压的过程:
下图为 tar 对 xxx.tgz 或 xxx.tar.gz 压缩包一步解压的过程:
4. Linux系统上C程序的编译与调试
(1)Yum 仓库搭建及 gcc 的安装
- 准备安装包,安装包再系统光盘“rhel-server-6.3-i386-dvd.iso”的镜像文件中
- 将安装包添加到 VMware 的虚拟光驱中
- 在系统终端中切换到管理员用户
- 挂在光盘 mount /dev/cdrom /mnt
- 在 /etc/yum.repos.d 目录中写配置文件 test.repo
- 验证 yum 仓库是否有效 yum repolist
- 搜索 gcc,yum search gcc
- 安装 yum install gcc.i686
test.repo 文件内容如下:
(2)gcc 分步编译链接
- 预编译 :
gcc -E main.c -o main.i - 编译:
gcc -S main.i -o main.s - 汇编:
gcc -c main.s -o main.o - 链接:
gcc main.o -o main
(3)makefile 和 make
作用:管理工程、实现自动化编译
对 main.c add.c max.c 三个文件进行编译(注意: gcc 前面必须是 table 建缩进)
make 命令根据 makefile 文件的规则生成可执行程序
(4)gdb调试
- debug版本和release版本
- Debug 版本
Debug 版本为可调式版本,生成的可执行文件中包含调试需要的信息。我们作为开发人员,最常用的就是 debug 版本的可执行文件。
Debug 版本的生成:
因为调试信息是在编译过程时加入到中间文件(.o)中的,所以必须在编译时控制其生成包含调试信息的中间文件。
gcc -c hello.c -g
—> 生成包含调试信息的中间文件
gcc -o hello hello.o或者 gcc -o hello hello.c -g - Release 版本
Release 版本为发行版本,是提供给用户使用的版本。用 gcc 默认生成的就是 Release 版本。
首先将源代码编译、链接生成 Debug 版本的可执行文件,然后通过‘gdb Debug 版本的可执行文件名’进入调试模式。
- Debug 版本
- 单进程、单线程基础调试命令
- 多进程调试命令
(gdb)set follow-fork-mode mode
mode 可以选择 parent 或者 child,即:选择调试那个进程。
注意:未被跟踪调试的进程会直接执行结束。
attach + pid
跟踪具体指定的一个进程
- 多线程调试命令
- 利用
info threads
查看线程信息; thread id
调试目标 id 指定的线程;set scheduler-locking off | on | step
; “off”表示不锁定任何线程;
“on”只有当前被调试的线程继续运行;
“step”在单步执行的时候,只有当前线程会执行;
- 利用
- 如何调试死锁
strace -p pid
去跟踪程序,会显示程序执行过程的系统调用,就会告诉你在lock地方停留住了
(5)nm
查看可执行程序中有哪些方法,生成的符号名称
5. Linux 系统上的库文件生成与使用
(1)什么是库文件
库是一组预先编译好的方法的集合。Linux系统存储的库的位置一般在:/lib
和 /usr/lib
。 在 64 位的系统上有些库也可能被存储在/usr/lib64 下。库的头文件一般会被存储在/usr/include 下或其子目录下。
库有两种,一种是静态库,其命令规则为 libxxx.a
,一种是共享库,其命令规则为 libxxx.so
,如下图所示:
(2)静态库的生成与使用
-
静态库的生成
以下是需要生成静态库的”.c”文件,其中“foo.h”中是函数的声明,“add.c”和“max.c”是函数的定义:
第一步:先将需要生成库文件的所有“.c“文件编译成“.o”文件
第二步:使用 ar 命令将第一步编译的所有”.o”文件生成静态库,其中:
◼ c 是创建库
◼ r 是将方法添加到库中
◼ v 显示过程
-
静态库的使用
以下是测试代码”main.c”中的内容:
以下是使用静态库“libfoo.a”和“main.c”生成可执行文件的过程,其中:
◼ -L 指定库的存储路径
◼ -l 指定库的名称(不需要前面的‘lib’和扩展名‘.a’)
(3)共享库的生成与使用
共享库会被映射到进程地址空间的堆区和栈区之间。
-
共享库的生成
以下是需要生成共享库的”.c”文件,其中“foo.h”中是函数的声明,“add.c”和“max.c”
是函数的定义:
第一步:先将需要生成库文件的所有“.c“文件编译成“.o”文件
第二步:使用 gcc 命令将第一步编译的所有”.o”文件生成共享库
-fPIC
作用于编译阶段,告诉编译器产生与位置无关代码,则产生的代码中,没有绝对地址,全部使用相对地址,故而代码可以被加载器加载到内存的任意位置,都可以正确的执行。这正是共享库所要求的,共享库被加载时,在内存的位置不是固定的。为什么不用绝对地址?
如果不加
-fPIC
,则加载.so
文件的代码段时,代码段引用的数据对象需要重定位, 重定位会修改代码段的内容,这就造成每个使用这个.so
文件代码段的进程在内核里都会生成这个.so
文件代码段的copy
。每个copy
都不一样,取决于这个.so
文件代码段和数据段内存映射的位置。不加fPIC
编译出来的so
,是要再加载时根据加载到的位置再次重定位的。(因为它里面的代码并不是位置无关代码)如果被多个应用程序共同使用,那么它们必须每个程序维护一份so的代码副本了。(因为so
被每个程序加载的位置都不同,显然这些重定位后的代码也不同,当然不能共享) -
共享库的使用
以下是测试代码”main.c”中的内容:
以下是使用共享库“libfoo.so”和“main.c”生成可执行文件的过程,其中 -L 指定库的存储路径, -l 指定库的名称(不需要前面的‘lib’和扩展名‘.so’), 如果在库的存储路径有同名的共享库和静态库,gcc 默认使用共享库。
生成之后,直接执行 main 程序,发现出错,原因是系统加载共享库时,找不到对应的共享库文件”libfoo.so”, 但是该库确实在当前目录下存在。这是为什么呢?因为系统默认只会去存储库的标准位置(/lib 或/usr/lib 等)加载,而不会在当前位置寻找。所以将库拷贝到/usr/lib 下,再执行程序,就可以成功。如果库不在标准位置下,也可以通过设置环境变量”LD_LIBRARY_PATH”来指定加载库的路径。
可以通过 ldd 命令查看可执行程序使用了哪些共享库:
(4)静态库和共享库的区别
- 静态库在链接时将用到的方法包含到最终生成的可执行程序中,当静态库被删除,对可执行文件没有影响。但是浪费内存空间。如果静态库被修改,可执行程序要重新编译。
- 共享库只做标记,在运行程序时,才动态加载。加载器在加载动态库时,操作系统会先检查动态库是否因为其它程序已经将这个动态库信息加载到了内存中。如果没有加载到内存中,操作系统会将动态库载入内存,并将它的引用计数设置为1;如果已经加载到内存,仅将动态库的引用计数加1。