Linux 学习

本文详细介绍了Linux操作系统,包括内核的系统架构和源码组织,目录结构,常用快捷键,关机与重启,用户管理(如添加、删除、权限修改)以及权限管理,如文件的读写执行权限,进程管理涉及的系统调用如fork、execv、wait、exit等,以及进程的优先级和信号。此外,还涵盖了进程的前后台调用和守护进程的概念。通过对这些基础知识的讲解,读者可以深入理解Linux系统的基本操作和管理。
摘要由CSDN通过智能技术生成


1. 介绍

Linux 是一套免费使用和自由传播的类 Unix 操作系统,是一个基于 POSIX 和 UNIX 的多用户、多任务、支持多线程和多 CPU 的操作系统,它的内核最初只是由芬兰人林纳斯·托瓦兹(Linus Torvalds)在赫尔辛基大学上学时出于个人爱好而编写的。

Linux 能运行主要的 UNIX 工具软件、应用程序和网络协议。它支持 32 位和 64 位硬件。Linux 继承了 Unix 以网络为核心的设计思想,是一个性能稳定的多用户网络操作系统

Linux 是一款操作系统,免费,开源, 安全,高效,稳定, 处理高并发非常强悍,现在很多的企业级的项目都部署到 Linux/Unix 服务器运行,其内核于1991年10月5日首次发布。

目前市面上较知名的发行版有:Ubuntu、RedHat、CentOS、Debian、Fedora、SuSE、OpenSUSE、Arch Linux、SolusOS 等。

Linux 系统作为一个多用户多任务的分时操作系统,任何一个要使用系统资源的用户,都必须首先向系统管理员申请一个账号,然后以这个账号的身份进入系统。
在实际的开发中,由于要涉及到多个部门共同参与,这时就需要为每位开发人员创建一个用户,为了方便给不同的人分配不同的权限,可以将用户分为不同的组,之后对各个组分配权限就很方便了。
对于创建的每一个用户,都会在 /home 文件夹下默认创建一个以用户名命名的文件夹,用于该用户文件的存放。

注意:

  1. 在 linux 中,一个用户属于一个组
  2. 当我们创建一个用户后,默认会在 /home 下创建一个和用户名相同的目录,该目录就是用户家目录
  3. 一个用户默认是不能进入到其他用户目录
  4. 用户权限体现在对文件的操作

2. Linux 内核

Linux 内核系统体系结构

Linux内核主要由五个子系统组成:

  • 进程调度
  • 内存管理
  • 虚拟文件系统
  • 网络接口
  • 进程间通信

进程调度(SCHED)
控制进程对 CPU 的访问,由进程调度系统选择最值得运行的进程

内存管理(MM)
允许多个进程安全的共享主内存区域,支持虚拟内存。

虚拟文件系统(VFS)
隐藏了各种硬件的具体细节,为所有的设备提供了一个统一的接口
分为逻辑文件系统和设备驱动程序。

网络接口(NET)
提供对各种网络标准的存取和各种网络硬件的支持
分为网络协议和网络驱动程序

进程间通信(IPC)
支持进程间的各种通信机制

进程调度处于中心位置,所有的子系统都依赖
各个子系统之间的依赖关系:

  1. 进程调度和内存管理相互依赖
  2. 进程间通信依赖于内存管理,支持共享内存通信机制
  3. 虚拟文件系统利用网络接口支持网络文件系统(NFS),也依赖内存管理支持 RAMDISK 设备
  4. 内存管理利用虚拟文件系统支持交换,交换进程定期由进程调度程序调度——这也是内存管理依赖于进程调度的唯一原因

Linux内核的源码组织结构

使用目录树进行组织
每个源码文件目录下有 Makefile 和 config 文件
顶层的 Makefile 是整个内核配置、编译的总控制文件

主要的子目录以及存放内容:

  1. arch:硬件体系结构相关的代码,每种平台占用一个目录。每个平台的目录下的子目录中较为重要的有:kernel、mm、lib、boot 等
  2. Documentation
  3. drivers:设备驱动程序
  4. fs:文件系统
  5. include:头文件
  6. init:C 语言部分的初始化代码(不是系统引导代码)
  7. ipc:进程间通信的代码
  8. kernel
  9. lib
  10. mm
  11. net:网络相关代码
  12. crypto:常用加密和散列算法
  13. scripts:配置内核的脚本文件
  14. sound:音频设备的驱动程序
  15. usr:实现链一个 cpio(从归档中存入、读取文件)


3. Linux 目录结构

Linux 的文件系统采用级层式的树状目录结构,在此结构中的最上层是根目录"/",然后在此目录下再创建其他的目录。

系统了解 Linux 中的目录对学习 Linux 有很大的帮助
记住一句经典的话:在 Linux 世界里,一切皆文件。

Linux的目录结构

