开源之家
  • 首页
  • 精品培训视频
  • 计算机电子书
  • 软件工具
  • 知识库
    • Linux入门教程
    • Shell脚本学习指南
    • Nginx入门教程
    • Docker 入门实战
    • Kubernetes(k8s)手册
    • 快乐的Linux命令行
  • Linux命令手册
登录

Linux入门教程

01 Linux简介
  • 1.0 Linux学习路线
  • 1.1 操作系统概述
  • 1.2 Linux是什么,有哪些特点?
  • 1.3 Linux和UNIX的关系及区别(详解版)
  • 1.4 类UNIX系统是什么鬼?
  • 1.5 Linux中大量使用脚本语言,而不是C语言!
  • 1.6 为什么要学Linux,它比Windows好在哪里?
  • 1.7 Linux系统的优缺点
  • 1.8 常见Linux发行版本有哪些?
  • 1.9 初学者应选择哪个Linux发行版?
  • 1.10 Linux桌面系统大比拼|附带优缺点
  • 1.11 Linux的主要应用领域有哪些?
  • 1.12 Linux已经霸占了服务器领域!
  • 1.13 开源软件是什么?有哪些?
  • 1.14 开源协议是什么?有哪些?如何选择?
  • 1.15 开源就等于免费吗?用事实来说话
  • 1.16 Linux该如何学习(新手入门必看)
  • 1.17 想学好Linux,这些习惯必须养成(初学者必读)
02 Linux安装
  • 2.1 安装Linux系统对硬件有什么要求?
  • 2.2 虚拟机是什么
  • 2.3 为什么建议使用虚拟机来安装Linux?
  • 2.4 小白必看:零基础安装Linux系统(超级详细)
  • 2.5 使用U盘安装Linux系统
  • 2.6 使用dd命令安装Linux系统
  • 2.7 使用LiveCD从光盘直接运行Linux,无需安装
  • 2.8 忘记root账户密码怎么办?
  • 2.9 使用系统光盘修复Linux系统
  • 2.10 破解密码这么简单,Linux是安全的操作系统吗?
  • 2.11 Linux四种远程管理协议
  • 2.12 Linux两种远程管理工具(PuTTY和SecureCRT)
  • 2.13 新手必读的Linux使用注意事项
  • 2.14 Linux文件目录结构一览表
  • 2.15 Linux中一切皆文件[包含优缺点]
  • 2.16 Linux挂载详解
  • 2.17 新手必看的Linux服务器管理和维护注意事项
03 Linux文件和目录管理
  • 3.1 Linux文件系统的层次结构
  • 3.2 Linux文件系统到底有什么用处?
  • 3.3 Linux绝对路径和相对路径详解
  • 3.4 Linux文件(目录)命名规则
  • 3.5 Linux命令行下如何识别文件类型?
  • 3.6 Linux命令基本格式
  • 3.7 Linux切换目录(cd命令)
  • 3.8 Linux显示当前工作路径(pwd命令)
  • 3.9 Linux查看目录中的文件(ls命令)
  • 3.10 Linux创建目录(mkdir命令)
  • 3.11 Linux删除空目录(rmdir命令)
  • 3.12 Linux创建文件及修改文件时间戳(touch命令)
  • 3.13 Linux建立软硬链接文件(ln命令)
  • 3.14 深度剖析Linux硬链接和软链接,直击它们的本质!
  • 3.15 Linux复制文件和目录(cp命令)
  • 3.16 Linux删除文件或目录(rm命令)
  • 3.17 Linux移动或重命名文件和目录(mv命令)
  • 3.18 Linux懒人神器:命令自动补全功能!
  • 3.19 Linux命令的执行过程是怎样的?(新手必读)
  • 3.20 什么是环境变量,Linux环境变量有哪些?
  • 3.21 Linux PATH环境变量及作用(初学者必读)
04 Linux打包和压缩详解
  • 4.1 打包和压缩的概念和区别
  • 4.2 Linux tar打包命令详解
  • 4.3 Linux压缩文件或目录为.zip格式(zip命令)
  • 4.4 Linux解压.zip格式的文件(unzip命令)
  • 4.5 Linux压缩文件或目录中文件为.gz格式(gzip命令)
  • 4.6 Linux解压.gz格式的文件(gunzip命令)
  • 4.7 Linux压缩文件或目录中文件为.bz2格式(bzip2命令)
  • 4.8 Linux解压.bz2格式的文件(bunzip2命令)
05 Vim文本编辑器
  • 5.1 Vim及其安装
  • 5.2 Vi和Vim之间到底有什么关系?
  • 5.3 Linux Vim三种工作模式
  • 5.4 Linux Vim基本操作
  • 5.5 Vim移动光标命令汇总
  • 5.6 Linux Vim撤销和恢复撤销快捷键
  • 5.7 Linux Vim可视化模式
  • 5.8 Vim多窗口编辑模式
  • 5.9 Linux Vim批量注释和自定义注释
  • 5.10 Vim显示行号
  • 5.11 Vim配置文件(.vimrc)详解
06 Linux文本处理
  • 6.1 Linux连接合并文件内容(cat命令)
  • 6.2 Linux分屏显示文件内容(more命令)
  • 6.3 Linux显示文件开头内容(head命令)
  • 6.4 Linux查看文件内容(less命令)
  • 6.5 Linux显示文件结尾内容(tail命令)
  • 6.6 Linux重定向(输入输出重定向)
  • 6.7 Linux grep(Linux三剑客之一)
  • 6.8 Linux sed(Linux三剑客之一)
  • 6.9 Linux sed命令的高级玩法
  • 6.10 Linux awk(Linux三剑客之一)
  • 6.11 Linux awk命令的高级玩法