目录名称描述
/binbin 是 Binaries(二进制文件)的缩写, 这个目录存放着最经常使用的命令。
/boot存放的是启动 Linux 时使用的一些核心文件,包括一些连接文件以及镜像文件。
/devdev 是 Device(设备)的缩写,该目录下存放的是 Linux 的外部设备,在 Linux 中访问设备的方式和访问文件的方式是相同的。
/etcetc 是 Etcetera(等等)的缩写,这个目录用来存放所有的系统管理所需要的配置文件和子目录,如果你更改了该目录下的某个文件可能会导致系统不能启动。
/bin,/sbin,/usr/bin,/usr/sbin这是系统预设的执行文件的放置目录,比如 ls 就是在 /bin/ls 目录下的。值得提出的是 /bin、/usr/bin 是给系统用户使用的指令(除 root 外的通用用户),而/sbin, /usr/sbin 则是给 root 使用的指令。
/home用户的主目录,在 Linux 中,每个用户都有一个自己的目录,一般该目录名是以用户的账号命名的,如上图中的 alice、bob 和 eve。
/lost+found这个目录一般情况下是空的,当系统非法关机后,这里就存放了一些文件。
/liblib 是 Library(库)的缩写这个目录里存放着系统最基本的动态连接共享库,其作用类似于 Windows 里的 DLL 文件。几乎所有的应用程序都需要用到这些共享库。
/medialinux 系统会自动识别一些设备,例如U盘、光驱等等,当识别后,Linux 会把识别的设备挂载到这个目录下。
/mnt系统提供该目录是为了让用户临时挂载别的文件系统的,我们可以将光驱挂载在 /mnt/ 上,然后进入该目录就可以查看光驱里的内容了。
/optopt 是 optional(可选)的缩写,这是给主机额外安装软件所摆放的目录。比如你安装一个ORACLE 数据库则就可以放到这个目录下。默认是空的。
/procproc 是 Processes(进程)的缩写,/proc 是一种伪文件系统(也即虚拟文件系统),存储的是当前内核运行状态的一系列特殊文件,这个目录是一个虚拟的目录,它是系统内存的映射,我们可以通过直接访问这个目录来获取系统信息。这个目录的内容不在硬盘上而是在内存里,我们也可以直接修改里面的某些文件,比如可以通过下面的命令来屏蔽主机的ping命令,使别人无法ping你的机器:/proc/sys/net/ipv4/icmp_echo_ignore_all
/root该目录为系统管理员,也称作超级权限者的用户主目录。
/run是一个临时文件系统,存储系统启动以来的信息。当系统重启时,这个目录下的文件应该被删掉或清除。如果你的系统上有 /var/run 目录,应该让它指向 run。
/sbins 就是 Super User 的意思,是 Superuser Binaries(超级用户的二进制文件)的缩写,这里存放的是系统管理员使用的系统管理程序。
/selinux这个目录是 Redhat/CentOS 所特有的目录,selinux 是一个安全机制,类似于 windows 的防火墙,但是这套机制比较复杂,这个目录就是存放 selinux 相关的文件的。
/srv该目录存放一些服务启动之后需要提取的数据。
/sys这是 Linux2.6 内核的一个很大的变化。该目录下安装了 2.6 内核中新出现的一个文件系统 sysfs 。sysfs 文件系统集成了下面3种文件系统的信息:针对进程信息的 proc 文件系统、针对设备的 devfs 文件系统以及针对伪终端的 devpts 文件系统。该文件系统是内核设备树的一个直观反映。当一个内核对象被创建的时候,对应的文件和目录也在内核对象子系统中被创建。
/tmptmp 是 temporary(临时)的缩写,这个目录是用来存放一些临时文件的。
/usrusr 是 unix shared resources(共享资源)的缩写,这是一个非常重要的目录,用户的很多应用程序和文件都放在这个目录下,类似于 windows 下的 program files 目录。
/usr/bin系统用户使用的应用程序。
/usr/sbin超级用户使用的比较高级的管理程序和系统守护程序。
/usr/src内核源代码默认的放置目录。
/varvar 是 variable(变量)的缩写,这个目录中存放着在不断扩充着的东西,我们习惯将那些经常被修改的目录放在这个目录下。包括各种日志文件。这是一个非常重要的目录,系统上跑了很多程序,那么每个程序都会有相应的日志产生,而这些日志就被记录到这个目录下,具体在 /var/log 目录下,另外 mail 的预设放置也是在这里。

4. Linux快捷键

[PrtSc] 获取整个屏幕的截图并保存到 Pictures 目录
F11 使终端全屏,再次按下退出全屏
Tab 补全命令或显示所有可选项。
Ctrl + Alt + T 打开当前页面的终端。
Ctrl + Shift + [+] 放大终端
Ctrl + [-] 缩小终端
Ctrl + a 使光标快速到行首
Ctrl + e 光标快速移到行尾
Ctrl + r 在历史命令中搜索
Ctrl + c 强制终止当前命令
Ctrl + z 暂停在终端运行的任务
Ctrl + l 或者 clear 清屏
Ctrl + Shift + f 查找
Ctrl + Shift + g 查找上一个,按回车下一个
Ctrl + Shift + c 复制
Ctrl + Shift + v 粘贴
Ctrl + K 光标所处位置到行末的所有内容 和 ctrl + u 对立
Ctrl + U 光标所处位置到行首的所有内容 和 ctrl + k 对立
Ctrl + W 光标所处位置之前的一个词,以空格、标点为界
Alt + F4 关闭当前窗口
Shift + PgUp 向上翻页
Shift + PgUp 向下翻页
Alt+ Tab 切换不同的程序窗口
Alt + Shift + Tab 往回切换

linux 中不是太常用的快捷键

Ctrl + t 交换光标位置前的两个字符
Ctrl + y 粘贴最后一次被删除的单词
Ctrl + z 把命令放入后台
Alt + b 光标往回移动到前一个单词
Alt + d 删除从光标位置到当前所处单词的末尾
Alt + F1 访问菜单
Alt + F2 运行
Alt + F10 最大化当前窗口,再次缩小
Ctrl + Alt + F2 切换到文本终端,也可以通过命令 chvt n 来实现。如果你希望知道终端的名字,可以使用命令fgconsole
Ctrl + Alt + F1 从文本终端切换到图形用户界面
Ctrl + Alt + Delete 在文本终端下使用时强制重启
Shift + PrtSc 获取屏幕的某个区域截图并保存到 Pictures 目录
Alt + PrtSc 获取 当前窗口的截图并保存到 Pictures 目录
Ctrl + PrtSc 获取整个屏幕的截图并存放到剪贴板
Shift + Ctrl + PrtSc 获取屏幕的某个区域截图并存放到剪贴板
Ctrl + Alt + PrtSc 获取当前窗口的截图并存放到剪贴板
ctrl +f 光标向右移动一个 等价于小键盘的 <-- 键
ctrl +b 光标向左移动一个 等价于小键盘的 --> 键
ctrl +d 退出当前登录,等同于 exit logout;如果在当前使用了 ssh 远程其他机器,改指令会退回当前机器
ctrl + h 向前退格,等价于 backspace
ctrl + p 显示上一条指令 等价于小键盘 ↑
ctrl + n 显示下一条指令 等价于小键盘 ↓
ctrl + s 锁定终端,使任何人不允许输入,但是输入操作会记录
ctrl + q 解除 ctrl +s 的锁定,同时会展示或执行 ctrl +s 锁定时输入的指令

5. 关机、重启、登录与注销

关机与重启

shutdown [选项] 时间

-c 取消前一个关机或重启命令
-h 在指定时间关闭机算机
-r 在指定时间重启计算机
-p 关闭操作系统,并调用 poweroff 关闭电源。
-k 向系统中的登录者发送警告信息,并不真正执行关机操作。