07 Linux系统软件安装
  • 7.1 Linux软件包
  • 7.2 Linux RPM包统一命名规则
  • 7.3 Linux RPM包安装、卸载和升级
  • 7.4 Linux rpm命令查询软件包
  • 7.5 Linux RPM包验证和数字证书
  • 7.6 Linux提取RPM包
  • 7.7 Linux SRPM源码包安装
  • 7.8 Linux重建RPM数据库(修复损坏的RPM数据库)
  • 7.9 RPM包的依赖性及其解决方案
  • 7.10 Linux yum源及配置
  • 7.11 Linux yum命令
  • 7.12 Linux yum管理软件组
  • 7.13 Linux源码包安装和卸载
  • 7.14 Linux源码包升级
  • 7.15 RPM包和源码包,究竟应该选择哪种安装方式?
  • 7.16 Linux函数库(静态函数库和动态函数库)及其安装过程
  • 7.17 Linux脚本程序包及安装方法详解(以webmin为例)
08 Linux用户和用户组管理
  • 8.1 Linux用户和用户组
  • 8.2 Linux UID和GID
  • 8.3 Linux /etc/passwd
  • 8.4 Linux /etc/shadow
  • 8.5 Linux /etc/group
  • 8.6 Linux /etc/gshadow
  • 8.7 Linux初始组和附加组
  • 8.8 Linux /etc/login.defs
  • 8.9 Linux系统添加新用户(useradd命令)
  • 8.10 Linux修改系统用户密码(passwd命令)
  • 8.11 Linux修改系统用户信息(usermod命令)
  • 8.12 Linux强制系统用户登陆时修改密码(chage命令)
  • 8.13 Linux删除系统用户(userdel命令)
  • 8.14 Linux查看用户的UID和GID(id命令)
  • 8.15 Linux临时切换用户身份(su命令)
  • 8.16 Linux whoami和who am i命令
  • 8.17 Linux添加用户组(groupadd命令)
  • 8.18 Linux修改用户组(groupmod命令)
  • 8.19 Linux删除用户组(groupdel命令)
  • 8.20 Linux将系统用户加入或移除群组(gpasswd命令)
  • 8.21 Linux切换用户的有效群组(newgrp命令)
09 Linux权限管理
  • 9.1 Linux权限管理的重要性
  • 9.2 Linux修改文件和目录的所属组(chgrp命令)
  • 9.3 Linux修改文件和目录的所有者和所属组(chown命令)
  • 9.4 Linux文件权限到底是如何设定的?
  • 9.5 Linux读写执行权限(-r、-w、-x)的真正含义是什么?
  • 9.6 Linux修改文件或目录权限(chmod命令)
  • 9.7 Linux默认权限的设定和修改(umask)
  • 9.8 Linux ACL访问控制权限
  • 9.9 Linux ACL权限设置(setfacl和getfacl)
  • 9.10 Linux mask有效权限有什么用,如何修改?
  • 9.11 Linux SetUID(SUID)特殊权限
  • 9.12 不要轻易设置SetUID(SUID)权限,否则会带来重大安全隐患!
  • 9.13 Linux SetGID(SGID)特殊权限
  • 9.14 Linux Stick BIT(SBIT)特殊权限
  • 9.15 Linux文件特殊权限(SUID、SGID和SBIT)的设置
  • 9.16 Linux修改文件或目录的隐藏属性(chattr命令)
  • 9.17 Linux查看文件或目录的隐藏属性(lsattr命令)
  • 9.18 Linux sudo命令(包含和su命令的对比)
  • 9.19 Linux权限对指令执行的影响
10 Linux文件系统管理
  • 10.1 硬盘结构(机械硬盘和固态硬盘)详解
  • 10.2 Linux文件系统详解
  • 10.3 Linux系统是如何识别硬盘设备和硬盘分区的?
  • 10.4 Linux df用法详解:查看文件系统硬盘使用情况
  • 10.5 Linux du命令:统计目录或文件所占磁盘空间大小
  • 10.6 Linux mount命令详解:挂载Linux系统外的文件
  • 10.7 Linux挂载光盘(使用mount命令)
  • 10.8 Linux挂载U盘(使用mount命令)
  • 10.9 Linux开机自动挂载硬件设备(配置/etc/fatab文件)
  • 10.10 修改/etc/fstab文件出错导致Linux不能启动,该怎么办?
  • 10.11 Linux umount命令:卸载文件系统
  • 10.12 Linux fsck命令:检测和修复文件系统
  • 10.13 Linux dumpe2fs命令:查看文件系统信息
  • 10.14 Linux fdisk命令详解:给硬盘分区
  • 10.15 Linux fdisk创建分区(主分区、扩展分区和逻辑分区)过程详解
  • 10.16 Linux parted命令用法详解:创建分区
  • 10.17 Linux mkfs命令详解格式化分区(为分区写入文件系统)
  • 10.18 Linux mke2fs命令格式化硬盘(给硬盘写入文件系统)
  • 10.19 Linux虚拟内存和物理内存
  • 10.20 Linux swap分区及作用详解
11 Linux高级文件系统管理
  • 11.1 磁盘配额是什么
  • 11.2 磁盘配额启动前的准备工作
  • 11.3 Linux扫描文件系统并建立磁盘配额记录文件(quotacheck命令)
  • 11.4 Linux开启磁盘配额限制(quotaon命令)
  • 11.5 Linux关闭磁盘配额限制(quotaoff命令)
  • 11.6 Linux修改用户(群组)的磁盘配额(edquota命令)
  • 11.7 Linux非交互式设置磁盘配额(setquota命令)
  • 11.8 Linux查询已建立好的磁盘配额(quota和repquota命令)
  • 11.9 Linux磁盘配额测试过程完全攻略
  • 11.10 Linux LVM逻辑卷管理机制
  • 11.11 Linux PV物理卷
  • 11.12 Linux VG卷组
  • 11.13 Linux LV逻辑卷
  • 11.14 Linux LVM(逻辑卷管理)的删除
  • 11.15 Linux RAID(磁盘阵列)完全攻略
  • 11.16 使用图形界面来配置RAID
  • 11.17 使用mdadm命令来配置RAID
12 Linux系统管理
  • 12.1 Linux进程管理
  • 12.2 Linux进程启动的方式有几种?
  • 12.3 Linux如何查看正在运行的进程(ps命令)
  • 12.4 Linux实时监听进程运行状态(top命令)
  • 12.5 Linux查看进程树(pstree命令)
  • 12.6 Linux列出进程调用或打开的文件信息(lsof命令)
  • 12.7 Linux进程优先级
  • 12.8 Linux调整进程的优先级(nice和renice命令)
  • 12.9 Linux常用信号(进程间通信)
  • 12.10 Linux终止进程(kill命令)
  • 10.11 Linux umount命令:卸载文件系统
  • 10.12 Linux fsck命令:检测和修复文件系统
  • 10.13 Linux dumpe2fs命令:查看文件系统信息
  • 10.14 Linux fdisk命令详解:给硬盘分区
  • 10.15 Linux fdisk创建分区(主分区、扩展分区和逻辑分区)过程详解
  • 10.16 Linux parted命令用法详解:创建分区
  • 10.17 Linux mkfs命令详解格式化分区(为分区写入文件系统)
  • 10.18 Linux mke2fs命令格式化硬盘(给硬盘写入文件系统)
  • 10.19 Linux虚拟内存和物理内存
  • 10.20 Linux swap分区及作用详解
13 Linux数据备份与恢复
  • 13.1 Linux备份的重要性
  • 13.2 Linux中的哪些数据需要备份?
  • 13.3 Linux数据备份介质的选择
  • 13.4 Linux备份策略
  • 13.5 Linux tar命令备份数据
  • 13.6 Linux dump
  • 13.7 Linux restore
  • 13.8 Linux dd
  • 13.9 Linux rsync命令:支持本地备份和远程备份
14 Linux系统服务管理
  • 14.1 Linux系统服务
  • 14.2 Linux端口
  • 14.3 Linux独立服务管理
  • 14.4 Linux基于xinetd服务的管理
  • 14.5 Linux源码包服务管理
  • 14.6 Linux常见服务类别及功能
  • 14.7 影响Linux系统性能的因素有哪些?
  • 14.8 Linux分析系统性能(sar命令)
  • 14.9 Linux如何查看CPU运行状态?
  • 14.10 Linux如何查看内存的使用情况?
  • 14.11 Linux如何查看硬盘的读写性能?
15 Linux系统日志管理
  • 15.1 Linux rsyslogd服务
  • 15.2 Linux日志文件及功能
  • 15.3 Linux日志文件的格式分析
  • 15.4 rsyslogd配置文件格式及其内容
  • 15.5 Linux日志服务器设置
  • 15.6 Linux日志轮替(日志转储)
  • 15.7 Linux logrotate命令
  • 15.8 Linux日志分析工具
16 Linux系统启动管理
  • 16.1 Linux系统启动流程
  • 16.2 BIOS开机自检
  • 16.3 主引导目录(MBR)结构及作用
  • 16.4 Linux内核(内核模块)的加载
  • 16.5 Linux /sbin/init
  • 16.6 Linux /etc/inittab
  • 16.7 Linux /etc/rc.d/rc.local配置文件
  • 16.8 Linux启动引导程序加载内核
  • 16.9 Linux /boot/grub/目录
  • 16.10 Linux GRUB磁盘分区表示法
  • 16.11 Linux GRUB配置文件
  • 16.12 Linux多系统并存的GRUB配置文件
  • 16.13 Linux GRUB手动安装
  • 16.14 Linux GRUB加密
  • 16.15 Linux字符界面调整分辨率
  • 16.16 Linux内核模块管理
  • 16.17 Linux NTFS文件系统安装
17 LAMP环境搭建和LNMP环境搭建
  • 17.1 Linux LAMP环境搭建的前期准备
  • 17.2 Linux libxml2安装
  • 17.3 Linux libmcrypt安装
  • 17.4 Linux mhash和mcrypt安装
  • 17.5 Linux zlib和libpng安装
  • 17.6 Linux jpeg6安装
  • 17.7 Linux freetype安装
  • 17.8 Linux gd库安装
  • 17.9 Linux Apache安装
  • 17.10 Linux ncurses安装
  • 17.11 Linux MySQL安装
  • 17.12 Linux PHP安装
  • 17.13 Linux memcache安装和配置
  • 17.14 Linux phpmyadmin安装及配置
  • 17.15 LNMP安装的前期准备
  • 17.16 LNMP一键安装
  • 17.17 LNMP安装php扩展模块
18 SELinux管理
  • 18.1 SELinux是什么
  • 18.2 SELinux的主要作用
  • 18.3 SELinux 的3种工作模式
  • 18.4 SELinux配置文件(/etc/selinux/config)
  • 18.5 SELinux工作模式设置
  • 18.6 SELinux安全上下文查看
  • 18.7 SELinux安全上下文的修改和设置
  • 18.8 SELinux默认安全上下文的查询和修改
  • 18.9 SELinux auditd日志系统的安装与启动
  • 18.10 SELinux auditd日志使用方法
  • 18.11 SELinux的3种策略类型
  • 18.12 SELinux策略规则查看的方法
  • 18.13 SELinux策略规则的开启和关闭

Shell脚本学习指南

01 Shell基础
  • 1.1 Shell是什么
  • 1.2 Shell是运维人员必须掌握的技能
  • 1.3 常用的Shell有哪些?
  • 1.4 进入Shell的两种方式
  • 1.5 Shell命令的基本格式
  • 1.6 Shell命令的本质到底是什么?如何自己实现一个命令?
  • 1.7 Shell命令的选项和参数在本质上是什么
  • 1.8 Shell命令提示符
  • 1.9 修改命令提示符
  • 1.10 第一个Shell脚本
  • 1.11 执行Shell脚本
  • 1.12 Shell四种运行方式
  • 1.13 Shell配置文件的加载
  • 1.14 如何编写自己的Shell配置文件?