shutdown -h now : 表示立即执行
shutdown -h 10 : 10分钟后自动关机
shutdown -h 20:30 : 系统将在20:30时准时关机

shutdown -r 10:10分钟后自动重启

shutdown -c : 取消自动关机

--------------------------------------------------------------------------------------------

halt : 立刻关机(一般加 -p 关闭电源)
halt 关闭正在运行的操作系统

--------------------------------------------------------------------------------------------

poweroff :立刻关机
poweroff 关闭正在运行的 linux 操作系统并切断系统电源

--------------------------------------------------------------------------------------------

reboot : 重启系统
reboot 重启正在运行的 linux 操作系统

--------------------------------------------------------------------------------------------

init 0 : 关闭系统
init 6 : 重启系统

登录与注销

登录:
ssh root@192.168.142.128

切换用户:
su - 用户名
login username

注销:
logout
exit

6. 用户管理

用户的相关操作

# 添加用户

adduser username # 创建临时用户,需要root账户
useradd username # 创建临时用户,需要权限,不设置密码,不创建用户目录

useradd -d 指定目录 新的用户名 # 为新增用户指定家目录

useradd –g 用户组 用户名 # 为新增用户指定默认组,可以是 GID 或者 GROUPNAME

# 删除用户

userdel 用户名

userdel -r 用户名 # 删除用户以及用户主目录

# 修改用户名和密码

# 注意:需要从要改名的帐号中登出并杀掉该用户的所有进程,要杀掉该用户的所有进程可以执行下面命令

sudo pkill -u username
sudo pkill -9 -u username

usermod -l newname oldname 

passwd username # 如果没有带用户名,则是给当前登录的用户修改密码

# 查询用户信息

# id 命令可以显示真实有效的用户 ID(UID) 和组 ID(GID)
# 带用户名时则打印指定的 uid 及 gid
id 用户名

whoami # 打印当前登陆的用户名称
who am i # 打印最开始登录的用户名称

# su switch user
# 切换到指定用户
su 用户名
# 切换到 root 用户
su - 

# 系统中的登陆审计

w # 显示正在登陆系统的账号   
w -i # 显示登陆来源
last # 显示成功登录现已退出的账号
lastb # 显示尝试登录但被拦截的账号

注意:

  • 从权限高的用户切换到权限低的用户,不需要输入密码,反之需要
  • 当需要返回到原来用户时,使用 exit 指令

用户组的相关操作

# 新增组
groupadd groupname

# 删除组
groupdel groupname

# 1. 创建账号 robot1、2、3

useradd robot1
useradd robot2
useradd robot3


# 2. 分别给设置密码

passwd robot1
passwd robot2
passwd robot3


# 3. 创建三个组 group1、2、3

groupadd group1
groupadd group2
groupadd group3


# 4. 将不同账号分配到不同组

usermod -g robot1 group1
usermod -g robot2 group2
usermod -g robot3 group3


# 5. robot1 移动到 group4

mkdir /home/group4
usermod -d /home/group4 robot1


# 6. robot3 移动到 group1

usermod -g group1 robot3



# 7. 把 robot2 及其所在的 group2 删除

userdel robot2
groupdel group2


# 8. 最后看一下/etc/passwd 和 、/etc/shadow的变化

tail -n 15 /etc/passwd

只有 root 或具有 sudo 访问权限的用户才能调用 usermod 和修改用户帐户。

usermod

1.更改用户名
可以使用 usermod 命令的 -l 选项更改用户名:

sudo usermod -l new_username old_username

2.更改用户的主目录
可以使用 usermod 命令的 -d 选项更改用户的主目录:

sudo usermod -d new_home_dir user_name

更改用户主目录的更好方法是使用 -m 选项和 -d 选项,这样,如果新主目录不存在,将创建新的主目录,除此之外,它还将旧主目录的内容移动到新主目录,正确文件权限和所有权。

sudo usermod -md new_home_dir user_name

3.更改用户的登录名shell
可以使用 usermod 命令的 -s 选项为用户更改默认 shell,假设想要将默认的 shell 更改为 zsh,下面是你可以执行的操作:

sudo usermod -s /bin/zsh username

4.更改默认用户组
还可以更改用户的默认组,当你更改了用户名时,这尤其有用,最好同时更改默认用户组。

sudo usermod -g new_default_group_name username

5.将用户添加到其他组
这可能是 usermod 命令最常见的用法,如果要将用户添加到 sudoer 列表,只需将用户添加到 sudo 组。

sudo usermod -aG group_name username

你注意到我在这里使用了选项 -aG,而不仅仅是 -G,这是因为如果只使用 -G选项,它用你提供的新组替换用户组。
这就是为什么您应该使用 append 选项 -a 的原因,以便将用户另外添加到新组中,而不是从其先前的组中删除。

6.锁定和解锁用户帐户
您可以使用 usermod 命令选项 -L 锁定 Linux 中的用户帐户。锁定的用户无法登录到系统。

sudo usermod -L username

你还可以使用选项 -U 解锁用户

sudo usermod -U username

7.设置用户帐户的到期日期
若要将到期日期设置为用户帐户,可以使用选项 -e,它日期为 yyyy-MM-dd 格式。

sudo usermod -e 2020-04-01 username

8.更改用户的 UID
可以使用选项 -u 更改用户的 UID (用户ID ):

sudo usermod -u UID username

用户和组的相关文件
/etc/passwd 文件
用户(user)的配置文件,记录用户的各种信息
每行的含义:

用户名:口令:用户标识号:组标识号:注释性描述:主目录:登录 Shell

特殊账号:

特殊账号

/etc/group文件

组(group)的配置文件,记录 Linux 包含的组的信息
每行含义:

组名:口令:组标识号:组内用户列表

7. 权限管理

Linux 中所有内容都是以文件的形式保存和管理,即:一切皆文件。

  • 普通文件是文件。
  • 目录(在 win 下称为文件夹)是文件。
  • 硬件设备(键盘、硬盘、打印机)是文件。

Linux 下有两种用户:超级用户(root)、普通用户。
超级用户:可以在 linux 系统下做任何事情,不受限制,命令提示符是 “#”
普通用户:在 linux 下做有限的事情,命令提示符是 “$”