02 Shell编程
  • 2.1 Shell变量
  • 2.2 Linux中的文件描述符到底是什么?
  • 2.3 Shell命令替换
  • 2.4 Shell位置参数
  • 2.5 Shell特殊变量
  • 2.6 Shell $*和$@之间的区别
  • 2.7 Shell $?
  • 2.8 Shell字符串详解
  • 2.9 Shell字符串拼接
  • 2.10 Shell字符串截取
  • 2.11 Shell数组
  • 2.12 Shell获取数组长度
  • 2.13 Shell数组拼接
  • 2.14 Shell删除数组元素
  • 2.15 Shell关联数组
  • 2.16 Shell内建命令
  • 2.17 Shell alias命令
  • 2.18 Shell echo命令
  • 2.19 Shell read命令
  • 2.20 Shell exit命令
  • 2.21 Shell declare和typeset命令
  • 2.22 Shell数学计算
  • 2.23 Shell (())
  • 2.24 Shell let命令
  • 2.25 Shell $[]
  • 2.26 Shell expr命令
  • 2.27 Linux bc命令
  • 2.28 Shell declare -i
  • 2.29 Shell if else
  • 2.30 Shell退出状态
  • 2.31 Shell test命令
  • 2.32 Shell [[]]
  • 2.33 Shell case in
  • 2.34 Shell while
  • 2.35 Shell until
  • 2.36 Shell for
  • 2.37 Shell select in
  • 2.38 Shell break和continue
  • 2.39 Shell函数
  • 2.40 Shell函数参数
  • 2.41 Shell函数返回值精讲
03 Shell高级教程
  • 3.1 Shell重定向
  • 3.2 Linux中的文件描述符到底是什么?
  • 3.3 结合文件描述符谈重定向,彻底理解重定向的本质!
  • 3.4 使用exec命令操作文件描述符
  • 3.5 使用exec命令操作文件描述符
  • 3.6 Shell Here Document
  • 3.7 Shell Here String
  • 3.8 Shell组命令
  • 3.9 Shell进程替换
  • 3.10 Linux管道
  • 3.11 Shell过滤器
  • 3.12 子Shell和子进程到底有什么区别?
  • 3.13 如何检测子Shell和子进程?
  • 3.14 Linux中的信号是什么
  • 3.15 Bash Shell中的信号
  • 3.16 Linux进程简明教程
  • 3.17 使用什么命令查看进程
  • 3.18 Shell向进程发送信号
  • 3.19 使用trap命令获取信号
  • 3.20 trap命令捕获信号实例演示
  • 3.21 移除(重置)信号捕获
  • 3.22 关于进程、信号和捕获的总结
  • 3.23 Shell模块化
04 Bash Shell快捷键
  • 4.1 Bash Shell快捷键大全
  • 4.2 Bash Shell命令自动补全功能
  • 4.3 Bash Shell历史命令

Nginx入门教程

01 Nginx基础
  • 1.1 前言
  • 1.2 Nginx 简介
  • 1.3 Nginx 源码架构分析
  • 1.4 Nginx 编译安装
  • 1.5 Tengine 编译安装
  • 1.6 OpenResty 编译安装
  • 1.7 Nginx 配置简述
  • 1.8 Nginx Docker 容器化配置
02 Nginx核心配置
  • 2.1 Nginx 核心配置指令
  • 2.2 Nginx 配置文件
  • 2.3 Nginx 进程配置指令
  • 2.4 Nginx 端口监听
  • 2.5 Nginx 主机名
  • 2.6 Nginx 处理HTTP请求
  • 2.7 Nginx 路由匹配规则
  • 2.8 Nginx 重定向配置
  • 2.9 Nginx 根目录配置
  • 2.10 Nginx 访问路径别名
  • 2.11 Nginx 文件判断
  • 2.12 Nginx 零复制
  • 2.13 Nginx 日志记录配置
03 Nginx HTTP模块
  • 3.1 Nginx 镜像模块
  • 3.2 Nginx 请求头控制模块
  • 3.3 Nginx IP访问控制模块
  • 3.4 Nginx 用户cookie模块
  • 3.5 Nginx 并发连接数限制模块
  • 3.6 Nginx 首页处理模块
  • 3.7 Nginx 请求频率限制模块
  • 3.8 Nginx 页面缓存时间配置
  • 3.9 Nginx gzip压缩及相关配置
04 Nginx Web服务
  • 4.1 Nginx 静态资源服务器搭建
  • 4.2 Nginx 文件下载服务器搭建
  • 4.3 Nginx 伪动态SSI服务器
  • 4.4 Nginx HTTPS服务器搭建
  • 4.5 Nginx FastCGI模块配置简述
  • 4.6 Nginx PHP服务器环境搭建
  • 4.7 Nginx 基于FastCGI负载均衡
  • 4.8 Nginx CGI网关接口
  • 4.9 Nginx uWSGI模块配置
  • 4.10 Nginx Python项目部署
  • 4.11 Nginx 伪流媒体服务器搭建
  • 4.12 Nginx HTTP2模块配置简述
  • 4.13 Nginx WebDAV模块配置简述
05 Nginx 代理服务器
  • 5.1 Nginx HTTP代理服务器
  • 5.2 Nginx stream模块简述
  • 5.3 Nginx TCPUDP代理简述
  • 5.4 Nginx 基于SSL的TCP代理服务器
  • 5.5 Nginx gRPC代理服务器
06 Nginx 缓存
  • 6.1 Nginx Web缓存配置
  • 6.2 Nginx 代理缓存配置
  • 6.3 Nginx Memcached 缓存模块
  • 6.4 Nginx 反向代理缓存服务器配置
  • 6.5 Nginx 客户端缓存控制
07 Nginx 负载均衡
  • 7.6 Nginx TCPUDP负载均衡
  • 7.5 Nginx upstream动态更新
  • 7.4 Nginx upstream容错机制
  • 7.3 Nginx 长连接负载均衡
  • 7.2 Nginx 负载均衡策略
  • 7.1 Nginx 负载均衡模块
08 Nginx 日志管理监控
  • 8.1 Nginx 日志分析简述
  • 8.2 Nginx 访问日志配置
  • 8.3 Nginx 错误日志配置
  • 8.4 Nginx 日志归档配置
  • 8.5 Nginx 日志分析工具 ELK
  • 8.6 Nginx 监控工具 Prometheus
09 Nginx 集群
  • 9.1 LVS简介
  • 9.2 Keepalived 配置简述
  • 9.3 Nginx 集群负载搭建
  • 9.4 Nginx 集群配置管理规划
  • 9.5 Nginx 配置归档工具GitLab
  • 9.6 Nginx 配置修改工具Ansible
  • 9.7 Jenkins 安装与配置简述
  • 9.8 Nginx 集群配置管理实例
10 Nginx 在 k8s 的应用
  • 10.1 Kubernetes(k8s)系统简述
  • 10.2 Kubernetes(k8s)集群部署
  • 10.3 Kubernetes(k8s)网络通信
  • 10.4 Nginx Ingress 简介
  • 10.5 Nginx Ingress 安装部署
  • 10.6 Nginx Ingress 配置映射
  • 10.7 Nginx Ingress 注解

Docker 入门实战

01 Docker基础
  • 1.1 前言
  • 1.2 Docker 架构
02 Docker安装
  • 2.1 CentOS Docker 安装
  • 2.2 Ubuntu Docker 安装
  • 2.3 Debian Docker 安装
  • 2.4 Windows Docker 安装
  • 2.5 MacOS Docker 安装
  • 2.6 Docker 镜像加速
03 Docker 使用
  • 3.1 Docker Hello World
  • 3.2 Docker 容器使用
  • 3.3 Docker 镜像使用
  • 3.4 Docker 容器连接
  • 3.5 Docker 仓库管理
  • 3.6 Docker Dockerfile
  • 07 Docker Compose
  • 08 Docker Machine
  • 09 Swarm 集群管理
04 Docker 实例
  • 4.1 Docker 安装 Ubuntu
  • 4.2 Docker 安装 CentOS
  • 4.3 Docker 安装 Nginx
  • 4.4 Docker 安装 Node.js
  • 4.5 Docker 安装 PHP
  • 4.6 Docker 安装 MySQL
  • 4.7 Docker 安装 Tomcat
  • 4.8 Docker 安装 Python
  • 4.9 Docker 安装 Redis
  • 4.10 Docker 安装 MongoDB
  • 4.11 Docker 安装 Apache
05 Docker 参考手册
  • 5.1 Docker 常用命令
  • 5.2 Docker 备忘单

Kubernetes(k8s)手册

01 kubernetes 概述
  • 01 kubernetes 简介
  • 02 Kubernetes 组件
  • 03 Kubernetes API
02 Kubernetes 安装
  • 01 Kubernetes Linux安装

快乐的Linux命令行

  • 第1章:引言
  • 第2章:什么是 shell
  • 第3章:文件系统中跳转
  • 第4章:探究操作系统
  • 第5章:操作文件和目录
  • 第6章:使用命令
  • 第7章:重定向
  • 第8章:从Shell眼中看世界
  • 第9章:键盘高级操作技巧
  • 第10章:权限
  • 第11章:进程
  • 第12章:Shell环境
  • 第13章:vi简介
  • 第14章:自定制Shell提示符
  • 第15章:软件包管理
  • 第16章:存储媒介
  • 第17章:网络系统
  • 第18章:查找文件
  • 第19章:归档和备份
  • 第20章:正则表达式
  • 第21章:文本处理
  • 第22章:格式化输出
  • 第23章:打印
  • 第24章:编译程序
  • 第25章:编写第一个Shell脚本
  • 第26章:启动一个项目
  • 第27章 : 自顶向下设计
  • 第28章 : 流程控制:if 分支结构
  • 第29章 : 读取键盘输入
  • 第30章 : 流程控制:while/until 循环
  • 第31章 : 疑难排解
  • 第32章 : 流程控制:case 分支
  • 第33章 : 位置参数
  • 第34章 : 流程控制:for 循环
  • 第35章 : 字符串和数字
  • 第36章 : 数组
  • 第37章 : 奇珍异宝

第24章:编译程序

文章目录
  • 24.1 什么是编译?
    • 24.1.1 所有的程序都是可编译的吗?
  • 24.2 编译一个 C 语言
    • 24.2.1 得到源码
  • 24.3 检查源码树
    • 24.3.1 构建程序
    • 24.3.2 安装程序
  • 24.4 总结

第24章:编译程序

在这一章中,我们将看一下如何通过编译源代码来创建程序。源代码的可用性是至关重要的自由,从而使得 Linux 成为可能。整个 Linux 开发生态圈就是依赖于开发者之间的自由交流。对于许多桌面用户来说,编译是一种失传的艺术。以前很常见,但现在,由系统发行版提供商维护巨大的预编译的二进制仓库,准备供用户下载和使用。在写这篇文章的时候,Debian 仓库(最大的发行版之一)包含了几乎23,000个预编译的包。

那么为什么要编译软件呢? 有两个原因:

  1. 可用性。尽管系统发行版仓库中已经包含了大量的预编译程序,但是一些发行版本不可能包含所有期望的应用。在这种情况下,得到所期望程序的唯一方式是编译程序源码。

  2. 及时性。虽然一些系统发行版专门打包前沿版本的应用程序,但是很多不是。这意味着,为了拥有一个最新版本的程序,编译是必需的。

从源码编译软件可以变得非常复杂且具有技术性;许多用户难以企及。然而,许多编译任务是相当简单的,只涉及到几个步骤。这都取决于程序包。我们将看一个非常简单的案例, 为的是给大家提供一个对编译过程的整体认识,并为那些愿意进一步学习的人们构筑一个起点。

我们将介绍一个新命令:

  • make - 维护程序的工具

24.1 什么是编译?

简而言之,编译就是把源码(一个由程序员编写的人类可读的程序的说明)翻译成计算机处理器的语言的过程。

计算机处理器(或 CPU)工作在一个非常基本的水平,执行用机器语言编写的程序。这是一种数值编码,描述非常小的操作,比如“加这个字节”、“指向内存中的这个位置”或者“复制这个字节”。

这些指令中的每一条都是用二进制表示的(1和0)。最早的计算机程序就是用这种数值编码写成的,这可能就解释了为什么编写它们的程序员据说吸很多烟,喝大量咖啡,并带着厚厚的眼镜。随着汇编语言的出现,这个问题得到克服。汇编语言使用诸如CPY(复制)和 MOV(移动)之类(略微)易用的字符助记符代替了数值编码 。用汇编语言编写的程序通过汇编器处理为机器语言。今天为了完成某些特定的程序任务,汇编语言仍在被使用,例如设备驱动和嵌入式系统。