linux 文件对不同用户可以分别设置权限,管理员(root)有所有权限。

文件访问者的分类
文件和文件目录的所有者:u—User
文件和文件目录的所有者所在的组的用户:g—Group
其它用户:o—Others

查看文件类型和所有者
一般为文件的创建者,谁创建了该文件,就自然的成为该文件的所有者,当然后期可以改
使用命令查看: ls -l
查看文件详细信息

关于文件的权限说明

rwx 作用到文件上

  1. r 代表可读(read):可以读取查看
  2. w 代表可写(write):可以修改,但不代表可以删除该文件,删除一个文件的前提条件是对该文件所在的目录具有写的权限,才能删除文件
  3. x 代表可执行(execute):可以被执行

rwx 作用到目录上

  1. r 代表可读(read):可以读取,ls 查看目录内容
  2. w 代表可写(write):可以修改,目录内创建 + 删除 + 重命名目录
  3. x 代表可执行(execute):可以进入该目录

工作目录

# 显示当前完整的工作路径
pwd

# 更改工作目录
cd directory # 切换至指定目录

# 创建工作目录
mkdir directory_name # 当前目录下创建新的目录
mkdir /.../directory_name # 使用相对路径创建,需要 root 权限
mkdir directory1 directory2 # 创建多个目录
mkdir -p directory1/directory2 # 使用 -p 选项可以递归创建多个目录

# 删除工作目录
rmdir directory_name # 删除当前目录下的工作目录

# 移动目录或文件
mv file direcotory # 移动文件到指定目录

# 复制目录或文件
cp file directory # 复制文件到指定目录,需要 root 权限
cp oldfilename new filename # 复制原文件到新文件中,可用于文件重命名

# 删除目录或文件
rm -rf directory # 无需逐步删除子目录和文件,直接删除该目录

# 创建文件或修改时间
touch file # 当前目录下创建文件
touch -at 0411011 file # 修改文件的最后访问时间

# 查看目录和文件
ls # 查看当前目录下的目录和文件
-a # 显示所有文件,包含隐藏文件
-i # 显示文件索引节点号
-l # 列出文件详细信息
-m # 有,区隔每个文件和目录
-R # 列出当前目录下的文件,并显示子目录及其文件

# 以树状图列出目录内容
tree -l # 生成目录树结构
-a # 显示所有文件
-i # 不以阶梯状列出文件和目录名称
-s # 列出文件或目录大小
-t # 按更改时间排序

# 显示文件详细信息
file file # 检验文件类型
stat file # 显示文件详细信息


创建和显示文件

cat > test.txt # 回车后开始编辑输⼊内容
#按 ctrl + d 组合键结束编辑。


# 分页往后显示文件
more file # 分页显示文件,用 space 进行翻页

# 分页自由显示文件
less file # 只显示最上或最下页,page down 键转最下页

# 指定显示文件前若干行
head -13 file # 查看文件前13行内容,默认前10行

# 显示文件后若干行
tail -13 file # 查看文件后13行,默认后10行

# 对文件内容进行排序
sort (r) file # 顺序(逆序)显示

# 检查文件中重复内容
uniq file # 重复内容只显示一次

# 在文件中查找指定内容
grep 'a' file # 显示所有包含’a’的行的内容,非行号
grep -c 'a' file # 只显示行数量

# 逐行对不同文件进行比较
diff file1 file2 # 两个文件进行比较
diff3 file1 file2 file3 # 三个文件进行比较
sdiff file1 file2 # 合并两个文件并输出

# 逐个字节对不同文件进行比较
cmp file1 file2 # 逐个字节对不同文件进行比较
-l # 显示详细不同内容

# 对有序文件进行比较
comm file1 file2

# 对文件内容进行剪切
cut -c 3 file # 截取每行第3个字符
cut -d 'b' -f 2 file # 以b为分隔符,截取第二个域

# 对文件内容进行粘贴
paste file1 file2 # 将 file2 粘贴到 file1 中

# 对文件内容进行统计
wc file # 统计文件中的字符数、单词数和行数
-c # 字符数
-w # 单词数
-l # 行数

修改文件权限 chmod

第一种方式:+ 、-、= 变更权限
使用 chmod 命令来改变文件的权限,
注:只有文件的拥有者和 root 用户才能调用 chmod 命令改变权限
u: 所有者 g: 所有组 o: 其他人 a: 所有人(u、g、o 的总和)

chmod u=rwx,g=rx,o=x file
chmod o+w file
chmod a-x file

第二种方式:通过数字变更权限
规则:
rwx 用三位二进制数字进行表示,0 表示不拥有该权限,1 表示拥有该权限,转化为八进制数字后赋值给用户,用户所在用户组以及其他用户

chmod u=rwx,g=rx,o=x file
相当于 chmod 751 file

修改文件所有者 chown

改变文件的所有者 chown newowner file
改变用户的所有者和所有组 chown newowner:newgroup file
选项:
-R 如果是目录 则使其下所有子文件或目录递归生效

修改文件所在组 chgrp

修改文件所在组 chgrp newgroup file

文件的压缩与解压

tar 命令的压缩与解压

tar 命令参数前面加 ‘-’ 与不加 ‘-’ 的区别:
tar 命令参数前面加不加“-”执行命令的结果是没有区别的,区别只要是在于 linux 风格方面,加 ‘-’ 属于 System V 风格,不加“-”属于 BSD 风格,所以在使用 tar 命令的时候它的参数加不加 ‘-’ 结果是一样的,看个人的使用方式。

tar 命令的常用参数:
-z 是否同时具有 gz 属性
-j 是否同时具有 bz2 属性
-J 是否同时具有 xz 属性
-x 解压缩、提取打包的内容
-t 查看压缩包内容
-c 建立一个压缩,打包文档
-C 切换到指定目录,表示指定解压缩包的内容和打包的内容存放的目录
-v 显示压缩或者打包的内容
-f 使用文件名,在 f 后面要接压缩后的文件的名字,只要用到 tar 命令,-f 选项是必须要用的,-f 参数在使用的时候一定排在其他参数的后面,在最右边
-p 保留备份数据的原本权限与属性,常用于备份(-c)重要的配置文件
-P 保留绝对路径

linux 主要有三种压缩方式:

  1. gzip:是公认的压缩这速度最快,压缩大文件的时候与其他的压缩方式相比更加明显,历史最久,应用最广泛的压缩方式
  2. bzip:压缩形成的文件小,但是可用性不如 gzip
  3. xz:是最新的压缩方式,可以自动提供最佳的压缩率
    建议的压缩的时候标明后缀:
参数作用命令
-z用于 gzip 压缩方式file.tar.gz
-j用于 bzip2 压缩方式file.tar.bz2
-J用于 xz 压缩方式file.tar.xz

压缩速度:gz > bz2 > xz
压缩率:xz > bz2 > gz

zip 命令的压缩与 unzip 的解压

zip 命令和 unzip 命令
在使用 zip 跟 unzip 命令之前先查看系统有没有安装这两个命令的包,没有的话要自己安装

zip命令
基本用法:
zip [参数] [压缩包名] [压缩的目录或者文件的路径]
常用参数:
zip 命令的常用参数
-m 将文件压缩后,删除原文件
-o 将压缩文件内的所有文件的最新变动时间设为压缩的时间
-q 安静模式,在压缩的时候不显示指令执行的过程
-r 递归压缩,将自定目录下的所有子文件以及文件一起处理
-x ”文件列表“,压缩时排除文件列表中的文件

unzip 命令
基本用法:
unzip [参数] [压缩文件] (-d [目录]) //如果不是用括号里面的内容,则解压文件在当前工作目录
常用参数:
unzip 命令的常用参数
-c 将解压缩的结果显示到屏幕上(显示每一个目录下的每一个文件的内容),同时对字符做适当的转换,但是并没有解压压缩包
-l 显示压缩文件内所包含的文件
-t 检查压缩文件是否正确
-v 执行时显示压缩文件的详细信息
-q 安静模式,执行时不显示任何信息
-d 指定文件解压后存储的目录
-x 指定不要处理压缩文件中的那些文件

zipinfo [压缩文件] 列出压缩文件的信息

8. 进程管理

进程的定义

程序是静态的代码文件,进程是指程序运行时的形态,进程是程序的另一个副本
进程是有生命周期的(准备期,运行期,终止期)

进程与线程
进程是资源调度的最小单位,线程是进程的最小单位
程序执行流是从上到下贯穿进行的
当进程是多任务时,cpu 是多核心,多任务应该同时被每个核心同时处理,每个核心处理的任务叫做线程 线程资源是共享的。

进程状态

  • R 可执行状态
  • S 可唤醒休眠
  • D 不可唤醒休眠
  • T 暂停状态
  • Z 僵死态

子进程的创建

在 Linux 系统中,除了系统启动之后的第一个进程由系统来创建,其余的进程都必须由已存在的进程来创建,新创建的进程叫做子进程,而创建子进程的进程叫做父进程。
在系统启动及完成初始化之后,Linux 自动创建的进程叫做根进程。根进程是 Linux 中所有进程的祖宗,其余进程都是根进程的子孙。具有同一个父进程的进程叫做兄弟进程。

Linux进程创建的过程示意图如下所示:
进程创建

子进程的创建
在 Linux 中,父进程以分裂的方式来创建子进程,创建一个子进程的系统调用叫做 fork()。

系统调用 fork()
为了在一个进程中分裂出子进程,Linux 提供了一个系统调用 fork()。
这里所说的分裂,实际上是一种复制。因为在系统中表示一个进程的实体是进程控制块,创建新进程的主要工作就是要创建一个新控制块,而创建一个新控制块最简单的方法就是复制。

当然,这里的复制并不是完全复制,因为父进程控制块中某些项的内容必须按照子进程的特性来修改,例如进程的标识、状态等。另外,子进程控制块还必须要有表示自己父进程的域和私有空间,例如数据空间、用户堆栈等。下面的两张图就表示父进程和相对应的子进程的内存映射:
父子进程的内存映射

稍微介绍一下进程地址空间:
进程的数据区也就是未初始化的数据(.bss)、已初始化的数据(.data);进程的栈区也就是进程的用户栈和堆;进程程序代码就是进程的程序文件(.text);除此之外还有进程的系统堆栈区。

与进程相关的系统调用

函数 execv()

为了在程序运行中能够加载并运行一个可执行文件,Linux 提供了系统调用 execv()。其原型为:

int execv(const char* path, char* const argv[]);
其中,参数 path 为可执行文件路径,argv[] 为命令行参数。

如果一个进程调用了 execv(),那么该函数便会把函数参数 path 所指定的可执行文件加载到进程的用户内存空间,并覆盖掉原文件,然后便运行这个新加载的可执行文件。

在实际应用中,通常调用 execv() 的都是子进程。人们之所以创建一个子进程,其目的就是执行一个与父进程代码不同的程序,而系统调用 execv() 就是子进程执行一个新程序的手段之一。子进程调用 execv() 之后,系统会立即为子进程加载可执行文件分配私有程序内存空间,从此子进程也成为一个真正的进程。

如果说子进程是父进程的“儿子”,那么子进程在调用 execv() 之前,它所具有的单独用户堆栈和数据区也仅相当于它的私有“房间”;但因它还没有自己的“住房”,因此也只能寄住在“父亲”家,而不能“自立门户”,尽管它有自己的“户口”(进程控制块)。

调用 execv() 后,父进程与子进程存储结构的示意图如下:
调用execv之后的内存映射

与上文刚 fork() 的内存映像图相比,调用 fork() 之后,父子共同使用同一块程序代码;而调用 execv() 之后,子程序拥有了自己的程序代码区。

系统调用 wait()

虽然子进程调用函数 execv() 之后拥有自己的内存空间,称为一个真正的进程,但由于子进程毕竟是由父进程所创建,所以按照计算机技术中谁创建谁负责销毁的惯例,父进程需要在子进程结束之后释放子进程所占用的系统资源。

为实现上述目标,当子进程运行结束后,系统会向该子进程的父进程发出一个信息,请求父进程释放子进程所占用的系统资源。但是,父进程并没有准确的把握一定结束于子进程结束之后,那么为了保证完成为子进程释放资源的任务,父进程应该调用系统调用 wait()。

如果一个进程调用了系统调用 wait(),那么进程就立即进入等待状态(也叫阻塞状态),一直等到系统为本进程发送一个消息。在处理父进程与子进程的关系上,那就是在等待某个子进程已经退出的信息;如果父进程得到了这个信息,父进程就会在处理子进程的“后事”之后才会继续运行。