下一步我们谈论一下什么是所谓的高级编程语言。之所以这样称呼它们,是因为它们可以让程序员少操心处理器的一举一动,而更多关心如何解决手头的问题。早期的高级语言(二十世纪50年代期间研发的)包括 FORTRAN(为科学和技术任务而设计)和 COBOL(为商业应用而设计)。今天这两种语言仍在有限的使用。

虽然有许多流行的编程语言,两个占主导地位。大多数为现代系统编写的程序,要么用 C 编写,要么是用 C++ 编写。在随后的例子中,我们将编写一个 C 程序。

用高级语言编写的程序,经过另一个称为编译器的程序的处理,会转换成机器语言。一些编译器把高级指令翻译成汇编语言,然后使用一个汇编器完成翻译成机器语言的最后阶段。

一个称为链接的过程经常与编译结合在一起。有许多常见的由程序执行的任务。以打开文件为例。许多程序执行这个任务,但是让每个程序实现它自己的打开文件功能,是很浪费资源的。更有意义的是,拥有单独的一段知道如何打开文件的程序,并允许所有需要它的程序共享它。对常见任务提供支持由所谓的库完成。这些库包含多个程序,每个程序执行一些可以由多个程序共享的常见任务。如果我们看一下 /lib 和 /usr/lib 目录,我们可以看到许多库定居在那里。一个叫做链接器的程序用来在编译器的输出结果和要编译的程序所需的库之间建立连接。这个过程的最终结果是一个可执行程序文件,准备使用。

24.1.1 所有的程序都是可编译的吗?

不是。正如我们所看到的,有些程序比如 shell 脚本就不需要编译。它们直接执行。这些程序是用所谓的脚本或解释型语言编写的。近年来,这些语言变得越来越流行,包括 Perl、Python、PHP、Ruby和许多其它语言。

脚本语言由一个叫做解释器的特殊程序执行。一个解释器输入程序文件,读取并执行程序中包含的每一条指令。通常来说,解释型程序执行起来要比编译程序慢很多。这是因为每次解释型程序执行时,程序中每一条源码指令都需要翻译,而一个已经编译好的程序,一条源码指令只翻译了一次,翻译后的指令会永久地记录到最终的执行文件中。

那么为什么解释型程序这样流行呢?对于许多编程任务来说,原因是“足够快”,但是真正的优势是一般来说开发解释型程序要比编译程序快速且容易。通常程序开发需要经历一个不断重复的写码、编译和测试周期。随着程序变得越来越大,编译阶段会变得相当耗时。解释型语言删除了编译步骤,这样就加快了程序开发。

24.2 编译一个 C 语言

让我们编译一些东西。在我们编译之前,然而我们需要一些工具,像编译器、链接器以及 make。在 Linux 环境中,普遍使用的 C 编译器叫做 gcc(GNU C 编译器),最初由 Richard Stallman 写出来的。大多数 Linux 系统发行版默认不安装 gcc。我们可以这样查看该编译器是否存在:

[me@linuxbox ~]$ which gcc
/usr/bin/gcc

在这个例子中的输出结果表明安装了 gcc 编译器。


小提示: 你的系统发行版可能有一个用于软件开发的 meta-package(软件包的集合)。如果是这样的话,若你打算在你的系统中编译程序就考虑安装它。若你的系统没有提供一个 meta-package,试着安装 gcc 和 make 工具包。在许多发行版中,这就足够完成下面的练习了


24.2.1 得到源码

为了我们的编译练习,我们将编译一个叫做 diction 的程序,来自 GNU 项目。这是一个小巧方便的程序,检查文本文件的书写质量和样式。就程序而言,它相当小,且容易创建。

遵照惯例,首先我们要创建一个名为 src 的目录来存放我们的源码,然后使用 ftp 协议把源码下载下来。

[me@linuxbox ~]$ mkdir src
[me@linuxbox ~]$ cd src
[me@linuxbox src]$ ftp ftp.gnu.org
Connected to ftp.gnu.org.
220 GNU FTP server ready.
Name (ftp.gnu.org:me): anonymous
230 Login successful.
Remote system type is UNIX.
Using binary mode to transfer files.
ftp> cd gnu/diction
250 Directory successfully changed.
ftp> ls
200 PORT command successful. Consider using PASV.
150 Here comes the directory listing.
-rw-r--r-- 1 1003 65534 68940 Aug 28 1998 diction-0.7.tar.gz
-rw-r--r-- 1 1003 65534 90957 Mar 04 2002 diction-1.02.tar.gz
-rw-r--r-- 1 1003 65534 141062 Sep 17 2007 diction-1.11.tar.gz
226 Directory send OK.
ftp> get diction-1.11.tar.gz
local: diction-1.11.tar.gz remote: diction-1.11.tar.gz
200 PORT command successful. Consider using PASV.
150 Opening BINARY mode data connection for diction-1.11.tar.gz
(141062 bytes).
226 File send OK.
141062 bytes received in 0.16 secs (847.4 kB/s)
ftp> bye
221 Goodbye.
[me@linuxbox src]$ ls
diction-1.11.tar.gz

注意:因为我们是这个源码的“维护者”,当我们编译它的时候,我们把它保存在 ~/src 目录下。由你的系统发行版源码会把源码安装在 /usr/src 目录下,而供多个用户使用的源码,通常安装在 /usr/local/src 目录下。


正如我们所看到的,通常提供的源码形式是一个压缩的 tar 文件。有时候称为 tarball,这个文件包含源码树,或者是组成源码的目录和文件的层次结构。当到达 ftp 站点之后,我们检查可用的 tar 文件列表,然后选择最新版本,下载。使用 ftp 中的 get 命令,我们把文件从 ftp 服务器复制到本地机器。

一旦 tar 文件下载下来之后,必须解包。通过 tar 程序可以完成:

[me@linuxbox src]$ tar xzf diction-1.11.tar.gz
[me@linuxbox src]$ ls
diction-1.11
diction-1.11.tar.gz