也就是说,wait() 函数功能是:父进程一旦调用了 wait 就立即阻塞自己,由 wait 自动分析当前进程是否有某个子进程已经退出,如果让它找到了这样一个已经变成僵尸的子进程,wait 就会收集这个子进程的信息,并把它彻底销毁后返回;如果没有找到这样一个子进程,wait 就会一直阻塞在这里,直到有一个出现为止。
如果父进程先于子进程结束进程,则子进程会因为失去父进程而成为“孤儿进程”。在 Linux 中,如果一个进程变成了“孤儿进程”,那么这个进程将以系统在初始化时创建的 init 进程为父进程。也就是说,Linux 中的所有“孤儿进程”以 init 进程为“养父”,init 进程将负责“孤儿进程”结束后的资源释放任务。

这里区分一下僵尸进程和孤儿进程:
孤儿进程:一个父进程退出,而它的一个或多个子进程还在运行,那么那些子进程将成为孤儿进程。孤儿进程将被init 进程(进程号为1)所收养,并由 init 进程对它们完成状态收集工作;
僵尸进程:一个进程使用 fork 创建子进程,如果子进程退出,而父进程并没有调用 wait 或 waitpid 获取子进程的状态信息,那么子进程的进程描述符仍然保存在系统中。这种进程称之为僵死进程(也就是进程为中止状态,僵死状态)。
Linix 提供了一种机制可以保证只要父进程想知道子进程结束时的状态信息, 就可以得到。这种机制就是:在每个进程退出的时候,内核释放该进程所有的资源,包括打开的文件,占用的内存等。 但是仍然为其保留一定的信息(包括进程号 the process ID,退出状态 the termination status of the process,运行时间 the amount of CPU time taken by the process 等)。直到父进程通过 wait / waitpid 来取时才释放。 但这样就导致了问题,如果进程不调用 wait / waitpid 的话, 那么保留的那段信息就不会释放,其进程号就会一直被占用,但是系统所能使用的进程号是有限的,如果大量的产生僵死进程,将因为没有可用的进程号而导致系统不能产生新的进程。此即为僵尸进程的危害,应当避免。

系统调用 exit()

系统调用 exit() 用来终结一个进程,通常这个系统调用会在一些与进程控制有关的系统调用中被调用。
如果一个进程调用 exit(),那么这个进程会立即退出运行,并负责释放被中止进程除了进程控制块之外的各种内核数据结构。这种只剩下“身份证”的进程叫做“僵尸进程”,其进程控制块域 state 的值为 TASK_ZOMBLE。
一个因调用 exec 函数族函数而执行新的可执行文件的子进程,当进程执行结束时,便会执行系统调用 exit() 而使自己成为一个“僵尸进程”,这也正是父进程要负责销毁子进程的进程控制块的原因。
另外,exit() 执行到最后,将调用进程调度函数 schedule() 进行一次进程调度。

这里区分一下 exit() 和 _exit() 函数:
exit() 定义在 stdlib.h 文件,_exit() 定义在 unistd.h 文件中。同时两者的步骤也是不一样的:

具体体现在哪里呢?
在 Linux 标准库中,有一套称为高级 I/O 函数,例如我们所熟知的 printf、fopen、fread、fwrite 都在此列,它们也被称为缓冲 I/O。其特征是对应每一个打开的文件,都存在一个缓冲区,在每次读文件时会多读若干条记录,这样下次读文件时就可以直接从内存的缓冲区去读。在每次写文件时也会先写入缓冲区,当缓冲区写满,或者我们 fflush() 手动的刷新缓冲区,或者遇到 \n、EOF 这样的结束符,才会把对应的数据从缓冲区写入到文件中。这样的好处是大大增加的文件的读写的速度,因为我们都知道磁盘上的读写速度是很慢的,但这也为我们编程带来了一点麻烦,例如有些数据,我们认为已经写入了文件,但实际上它们很可能存在在缓冲区中。
也就是说,_exit() 函数的作用是:直接使进程停止运行,清除其使用的内存空间,并清除其在内核的各种数据结构;exit()函数则在这些基础上做了一些小动作,在执行退出之前还加了若干道工序。
exit() 函数与 _exit() 函数的最大区别在于 exit() 函数在调用 exit 系统调用前要检查文件的打开情况,把文件缓冲区中的内容写回文件。也就是图中的“清理I/O缓冲”。

系统调用 vfork()

vfork() 是 Linux 提供的另一个用来生成一个子进程的系统调用。
与 fork() 不同,vfork() 并不把父进程全部复制到子进程中,而只是用用赋值指针的方法使子进程与父进程的资源实现共享。由于函数 vfork() 生成的子进程与父进程共享同一块内存空间,因此实质上 vfork() 创建的是一个线程,但习惯上人们还是叫它子进程。
用 vfork() 创建子进程且调用 execve() 之后,子进程的内存映像如下所示:
vfork创建的子进程

这里区分一下 fork() 与 vfork():
fork():子进程拷贝父进程的数据段,代码段 。vfork():子进程与父进程共享数据段 ;
fork():父子进程的执行次序不确定 。vfork():保证子进程先运行,在调用 execve() 或 exit() 之前,与父进程数据是共享的,在它调用 execve() 或 exit() 之后,父进程才可能被调度运行。
注意:由于 vfork() 保证子进程先运行,在它调用 execve() 或 exit() 之后,父进程才可能被调度运行。如果在调用这两个函数之前,子进程依赖于父进程的进一步动作,则会导致死锁。

进程查看命令

ps 命令的三种执行风格(unix bsd GUN)

  • a 与终端相关的进程 (当用户登录系统时所产生的所有进程都是带终端的)
  • x 与终端无关的进程
  • u 用户信息归类的查看方式
  • f 进程层级关系
  • o 显示指定参数
  • e 显示所有进程
  • f 显示信息的完整格式
  • H 显示进程的层级结构
  • o 显示指定参数

ps ax 显示的信息如下

  • PID 进程 id
  • TTY 进程用到的终端
  • STAT 进程终端
  • TIME 进程占用 cpu 时长
  • COMMAND 进程名称

ps ax显示的信息

ps aux 显示信息如下

  • USER 进程所有人
  • PID 进程id
  • %cpu 进程占用 cpu 的使用量
  • %MEM 进程占用内存的使用量
  • VSZ 进程使用虚拟内存的大小
  • RSS 进程常驻内存的使用大小
  • TTY 进程使用到的终端
  • STAT 进程状态
  • START 进程运行时长
  • TIME 进程占用 cpu 时长
  • COMMAND 进程名称

ps aux显示的信息

pgrep 程序过滤(显示指定程序)
-u uid 显示指定用户的进程
-U user 显式指定用户的进程
-t tty 显示 i 指定终端进程
-l 显示进程名称
-a 显示进程的完整名称
-p 显示进程的子进程
pgrep -U
pgrep -u

pidof vim 查看 vim 的 pid
top 动态进程查看
1.系统时间 2.运行时长 3.系统中有几个用户登录 4.任务总量 5.正在运行 6.休眠任务数量
7.被暂停数量 8.僵死任务数量 9.cpu 占用 10.用户空间 11.内核空间 12. nice 值调整时间
13.空闲时间 14.等待 io 时间 15.处理硬件中断时间 16.处理软件中断时间 17被偷走的时间(vm 占用时间)
18.总量 19.空闲 20.占用 21.缓存 22.交换分区用量
top 显示的信息

top 内部参数命令
p cpu 排序
M 内存排序
T 累计使用 cpu 时间排序
l 关闭/开启 uptime 信息
t 关闭/开启 cpu & task
s 指定刷新率
k 操作进程
u 查看指定用户进程

进程优先级

1. 进程优先级
1.1 基本概念

由于系统中进程数量众多,而 CPU 资源比较少甚至只有一个,进程之间需要竞争来使用 CPU。这时让一个比较重要、需要优先执行的进程去和其他进程竞争,显然是不合理的。为了更合理的分配 CPU 资源,就有了进程优先级。

优先级高的进程有优先执行的权利。此外,优先级还影响分配给进程的时间片长短。 重要的进程,应该分配多一些 cpu 时间片,好让其尽快完成任务。所有的进程都会有机会运行,但优先级高的进程会获取更多的 cpu 执行时间。配置进程优先级对多任务环境的 Linux 很有用,可以改善系统性能。

1.2 优先级取值范围

实时进程与非实时进程
和其他操作系统类似,Linux 也支持两种进程:实时进程和非实时进程。 实时进程具有一定程度上的紧迫性,要求对外部事件做出非常快的响应;而非实时进程则没有这种限制。所以,调度程序要区分对待这两种进程,通常,实时进程要比非实时进程优先运行。实时进程会一直运行直到退出,除非它阻塞才会释放 CPU,实时进程只能被更高优先级的实时进程抢占,任意实时进程比非实时进程的优先级都要高。 这两种进程的区分也反映在 task_struct 数据结构中。

进程优先级取值范围
在 Linux 系统中,进程优先级的取值范围是 0-139 , 而这个值又是由另外两个值组成的,一个是代表实时进程(realtime)优先级范围是 [0, 99],另外一个是代表非实时进程,取值范围是 [100, 139]。 所以,Linux 进程实际上实现了 140 个优先级范围,取值范围是从 [0, 139],这个值越小,优先级越高。

动态优先级:实时进程优先级, 范围 [0,99],该区间被称为动态优先级,优先级随着进程执行情况的变化而改变,以便获得更好的调度性能。
静态优先级:非实时进程的优先级, 范围 [100,139],该区间被称为静态优先级,该值不会随着时间而进行改变,但系统可以通过 nice 来进行修改。

1.3 其他概念

竞争性:系统进程数目众多,而 CPU 资源只有少量,甚至1个,所以进程之间是具有竞争属性的。为了高效完成任务,更合理竞争相关资源,便具有了优先级
独立性:多进程运行,需要独享各种资源,多进程运行期间互不干扰
并行:多个进程在多个 CPU 下分别同时进行运行,这称之为并行
并发:多个进程在一个 CPU 下采用进程切换的方式,在一段时间之内,让多个进程都得以推进,称之为并发

2. 查看进程优先级

输入命令 ps -l 即可查看,其中关于进程优先级的信息如下:

  • PRI : 进程优先级,越小越优先
  • NI : 进程的 nice 值,用于调整进程优先级

PRI 代表的就是进程的优先级。其值越小,优先级越高,即越早的被 CPU 所执行。

输入 top 命令也可以查看:

  • NI:nice 值,用于修改 PRI,调整进程优先级。PRI(new) = PRI(old) + nice。当 nice 值为负值的时候,那么该程序优先级会变高(PRI数值降低)。在 Linux 下,调整进程优先级就是更改 NI,也就是 nice 值,nice 的取值为 [ -20 ~ 19 ],一共 40 个范围。
  • PR:PR 是在 top 命令执行后的显示,其代表的是进程的静态优先级,与静态优先级(static_priority)关系为:PR = static_priority - 100。static_priority 取值为[100, 139],所以 PR 取值是 [0, 39]。PR 和 NI 关系为:PR(new) = PR(old) + nice
3. 调整进程优先级

系统允许 root 用户设置负数优先级,以及减小现有进程的优先级数值大小。对普通用户仅允许设置正数优先级,并且只能增大现有进程的优先级数值大小。
进程的 nice 值,可以通过 nice 命令和 renice 命令修改,进而调整进程的运行顺序。

nice 命令可以给要启动的进程赋予 NI 值,但是不能修改已运行进程的 NI 值。
nice 命令格式如下:
nice [-n NI 值] 命令
-n NI 值:给命令赋予 NI 值,该值的范围为 -20~19;

同 nice 命令恰恰相反,renice 命令可以在进程运行时修改其 NI 值,从而调整优先级。
renice 命令格式如下:
renice [优先级] PID
注意,此命令中使用的是进程的 PID 号,因此常与 ps 等命令配合使用。

用 top 命令更改已存在进程的 nice 值来调整进程优先级

  • 执行 top 命令
  • 进入 top 后输入 r;输入需要修改的进程的进程号 PID;再输入 nice 的值,按回车即可

进程前后台调用

ctrl+z 把程序打入后台
process_name bg process_id 把挂起的程序运行起来
process_name fg process_id 把后台的进程调回前台
process_name & 进程运行在后台
jobs 查看当前 shell 中运行在后台的工作