小提示:该 diction 程序,像所有的 GNU 项目软件,遵循着一定的源码打包标准。其它大多数在 Linux 生态系统中可用的源码也遵循这个标准。该标准的一个条目是,当源码 tar 文件打开的时候,会创建一个目录,该目录包含了源码树,并且这个目录将会命名为 project-x.xx,其包含了项目名称和它的版本号两项内容。这种方案能在系统中方便安装同一程序的多个版本。然而,通常在打开 tarball 之前检验源码树的布局是个不错的主意。一些项目不会创建该目录,反而,会把文件直接传递给当前目录。这会把你的(除非组织良好的)src 目录弄得一片狼藉。为了避免这个,使用下面的命令,检查 tar 文件的内容:

tar tzvf tarfile | head

24.3 检查源码树

打开该 tar 文件,会创建一个新的目录,名为 diction-1.11。这个目录包含了源码树。让我们看一下里面的内容:

[me@linuxbox src]$ cd diction-1.11
[me@linuxbox diction-1.11]$ ls
config.guess     diction.c          getopt.c      nl
config.h.in      diction.pot        getopt.h      nl.po
config.sub       diction.spec       getopt_int.h  README
configure        diction.spec.in    INSTALL       sentence.c
configure.in     diction.texi.in    install-sh    sentence.h
COPYING en       Makefile.in        style.1.in
de               en_GB              misc.c        style.c
de.po            en_GB.po           misc.h        test
diction.1.in     getopt1.c          NEWS

在源码树中,我们看到大量的文件。属于 GNU 项目的程序,还有其它许多程序都会,提供文档文件 README,INSTALL,NEWS,和 COPYING。

这些文件包含了程序描述,如何建立和安装它的信息,还有其它许可条款。在试图建立程序之前,仔细阅读 README 和 INSTALL 文件,总是一个不错的主意。

在这个目录中,其它有趣的文件是那些以 .c 和 .h 为后缀的文件:

[me@linuxbox diction-1.11]$ ls *.c
diction.c getopt1.c getopt.c misc.c sentence.c style.c
[me@linuxbox diction-1.11]$ ls *.h
getopt.h getopt_int.h misc.h sentence.h

这些 .c 文件包含了由该软件包提供的两个 C 程序(style 和 diction),被分割成模块。这是一种常见做法,把大型程序分解成更小,更容易管理的代码块。源码文件都是普通文本,可以用 less 命令查看:

[me@linuxbox diction-1.11]$ less diction.c

这些 .h 文件被称为头文件。它们也是普通文件。头文件包含了程序的描述,这些程序被包括在源码文件或库中。为了让编译器链接到模块,编译器必须接受所需的所有模块的描述,来完成整个程序。在 diction.c 文件的开头附近,我们看到这行代码:

#include "getopt.h"

当它读取 diction.c 中的源码的时候,这行代码指示编译器去读取文件 getopt.h, 为的是“知道” getopt.c 中的内容。getopt.c 文件提供由 style 和 diction 两个程序共享的例行程序。

在 getopt.h 的 include 语句上面,我们看到一些其它的 include 语句,比如这些:

#include <regex.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>

这些文件也是头文件,但是这些头文件在当前源码树的外面。它们由操作系统供给,来支持每个程序的编译。如果我们看一下 /usr/include 目录,能看到它们:

[me@linuxbox diction-1.11]$ ls /usr/include

当我们安装编译器的时候,这个目录中的头文件会被安装。

24.3.1 构建程序

Most programs build with a simple, two-command sequence:

大多数程序通过一个简单的,两个命令的序列构建:

./configure
make

这个 configure 程序是一个 shell 脚本,由源码树提供。它的工作是分析程序构建环境。大多数源码会设计为可移植的。也就是说,它被设计成能够在不止一种类 Unix 系统中进行构建。但是为了做到这一点,在建立程序期间,为了适应系统之间的差异,源码可能需要经过轻微的调整。configure 也会检查是否安装了必要的外部工具和组件。让我们运行 configure 命令。因为 configure 命令所在的位置不是位于 shell 通常期望程序所呆的地方,我们必须明确地告诉 shell 它的位置,通过在命令之前加上 ./ 字符,来表明程序位于当前工作目录:

[me@linuxbox diction-1.11]$ ./configure

configure 将会输出许多信息,随着它测试和配置整个构建过程。当结束后,输出结果看起来像这样:

checking libintl.h presence... yes
checking for libintl.h... yes
checking for library containing gettext... none required
configure: creating ./config.status
config.status: creating Makefile
config.status: creating diction.1
config.status: creating diction.texi
config.status: creating diction.spec
config.status: creating style.1
config.status: creating test/rundiction
config.status: creating config.h
[me@linuxbox diction-1.11]$

这里最重要的事情是没有错误信息。如果有错误信息,整个配置过程失败,然后程序不能构建直到修正了错误。

我们看到在我们的源码目录中 configure 命令创建了几个新文件。最重要一个是 Makefile。Makefile 是一个配置文件,指示 make 程序究竟如何构建程序。没有它,make 程序就不能运行。Makefile 是一个普通文本文件,所以我们能查看它:

[me@linuxbox diction-1.11]$ less Makefile

这个 make 程序把一个 makefile 文件作为输入(通常命名为 Makefile),makefile 文件描述了包括最终完成的程序的各组件之间的关系和依赖性。

makefile 文件的第一部分定义了变量,这些变量在该 makefile 后续章节中会被替换掉。例如我们看看这一行代码:

CC=                 gcc

其定义了所用的 C 编译器是 gcc。文件后面部分,我们看到一个使用该变量的实例:

diction:        diction.o sentence.o misc.o getopt.o getopt1.o
                $(CC) -o $@ $(LDFLAGS) diction.o sentence.o misc.o \
                getopt.o getopt1.o $(LIBS)

这里完成了一个替换操作,在程序运行时,$(CC) 的值会被替换成 gcc。大多数 makefile 文件由行组成,每行定义一个目标文件,在这种情况下,目标文件是指可执行文件 diction,还有目标文件所依赖的文件。剩下的行描述了从目标文件的依赖组件中创建目标文件所需的命令。在这个例子中,我们看到可执行文件 diction(最终的成品之一)依赖于文件diction.o,sentence.o,misc.o,getopt.o,和 getopt1.o都存在。在 makefile 文件后面部分,我们看到diction 文件所依赖的每一个文件做为目标文件的定义:

diction.o:       diction.c config.h getopt.h misc.h sentence.h
getopt.o:        getopt.c getopt.h getopt_int.h
getopt1.o:       getopt1.c getopt.h getopt_int.h
misc.o:          misc.c config.h misc.h
sentence.o:      sentence.c config.h misc.h sentence.h
style.o:         style.c config.h getopt.h misc.h sentence.h

然而,我们不会看到针对它们的任何命令。这个由一个通用目标解决,在文件的前面,描述了这个命令,用来把任意的 .c 文件编译成 .o 文件:

.c.o:
            $(CC) -c $(CPPFLAGS) $(CFLAGS) $<

这些看起来非常复杂。为什么不简单地列出编译每个部分的步骤,那样不就行了?一会儿就知道答案了。同时,让我们运行 make 命令并构建我们的程序:

[me@linuxbox diction-1.11]$ make

这个 make 程序将会运行,使用 Makefile 文件的内容来指导它的行为。它会产生很多信息。

当 make 程序运行结束后,现在我们将看到所有的目标文件出现在我们的目录中。

[me@linuxbox diction-1.11]$ ls
config.guess  de.po             en              en_GB           sentence.c
config.h      diction           en_GB.mo        en_GB.po        sentence.h
config.h.in   diction.1         getopt1.c       getopt1.o       sentence.o
config.log    diction.1.in      getopt.c        getopt.h        style
config.status diction.c         getopt_int.h    getopt.o        style.1
config.sub    diction.o         INSTALL         install-sh      style.1.in
configure     diction.pot       Makefile        Makefile.in     style.c
configure.in  diction.spec      misc.c          misc.h          style.o
COPYING       diction.spec.in   misc.o          NEWS            test
de            diction.texi      nl              nl.mo
de.mo         diction.texi.i    nl.po           README

在这些文件之中,我们看到 diction 和 style,我们开始要构建的程序。恭喜一切正常!我们刚才源码编译了我们的第一个程序。但是出于好奇,让我们再运行一次 make 程序:

[me@linuxbox diction-1.11]$ make
make: Nothing to be done for `all'.

它只是产生这样一条奇怪的信息。怎么了?为什么它没有重新构建程序呢?啊,这就是 make 奇妙之处了。make 只是构建需要构建的部分,而不是简单地重新构建所有的内容。由于所有的目标文件都存在,make 确定没有任何事情需要做。我们可以证明这一点,通过删除一个目标文件,然后再次运行 make 程序,看看它做些什么。让我们去掉一个中间目标文件:

[me@linuxbox diction-1.11]$ rm getopt.o
[me@linuxbox diction-1.11]$ make

我们看到 make 重新构建了 getopt.o 文件,并重新链接了 diction 和 style 程序,因为它们依赖于丢失的模块。这种行为也指出了 make 程序的另一个重要特征:它保持目标文件是最新的。make 坚持目标文件要新于它们的依赖文件。这个非常有意义,做为一名程序员,经常会更新一点儿源码,然后使用 make 来构建一个新版本的成品。make 确保基于更新的代码构建了需要构建的内容。如果我们使用 touch 程序,来“更新”其中一个源码文件,我们看到发生了这样的事情:

[me@linuxboxdiction-1.11]$ ls -l diction getopt.c
-rwxr-xr-x 1 me me 37164 2009-03-05 06:14 diction
-rw-r--r-- 1 me me 33125 2007-03-30 17:45 getopt.c
[me@linuxboxdiction-1.11]$ touch getopt.c
[me@linuxboxdiction-1.11]$ ls -l diction getopt.c
-rwxr-xr-x 1 me me 37164 2009-03-05 06:14 diction
-rw-r--r-- 1 me me 33125 2009-03-05 06:23 getopt.c
[me@linuxbox diction-1.11]$ make

运行 make 之后,我们看到目标文件已经更新于它的依赖文件:

[me@linuxbox diction-1.11]$ ls -l diction getopt.c
-rwxr-xr-x 1 me me 37164 2009-03-05 06:24 diction
-rw-r--r-- 1 me me 33125 2009-03-05 06:23 getopt.c

make 程序这种智能地只构建所需要构建的内容的特性,对程序来说,是巨大的福利。虽然在我们的小项目中,节省的时间可能不是非常明显,在庞大的工程中,它具有非常重大的意义。记住,Linux 内核(一个经历着不断修改和改进的程序)包含了几百万行代码。

24.3.2 安装程序

打包良好的源码经常包括一个特别的 make 目标文件,叫做 install。这个目标文件将在系统目录中安装最终的产品,以供使用。通常,这个目录是 /usr/local/bin,为在本地所构建软件的传统安装位置。然而,通常普通用户不能写入该目录,所以我们必须变成超级用户,来执行安装操作:

[me@linuxbox diction-1.11]$ sudo make install

执行了安装后,我们可以检查下程序是否已经可用:

[me@linuxbox diction-1.11]$ which diction
/usr/local/bin/diction
[me@linuxbox diction-1.11]$ man diction

完美!

24.4 总结

在这一章中,我们已经知道了三个简单命令:

./configure
make
make install

可以用来构建许多源码包。我们也知道了在程序维护过程中,make 程序起到了举足轻重的作用。make 程序可以用到任何需要维护一个目标/依赖关系的任务中,不仅仅为了编译源代码。

更新于 2022年10月2日
第23章:打印第25章:编写第一个Shell脚本

发表评论 取消回复

您需要登录后才可以发表评论...
登录... 后才能评论
文章目录
  • 24.1 什么是编译?
    • 24.1.1 所有的程序都是可编译的吗?
  • 24.2 编译一个 C 语言
    • 24.2.1 得到源码
  • 24.3 检查源码树
    • 24.3.1 构建程序
    • 24.3.2 安装程序
  • 24.4 总结

Copyright © 2015-2023 开源之家

  • 首页
  • 每日签到
  • 加入VIP
  • 顶部
AI&大数据 Java Java Linux Linux Python 前端 办公软件 办公软件 培训视频 娱乐休闲 小程序开发 数据库 系统相关 网络 英语 设计创意 软件测试