进程信号

1. 信号的概念

信号是进程之间事件异步通知的一种方式,属于软中断
告诉有这样一个信号,但是这个信号的具体处理方式以及什么时候处理由进程决定,所以是软中断。

2. 信号的种类

使用命令 kill -l 可以列举出所有信号
kill -l

没有 32,33 号信号

  • 非实时信号(又称非可靠信号)
    特点:信号可能会丢失 1~31
  • 实时信号(又称可靠信号)
    特点:信号不会丢失 34~64
3. 信号的产生

信号的产生有如下四种方式:

  • 硬件产生
  • 软件产生
  • 进程异常,产生信号
    本质上所有的信号最后都是经过 OS 向目标进程发出来的
  1. 硬件产生

kill 命令向进程发送信号 kill [-信号值] [pid]

  • ctrl+c:2 号信号 SIGINT

键盘按下 ctrl+c 结束一个进程的时候,其实是进程收到了 2 号信号。2 号信号导致进程的退出

  • ctrl+z:20 号信号 SIGTSTP

使用 ctrl+z 会使一个程序进入暂停状态 T;

  • ctrl+|:3号信号 SIGQUIT

使用 ctrl+| 会使进程退出并产生core文件,类似于一个程序错误信号。

  1. 软件产生

kill 函数 int kill(pid_t pid,int sig);
pid:进程号,要给哪个进程发送信号,则填写哪个进程的进程号
sig:要发送信号的值

raise 函数 int raise(int sig);
谁调用则给谁发送信号。该函数的实现也是调用 kill 函数

  1. 进程异常
  • 引用空指针,野指针,垂悬指针(收到 11 号信号)
  • 内存访问越界(收到 11 号信号)
  • 除0(收到 8 号信号)
  • double free(收到 6 号信号)
4. 信号的处理方式

man 7 signal 查看

man 7 signal

  1. 默认处理方式

SIG_DFL:操作系统当中已经定义信号的处理方式了
2–>终止程序
11–>终止程序,并且产生核心转储文件

  1. 忽略处理方式

SIG_IGN:该信号为忽略处理
进程收到忽略处理信号后,不进行处理

SIGCHLD 17号信号
子进程先于父进程退出,子进程退出的时候会给父进程发送SIGCHLD,而父进程接收到这个信号后,是忽略处理的,导致父进程没有回收到子进程的退出状态信息,从而子进程变成僵尸进程。

  1. 自定义处理方式

程序员也可以更改信号的处理方式,定义一个函数,当进程收到该信号的时候,调用自己写的函数

守护进程

概念

守护进程也称精灵进程(Daemon),是运行在后台的一种特殊进程,它独立于控制终端并且周期性地执行某种任务或等待处理某些发生的事件。

守护进程是一种很有用的进程,Linux 的大多数服务器就是用守护进程实现的,比如 Internet 服务器 inetd,Web 服务器 httpd 等。同时守护进程完成许多系统任务,比如作业规划进程 crond 等。
Linux 系统启动时会启动很多系统服务进程,这些系统服务进程没有控制终端,不能直接和用户交互。其他进程都是在用户登录或运行程序时创建,在运行结束或用户注销时终止,但系统服务进程不受用户登录注销的影响,它们一直在运行着,这种进程有一个名称叫守护进程(Daemon)。

守护进程的查看
我们可以用 ps axj 命令查看系统中的进程

  • 参数 a 表示不仅列出当前用户的进程,也列出所有其他用户的进程。
  • 参数 x 表示不仅列出有控制终端的进程,也列出所有无控制终端的进程。
  • 参数 j 表示列出与作业控制相关的信息。

凡是 TPGID 一栏写着 -1 的都是没有控制终端的进程,也就是守护进程。
除此之外,TTY显示的是?,意味着该进程已经与终端去关联了;在 COMMAND 一列用 [ ] 括起来的名字表示内核线程,这些线程在内核里创建,没有用户空间代码,因此没有程序文件名和命令行,通常采用以 k 开头的名字,表示 Kernel。
个别说明:

  • udevd 负责维护 /dev 目录下的设备文件。
  • acpid 负责电源管理。
  • syslogd 负责维护 /var/log 下的日志文件。

可以看出,守护进程通常采用以 d 结尾的名字,表示 Daemon。

守护进程的创建
原生创建守护进程
守护进程的创建步骤如下:

  1. 设置文件掩码为 0。
  2. fork 后终止父进程,子进程创建新会话。
  3. 忽略 SIGCHLD 信号。
  4. 再次 fork,终止父进程,保持子进程不是会话首进程,从而保证后续不会再和其他终端相关联。
  5. 更改工作目录为根目录。
  6. 将标准输入、标准输出、标准错误重定向到 /dev/null。

相关说明:

  1. 将文件掩码设置为 0,保证后续守护进程创建文件时,创建出来的文件的权限符合我们的预期。
  2. 调用 setsid 创建新会话的目的,是让当前进程自成会话,与当前 bash 脱离关系(创建守护进程的核心)。
  3. 调用 setsid 创建新会话时,要求调用进程不能是进程组组长,但是当我们在命令行上启动多个进程协同完成某种任务时,其中第一个被创建出来的进程就是组长进程,因此我们需要 fork 创建子进程,让子进程调用 setsid 创建新会话并继续执行后续代码,而父进程我们直接让其退出即可。
  4. 守护进程不能直接和用户交互,也就没有必要再打开某个终端了,而打开一个终端需要你是会话首进程,为了防止守护进程打开终端,我们需要再次 fork 创建子进程并让子进程继续执行后续代码,由于子进程不是会话首进程,也就没有能力打开其他终端了,而父进程我们直接让其退出即可。(这是一种防御性编程,该操作不是必须的)
  5. 我们一般会将守护进程的工作目录设置为根目录,便于让守护进程以绝对路径的形式访问某种资源。(该操作不是必须的)
  6. 守护进程不能直接和用户交互,也就是说守护进程已经与终端去关联了,因此一般我们会将守护进程的标准输入、标准输出以及标准错误都重定向到 /dev/null,/dev/null 是一个字符文件(设备),通常用于屏蔽/丢弃输入输出信息。(该操作不是必须的)
  • 0
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值