注册表查看HyperV状态bcdedit /enum | findstr /i hypervisorlaunchtype 如果查询是OFF状态，修改状态到Auto就可以。bcdedit /set hypervisorlaunchtype Auto
[/etc/systemd/system和/lib/systemd/system的区别 ]linux系统中有很多的system目录，在平常使用中或者大量的博客中，常看到的有/etc/systemd/system、/lib/systemd/system以及/usr/lib/systemd/system等，这三者有什么样的关系呢，本文将三者的关系详细说明，后续使用不再混淆。简介目录/lib/systemd/system以及/usr/lib/systemd/system其实指向的是同一目录，在/目录下ll可知：[root@localhost /]# ll total 28 lrwxrwxrwx. 1 root root 7 Jul 3 09:43 bin -> usr/bin dr-xr-xr-x. 5 root root 4096 Jul 19 12:04 boot drwxr-xr-x. 19 root root 3080 Jul 19 04:03 dev drwxr-xr-x. 76 root root 8192 Jul 19 20:07 etc drwxr-xr-x. 4 root root 39 Jul 19 04:37 home lrwxrwxrwx. 1 root root 7 Jul 3 09:43 lib -> usr/lib lrwxrwxrwx. 1 root root 9 Jul 3 09:43 lib64 -> usr/lib64 drwxr-xr-x. 2 root root 6 Apr 11 2018 media drwxr-xr-x. 2 root root 6 Apr 11 2018 mnt drwxr-xr-x. 3 root root 23 Jul 3 20:33 opt dr-xr-xr-x. 118 root root 0 Jul 19 04:03 proc dr-xr-x---. 10 root root 4096 Jul 20 06:31 root drwxr-xr-x. 27 root root 760 Jul 19 16:00 run lrwxrwxrwx. 1 root root 8 Jul 3 09:43 sbin -> usr/sbin drwxr-xr-x. 2 root root 6 Apr 11 2018 srv dr-xr-xr-x. 13 root root 0 Jul 19 04:03 sys drwxrwxrwt. 10 root root 4096 Jul 20 03:37 tmp drwxr-xr-x. 13 root root 155 Jul 3 09:43 usr drwxr-xr-x. 21 root root 4096 Jul 19 13:34 var[/usr]/lib/systemd/system/ 该目录中包含的是软件包安装的单元,也就是说通过yum、dnf、rpm等软件包管理命令管理的systemd单元文件，都放置在该目录下。[/usr]/lib/systemd/system/ The expectation is that `/lib/systemd/system` is a directory that should only contain systemd unit files which were put there by the package manager (YUM/DNF/RPM/APT/etc)./etc/systemd/system/(系统管理员安装的单元, 优先级更高)Files in /etc/systemd/system are manually placed here by the operator of the system for ad-hoc software installations that are not in the form of a package. This would include tarball type software installations or home grown scripts.在一般的使用场景下，每一个 Unit（服务等） 都有一个配置文件，告诉 Systemd 怎么启动这个 Unit 。Systemd 默认从目录/etc/systemd/system/读取配置文件。但是，里面存放的大部分文件都是符号链接，指向目录/usr/lib/systemd/system/，真正的配置文件存放在这个目录。 systemctl enable命令用于在上面两个目录之间，建立符号链接关系。$ sudo systemctl enable clamd@scan.service # 等同于 $ sudo ln -s '/usr/lib/systemd/system/clamd@scan.service' '/etc/systemd/system/multi-user.target.wants/clamd@scan.service'如果配置文件里面设置了开机启动，systemctl enable命令相当于激活开机启动。与之对应的，systemctl disable命令用于在两个目录之间，撤销符号链接关系，相当于撤销开机启动。$ sudo systemctl disable clamd@scan.service虽然在/etc/systemd/system/目录下放置的是系统管理员安装的单元，但是实际使用过程中，用户可以自定义服务配置文件，并且放置在该目录，将该服务的配置文件的优先级提高。优先级systemd的使用大幅提高了系统服务的运行效率, 而unit的文件位置一般主要有三个目录：Table 1. Load path when running in system mode (--system). ┌────────────────────────┬─────────────────────────────┐ │Path │ Description │ ├────────────────────────┼─────────────────────────────┤ │/etc/systemd/system │ Local configuration │ ├────────────────────────┼─────────────────────────────┤ │/run/systemd/system │ Runtime units │ ├────────────────────────┼─────────────────────────────┤ │/lib/systemd/system │ Units of installed packages │ └────────────────────────┴─────────────────────────────┘这三个目录的配置文件优先级依次从高到低，如果同一选项三个地方都配置了，优先级高的会覆盖优先级低的。系统安装时，默认会将unit文件放在/lib/systemd/system目录。如果我们想要修改系统默认的配置，比如nginx.service，一般有两种方法：在/etc/systemd/system目录下创建nginx.service文件，里面写上我们自己的配置。在/etc/systemd/system下面创建nginx.service.d目录，在这个目录里面新建任何以.conf结尾的文件，然后写入我们自己的配置。推荐这种做法。/run/systemd/system这个目录一般是进程在运行时动态创建unit文件的目录，一般很少修改，除非是修改程序运行时的一些参数时，即Session级别的，才在这里做修改。附systemd介绍服务设定位置：/usr/lib/systemd/system//run/systemd/system//etc/systemd/system/（一般为连接文件）服务统一管理:systemdservice设定文件：/usr/lib/systemd/system/*.service: 预设设定文件/etc/systemd/system/system/*.service.d/: 用户个性化设定文件，会被加入设定/etc/systemd/system/system/*.service.wants/: 连结文件，启动该服务后推荐启动的其他服务/etc/systemd/system/system/*.service.requires/: 连结文件，启动该服务之前，需要预先启动的服务/run/systemd/generator.late 使用 systemd-sysv-generator工具处理 SysV init脚本(即：/etc/init.d/*)，自动生成.service文件
近期购入了多网口N5105软路由，选择了ESXi作为主控系统。对于ESXi vmkernel不支持的网卡，需要手动封装网卡驱动到ESXi镜像，再安装ESXi。1.准备环境以ESXi7.0U3d为例，封装intel的i225驱动需要两个文件：vmware官方提供的社区版网卡驱动，下载链接ESXi的Offline Bundle版本，下载链接 （需注册账号并登陆）2.powershell安装必要组件准备一台win10以上的系统，管理员身份打开powershell。键入以下命令安装VMware命令行模块：Install-Module -Name VMware.PowerCLI预期之内会提示信任库之类的问题，键入Y即可。⚠注意：！！！不要中断，这一步非常慢，10-20分钟不等，代理或科学上网可稍微提升下速度。键入一下命令信任模块：set-ExecutionPolicy RemoteSigned同理，输入Y即可。3.开始封装驱动将第一步下载好的ESXi镜像和网卡驱动放到同一个文件夹。打开powershell，以此键入以下命令(路径和文件名需替换下)：$esxiOfflineBundle = "C:\esxi\VMware-ESXi-7.0U3d-19482537-depot.zip" #指定Office Bundle版本的Esxi路径 $intelNicOfflineBundle = "C:\esxi\Net-Community-Driver_1.2.7.0-1vmw.700.1.0.15843807_19480755.zip" #指定网卡驱动路径 $esxiImageProfileName = "ESXi-7.0U3d-19482537-standard" $newImageProfileName = "ESXi-7.0U3d-19482537-Intel-i225" #配置文件名随意，最好和最后一部输出的ISO文件名保持一致 Add-EsxSoftwareDepot $esxiOfflineBundle Add-EsxSoftwareDepot $intelNicOfflineBundle New-EsxImageProfile -CloneProfile $esxiImageProfileName -Name $newImageProfileName -Vendor DylanC Add-EsxSoftwarePackage -ImageProfile $newImageProfileName -SoftwarePackage "net-community" Export-EsxImageProfile -ImageProfile $newImageProfileName -ExportToIso -FilePath "C:\esxi\ESXi-7.0U3d-19482537-Intel-i225.ISO" #输入文件的路径即名称确保以上每个命令都不会报错，黄色字体的警告可忽略，红色字体则表示报错，有报错则解决报错。成功之后，对应文件夹会生成封装好的ESXi iso镜像：同时，自测powershell6.x以上版本，会报各种各样的错误，致命错误为VMware.ImageBuilder module不支持当前powershell版本，可更换成5.x版本使用，powershell历史版本下载，到此下载。
Linux入门教程本文的首要目的是给予Linux初学者一个简单、易学的教程，以便在看完本文后对Linux系统有一个基础的认识（而非系统级的深入），可以对常见的软件和功能进行配置，甚至可以自己写一写一键脚本。本教程写于2021年下半年，采用的系统为Debian GNU/Linux 11 (bullseye)。0 前言吐槽CentOS解释使用Debian而不是CentOS的原因国内首批接触Linux系统的人主要集中在科研院校，大多数是延续了Unix-like的背景，在千禧年前后才有了真正意义上的Linux使用者：纯Linux平台开发、运行服务和应用，他们或直接或间接地推广了Linux系统。红帽（Red Hat, Inc.）在1994年就开始发布了同名的操作系统：Red Hat Linux（后改组为Red Hat Enterprise Linux，缩写为RHEL）。得益于红帽优秀的团队和商业支持，RHEL这一发行版迅速占领了国内市场。彼时的国内计算机市场远不如今日繁荣，在口口相传和红帽的推广中，RHEL成为了Linux入门的主流选项，即使后来号称用户友好的Ubuntu出现了，绝大多数尝鲜的人依然能看到众多网站里面只提供RHEL版本的教程。CentOS是根据RHEL的源码重新编译的，等于换商标版本的RHEL，软件层面上，两者无本质区别。但CentOS是反人类的，至少是反入门用户的。使用RHEL的基本为商业用户，可以付费获得红帽的技术支持，或者干脆有一个自己的维护团队；而CentOS作为一个社区自发形成的操作系统，拥有落后的软件源/包，繁琐的配置，和对个人用户而言根本没有必要的SElinux等。举个例子，很多入门者修改SSH端口的时候，发现所有的操作都没有问题，但是死活无法生效，最终发现是没有在SElinux里面放行。如果你想安装个软件，你就得考虑是从落后主流版本好几代的软件源/包里面安装，还是自己下载源码进行编译以获取主流的使用体验。对于入门者而言，CentOS的安全性和稳定性是个虚假的概念，毕竟让一个刚接触Linux的人去自己编译源码安装，无异于让小学生上战场，输了就说是小学生战斗力太弱。所以本文以Debian GNU/Linux（后续简称为Debian）来演示，也有着推广Debian的意思在里面，毕竟相比于Ubuntu往系统里面塞包括snap在内的一系列私货而言，Debain始终遵循着一个纯净的Linux的要求。而其他一些发行版，要么是专用性太强（如SUSE），要么是入门者不友好（如 Arch Linux），权衡之后，选择了写本文时，最新的Debian系统，即Debian GNU/Linux 11 (bullseye)。1 环境搭建1.1 系统选择与安装Debian的安装包有一系列的前缀或者后缀，例如在默认的下载地址https://www.debian.org/download中的是debian-11.0.0-amd64-netinst.iso。其中，11代表大版本是11，代号是bullseye，各版本代号都来源于电影《玩具总动员》中的角色名称；amd64是指系统为64位的，i386或者x86是32位的，amd64或者x86-64是64位的，32位系统已经被逐步弃用，目前仅在特定行业中使用；netinst是网络安装版本，只是个安装器，安装过程需要联网，而DVD后缀的是完整版（如：debian-11.0.0-amd64-DVD-1.iso），如果系统太大，会在DVD后面加数字，默认DVD-1是完整版本，其后数字的是软件源/包；带firmware前缀的是包含第三方非开源驱动的（如：firmware-11.1.0-amd64-DVD-1.iso），其中就包含intel和Realtek等公司的闭源网卡驱动。VPS全称为virtual private server（虚拟专用服务器），如果需要安装纯净版的Debian 11系统，推荐使用vicer的Linux一键重装脚本（如下）：bash <(wget --no-check-certificate -qO- 'https://raw.githubusercontent.com/MoeClub/Note/master/InstallNET.sh') -d 11 -v 64 -p "自定义root密码" -port "自定义ssh端口"1.2 常用的命令cat 用于查看文本文件的内容，如cat /etc/os-release 将显示系统信息，如下：PRETTY_NAME="Debian GNU/Linux 11 (bullseye)" NAME="Debian GNU/Linux" VERSION_ID="11" VERSION="11 (bullseye)" VERSION_CODENAME=bullseye ID=debian HOME_URL="https://www.debian.org/" SUPPORT_URL="https://www.debian.org/support" BUG_REPORT_URL="https://bugs.debian.org/"touch 新建文本文件，如touch /home/hello.py 将在home 文件夹下新建一个Python文件。ls 列出所有文件，但默认只是显示出最基础的文件和文件夹，如果需要更详细的信息，则使用ls -la，这将列出包括隐藏文件在内的所有文件和文件夹，并且给出对应的权限、大小和日期等信息。cd 进入指定文件夹，如cd /home 将进入home目录。返回上层目录的命令是cd ..，返回刚才操作的目录的命令是cd -。mkdir 新建文件夹，如mkdir /home/Python 将在home 文件夹下新建一个Python 文件夹。mv 移动文件和文件夹，也可以用来修改名称，如mv /home/hello.py /home/helloworld.py 将上文的hello.py重命名为helloworld.py，mv /home/helloworld.py /home/Python/helloworld.py 将helloworld.py 由home文件夹移动到了次级的Python文件夹。cp 复制文件，cp /home/Python/hellowrold.py /home/Python/HelloWorld.py 将helloworld.py复制为HelloWolrd.py。注意：Linux系统严格区分大小写，helloworld.py和HelloWolrd.py是两个文件。如果想复制整个文件夹，则需要带r，即cp -r，但此命令无法复制隐藏文件夹，需要使用cp -r pathA/. pathB 注意这个点.是灵魂。rm 删除，即江湖传说中rm -rf ，r为递归，可以删除文件夹中的文件，f为强制删除。rm /home/Python/helloworld.py 可以删除刚才的helloworld.py 文件，而想删除包括Python 在内的所有文件，则是rm -rf /home/Python 。du -lh 查看当前文件夹下，各文件、文件夹的大小，l是硬链接（软连接类似于快捷方式），h是让文件自动使用K/M/G显示而不是只有K。1.3 基础文本编辑器nano、vimLinux系统的一大优势（同时也是劣势）是默认不需要GUI，因此节省了大量的性能开支，无GUI版本的Debian 11可以在512M甚至更小内存的VPS上正常启动和运行。但缺少GUI加大了入门者修改文件的难度，所幸Debian 11自带了简便易用的nano文本编辑器。以下以修改系统的更新源为例nano /etc/apt/sources.list #打开sources.list文件，在Linux系统中，#是注释符，其后的内容会被忽略如图所示，即为nano打开sources.list后的界面，最下面两行为提示，比如Ctrl+E为退出，如果文档被改动了，则会出现下图，询问是否保存。如果没有被更改，则会直接退出。Y则保存，N则不保存，Ctrl+C取消操作。此处输入Y，则会如下图：此时按下Enter键就会保存了。这里多提一句关于Debian 11的更新源内容，一般是以下6行。deb http://deb.debian.org/debian bullseye main contrib non-free deb-src http://deb.debian.org/debian bullseye main contrib non-free deb http://deb.debian.org/debian-security/ bullseye-security main contrib non-free deb-src http://deb.debian.org/debian-security/ bullseye-security main contrib non-free deb http://deb.debian.org/debian bullseye-updates main contrib non-free deb-src http://deb.debian.org/debian bullseye-updates main contrib non-freedeb表示为已经编译好的安装包，类似于Windows上的MSI安装包，deb-src是源文件，万一没有打包好，提供自己本地编译安装的机会。总共分三大行，第一行是系统主文件，第二行是安全性更新，第三个是一些更新补充，推荐三个都写上。在每行的末尾都有main contrib non-free字样，其中main是官方给的包/源，严格遵守相关开源协议；contrib是包/源本身遵守相关开源协议，但是它们的依赖则不是；non-free是私有的软件，比如上文提到的Realtek的WiFi驱动等。除此之外，其实还有个Backports作为第四大行，是将比较陈旧的软件移植过来的，很少会用到，一般默认不写上。nano虽然好，但是功能简单，只适合一些简单的文本文件编辑功能，而发展自vi的vim则被成为编辑器之神（Emacs被称为神之编辑器，Linux之父Linus Torvalds就在用）。系统会自带vi但是不带vim，正好我们可以使用上述修改过的更新源来安装vim作为示例。apt update # 更新一下源 apt install vim -y #安装vim这个软件 -y是确认安装使用vim /etc/apt/sources.list打开更新源文件，如下图所示：vim功能众多，使用复杂，得慢慢说。左下角是此文件的路径和名称，右下角是光标此时的行数和列数。此时是无法直接输入，要先按下insert或者i键变成插入模式才行。此时，左下角如下图，变成了INSERT/插入模式。然后就是该怎么写就怎么写，一些快捷键去百度谷歌必应吧，说的肯定比我详细。但是必须提到如何保存文件：insert模式下按esc键（一般是键盘最左上角，99%的人可能都不怎么用的一个键），INSERT会消失不见，如下图：这个时候再按下:键，界面上也会出现一个冒号，如下图。注意，这个冒号是半角的，全角冒号是没用的。这个时候，按下wq这两个键，即可保存内容。w是write/写入的意思，q是quit/退出的意思。如果你不想保存，则只输入q键即可，但是有时候因为文件已经被修改了，vim不让退出，这时候输入q!就可以了，感叹号是强制执行的意思，执行后文件不会被修改并且会退出vim。1.4 更新系统至此，不管是使用nano还是vim都可以对更新源进行编辑了，让我们来具体了解一下如果更新系统和相关指令。apt update apt list --upgradable apt upgrade -y以上三行，分别是和更新源同步，显示出哪些软件可以更新，以及进行更新。如上文中，安装了vim，若想卸载vim，则有以下两个命令，任意一个即可，但之间存在差别。apt remove vim -y apt purge vim -y第一个会址卸载vim软件本身，配置文件仍然会本留下；第二种连带着配置文件和相关依赖一起卸载了，所以存在一定风险。除此之外，apt autoremove是对整个系统进行整理，将不需要的依赖卸载了，不针对于特定软件。2 SSH连接和基础配置一般VPS供应商都会提供SSH的链接方式，包括用户名，密码和端口号，一些注重安全性的会修改端口号甚至只有采用密钥才能登陆VPS。这里使用纯净版的系统和默认配置进行演示。2.1 连接SSH的软件和相关操作SSH软件有开源的和不开源的，有付费的和免费的，整理了一个常见SSH客户端（Windows平台）的对比表格和相关信息。其实在2021年，macos、Linux和windows 10都自带SSH功能，这里先不讨论。个人目前主用mobaxterm，偶尔使用xshell。名称免费与否下载地址Xshell家庭/学校免费https://www.netsarang.com/zh/free-for-home-school/MobaXterm家庭版免费https://mobaxterm.mobatek.net/download.htmlFinalShell基础功能免费https://www.hostbuf.com/t/988.htmlelecterm免费+开源https://github.com/electerm/electerm/releasesPuTTY免费+开源https://www.chiark.greenend.org.uk/~sgtatham/putty/latest.htmlXshell：传播广泛，自带中文，个人使用完全免费，但是会话窗口限制最多只能打开四个SSH连接，再多之后就会自动新建会话窗口了，传输文件需要配合Xftp才行。目前国区被臭名昭著的思杰马克丁代理了，如需使用，请前往官网下载，在输入邮件和姓名后，会收到一封邮件，邮件里面给出下载连接。MobaXterm：只有英文版本，偶尔会反应慢半拍，除此之外没缺点。功能极其强大，传输文件、性能监控、串口通信、X11支持、IP检测、宏、WSL、远程桌面等，能想到的功能都有，而且个人使用免费。FinalShell：国人开发，所以本地化很好，全中文，日常需要的功能也都有。有一些进阶功能需要付费，也可以云端保存SSH账号，虽然也是付费功能。缺点的话，和MobaXterm一样，JAVA写的东西，总是让人觉得慢半拍。electerm：日常所需功能都有，完全开源和免费，还可以通过GitHub实现免费的云端保存SSH账号功能，适合自己折腾和魔改。基于electron开发的，从而实现了跨平台，Windows、Mac和Linux都有客户端。不过缺点也显而易见，electron本质上是个浏览器，占内存和硬盘空间。PuTTY：由Simon Tatham开发和维护的，老牌中的老牌，但是缺少人性化设置，不推荐。2.2 SSH配置文件介绍和修改SSH的配置文件在/etc/ssh/sshd_config中，是一个纯文本文件，可以使用nano或者vim打开和编辑。打开文件后，在前几行就能看到#Port 22字样，这个代表使用了默认的22端口作为SSH连接使用。因为大家都在使用22端口，所以会有一些扫描机器使用弱密码不断尝试登录，使用lastb命令可以查看登录失败的记录，如下图。233333是尝试登录的账号，144.214.xxx.xxx是发起者的IP，最后面是尝试登录的时间。因此，我们可以改成高端口，比如35261这种没有特殊含义/排列的随机数，以减小被攻击的可能。要注意端口只能在0-65535之间，并且很多低位数的端口，已经被共识的程序占领了，比如80端口是http的，443端口是https的，就如22是SSH的一样。此处，我们修改/etc/ssh/sshd_config中的端口数后，还需要重启SSH服务才行，否则只会在系统下次重启后才启用新的端口。systemctl restart ssh #重启SSH服务systemctl是systemd的命令，用于启动和监控系统服务的，在系统内核启动后，systemd就会开始服务，restart即重启的意思。关于systemd的相关内容，后文会详细说明。除此之外，把密码改的复杂一些，也可以有效的降低系统被黑的风险，使用passwd root命令，即可修改root账号的密码，会提示New password:，此时输入新密码，注意这里是看不见任何输入反馈的，随后在显示Retype new password:后再次输入一遍，如果两次密码相同，就会更新root密码了。2.3 使用密钥登陆SSH即使更改了端口，但因为使用密码即可登录，考虑到不是所有人都会使用强密码，所以SSH提供了使用密钥登录的功能，可以简单理解成是一长串复杂的并且可以相互验证的密码。以root用户为例，演示如何将SSH由密码登录改成密钥登录。输入ssh-keygen -t rsa ，随后一路enter键，如下图在显示完成后，在/root/.ssh/文件夹下，你将看到id_rsa和id_rsa.pub两个文件，id_rsa是私钥，下载下来并妥善保存，id_rsa.pub是公钥，放在服务器上的。将id_rsa.pub写入到SSH的密钥文件中：touch authorized_keys cat id_rsa.pub >> authorized_keys除此之外，还需要给文件和相关文件夹合适的权限：chmod 600 authorized_keys chmod 700 ~/.ssh这里有个~，它代表的是当前用户，比如现在是root用户，那~就是root，所以chmod 700 ~/.ssh等于chmod 700 /root/.ssh现在密钥已经配对好了，还需要修改SSH的配置文件，打开/etc/ssh/sshd_config文件，查找并修改如下：PubkeyAuthentication yes # yes表示允许密钥登陆 AuthorizedKeysFile .ssh/authorized_keys .ssh/authorized_keys2 # 指定密钥的文件位置，这里是去掉了开头的# PasswordAuthentication no # 不允许使用密码登陆，等测试密钥登陆成功了再修改此条，以防无法登陆使用systemctl restart ssh重启SSH服务，此刻，你将只能使用密钥才能登录，一旦私钥遗失了，就再也进不去了。3 Linux文件系统3.1 文件系统格式与Windows分割硬盘（甚至一个硬盘被划分成了好几个）不同，Linux的是将所有硬盘都挂载在了一起。简单来说，Windows分C盘D盘等，还针对软盘额外给予了A盘和B盘，Linux把所有的硬盘都放在了/下，即根目录，这也是Linux中root账户的权限最大的原因，root即为根，如同树根一样，所有的内容都要基于根才有了可能。文件系统是另外一个极其复杂的内容，这里只提到Windows使用的是NTFS，而Linux普遍采用EXT4格式，这两种文件系统互不兼容，装在Linux系统上的硬盘，在Windows上是无法直接读写的，必须使用额外的软件才能访问。反过来，在Linux上读取Windows下的硬盘中的内容，需要安装ntfs-3g才行。这两种文件系统各有优缺点，一般人用就行了，不要问，问就是用默认。实际上，目前在广泛使用的文件系统种类繁多，所有需要在它们之间交换文件的时候，会使用exFAT格式的U盘/硬盘（exFAT是FAT的替代品，因为FAT下单个文件最大不能超过4G）。3.2 文件树、文件夹功能和权限在/目录下，使用ls -la会显示出所有的文件和文件夹（如下图所示），a是列出所有文件，l是显示详细信息。第一列是文件/文件夹的权限，一共有10个字符，第一位是文件类型，比如d代表文件夹，l代表链接。之后，三个为一组，总共3组。r是读，w是写，x是执行，也可以通过数字来区分，r是4，w是2，x是1，所以有了常见的一把梭chmod +777。第二列是硬链接数量，即这个文件/文件夹下有多少真实放着的文件。第三列和第四列是这个件分别属于谁，以及这个人是哪个组的。这里的组概念来源于最开始的unix是个多用户系统，所有会把用户分类，比如某软件用户放一个组，系统维护人员放一个组等。第六列是文件/文件夹大小，默认单位是K。第七八九列是修改的日期。最后一列是文件/文件夹的名字。我们会发现有一些->的字样，这是指软链接。软连接类似于Windows上的快捷方式，而硬连接类似于复制了一份（但并不会真的占用空间）。bin或者usr/bin：应用程序，比如Python的主程序就在这里boot：系统启动文件dev：外部硬件设备，Linux下一切皆文件，所以外部硬件设备也是以文件形式出现etc：系统的配置文件，比如上述提到的SSH的配置文件就在这里home：用户目录，类似于Windows上的桌面initrd.img：启动文件，可以看到它被软连接到了boot目录中lib：库文件，类似于Windows的dll，程序的依赖都在这里lost+found：丢失寻找文件，系统被强迫关机后，会在这里记录下来media：媒体文件，如果系统发现了光盘之类的，会自动挂载到这里mnt：临时挂载目录，上述的光盘，还有U盘硬盘，如果手动挂载，都会选择这里opt：系统额外软件的安装位置，极少使用，比如甲骨文的数据库会放一些东西在这里proc：系统进程/内核会把一些信息放到这里，本质上是反应系统状态而不是文件root：root用户的“桌面”，普通用户在home中run：系统启动后存放临时文件sbin：root用户的"bin"srv：放服务运行而需要的文件sys：文件系统，里面包括进程信息，设备信息和终端信息tmp：临时文件usr：共享资源，类似于Windows安装软件的默认目录var：不断变化的文件会放在这里，比如日志vmlinuz：启动文件，可以看到它被软连接到了boot目录中如果我们自己写了一个程序，还放在系统里面运行，那一般是在/usr/local/中新建目录，这遵循着Linux系统的默认规则。3.3 示例：挂载U盘如果是Ubuntu桌面的话，会自动挂载U盘，但是无GUI版本的Linux大概率不会，所以会需要手动挂载，又或者加了一块新的硬盘，需要我们自己挂载。fdisk -l mkdir /mnt/usb mount /dev/sda1 /mnt/usb umount /mnt/usbfdisk -l是显示出所有的储存，会显示出来类似于/dev/sda1等，mkdir /mnt/usb在mnt目录里面新建一个文件夹，即挂载点，假设sda1就是我们插入的U盘，mount /dev/sda1 /mnt/usb将这块U盘挂载到了/mnt/usb中，这时候我们就能在/mnt/usb中看到U盘里的文件。如果不再需要了，要手动移除这个U盘，使用umount /mnt/usb命令。4 Shell/Dash入门让人头大，Shell本身就能写一本书了，少说得有300页！这里面夹杂着从Unix开始的一大堆事情，shell的发展，bash和dash的区别与联系，本身的命令，调用系统的命令，交互方式。累了，姑且先把它当成一堆命令拼凑起来的脚本吧。还是写个例子，简单介绍一下实际内容，等以后有时间了再继续补充。比如我们想写一个查看CPU和内存使用率的脚本：#!/bin/bash echo "which useage do you want to konw?" echo "1 for CPU, 2 for RAM" read choice if [ $choice -eq 1 ] then echo "CPU usage" grep 'cpu ' /proc/stat | awk '{usage=($2+$4)*100/($2+$4+$5)} END {print usage "%"}' elif [ $choice -eq 2 ] then echo "RAM usage" free -m | grep Mem | awk '{print ($3/$2)*100 "%"}' else echo "WRONG INPUT" fi细说每一行内容#!/bin/bash是指定此文件由/bin下面的bash这个程序来执行。在Debian 11里面，bash其实是dash，别问dash是什么，就写bash，天王老子来了也写bash。Bash全称是GNU Bourne-Again Shell，bash被从NetBSD（一个Unix的分支）上移植到Debian上，所以叫dash (Debian Almquist Shell)。echo "which useage do you want to konw?"是输出冒号内的文字echo "1 for CPU, 2 for RAM" read choice把输入内容赋值给choice这个变量，即数字1或者2。rcho -p "1 for CPU, 2 for RAM" choice也可以实现相同功能。if [ ... ] then ... ... elif [ ... ] then ... ... else ... fi这是一个if...elif...else的判断语句，先经过两次判断，如果都不能成功，那就执行最后一行。$choice -eq 1把刚才的choice这个输入变量和数字1对比，注意，要有$才代表变量，不然就默认是文字，-eq是等于的意思。判断是否等于1，是的话就给出CPU使用量，如果不等于1，那就继续判断是否等于2，是的话就给出RAM使用量，如果不等于2，那就输出错误提醒，然后结束。grep是抓取有关键词的那一行，$2是这一行的第几个内容，如下：grep Mem抓取到了第二行，即真实内存这一行，$2是内存总量，$3是已经使用了的内存，因此($3/$2)*100就是已经使用了百分之多少的内存，5 Crontab定时任务Crontab用于定时任务，比如设定周五晚上运行脚本备份网站，又或者每分钟检查一下CPU使用率等。但除此之外，crontab还有个@reboot功能，即可以在系统启动的时候自动运行指定程序。推荐crontab -e，其中的-e是指当前用户，不建议直接使用crontab。首次运行crontab -e的时候，会让选择使用何种编辑工具，这个随便，nano和vim basic都行，什么顺手和习惯就用什么。如上图，将每隔15分钟，就会使用位于usr/bin中的python3运行位于/usr/local/weather中的weather.py程序。前五个星号其实是设置的时间，推荐去 https://crontab.guru/ 这里直接设置时间（如下图）。第一个星号是分钟，第二个星号是小时，第三个星号是天，第四个星号是月份，第五个星号是每周的第几天。6 系统权限6.1 root和user，以及sudo上述已经简单的减少了root来源，由于root的权限太高，以至于在实际使用中发现并不安全，而且作为一个初始目的是多用户多终端的操作系统，Linux主要操作都不需要发生在root用户上的。所以这里就有了user这个角色，如果用户多了起来，为了便于管理，也会把某些用户分组，就有了group的概念。以下演示使用root用户新建一个user用户并进入此用户：如图所示，adduser mjj为新建一个叫做mjj的用户，由于此前并没有除了root之外的用户，所以会使用这个名字作为group/组的名字，并且在/home文件夹里面生成一个mjj文件夹，即mjj的”桌面“。所以输入两次密码，之后会问一堆问题，都是例行的，一路enter就好，最后会问一下信息对不对，输入y就完成添加新用户了。但此时，mjj这个用户的权限是很小的，四舍五入等于没有，连某些文件夹都不能进去更别说执行软件了。使用su mjj切换到mjj用户中，可以在终端中看到已经从root@rn变成了mjj@rn，rn是这台服务器的名字，即为某某在rn这台服务器上。查看以下root文件夹下有些什么东西，结果发现权限不够而被拒绝访问/Permission denied。所以我们要给一个能够临时使用root权限的能力，这被称为sudo。su root #切换回root账号 apt install sudo -y #有些时候，纯净安装的Debian系统是没有sudo的，所以要安装一下 usermod -aG sudo mjj ##给予mjj用户sudo权限此时，我们再切换到mjj用户上，在刚才的命令前加上sudo，临时获取root权限，就可以查看了：在用户首次使用root权限的时候，系统会提示三个准则，也请谨记：尊重他人隐私；输入之前请三思；能力越大，责任越大。6.2 chmod和chownchmod的全称是change mode，是针对于文件夹或者文件，改变它们的权限，这样就可以让某些用户正常使用了。这里不深入探讨chmod的使用详解，仅演示一些常见的内容。chmod +x helloworld.py 这里的x在上面说过，是执行的意思，即赋予此程序被执行的权限，多见于一键脚本里面，让脚本能够正常运行。+是新增权限，如果是-则是去除对应的权限。chmod -R 755 folder/ -R如上述的rm -rf中的r一样，是递归，即从这里开始，下面不论多少层文件夹，都执行这个命令。755是换算下来，则是root用户可以读写执行（1+2+4=7），用户和用户组只能读和执行（1+4=5），不能对文件进行更改。某些程序会对文件的权限有着极其严重的控制，比如上说的SSH密钥，分别给authorized_keys600的权限和.ssh文件夹700的权限，意味着只能被所有者/owner读写，在例子中即为只能被root账户读写。这种设计让没有相应权限的人无法修改密钥登陆的方式，换而言之，隔绝了用户之间的操作，从而增强安全性。chown的全称是change owner，是用于设置文件所有权的。由于归属者的概念并没有文件这个概念常见，所有chown比较少见到，大多数人接触到的时候，大概是建网站的时候用chown -R www-data:www-data-group /var/www/html来确定文件关联。这句的意思是，将/var/www/html这个文件夹及里面的所有文件都归给www-data-group用户组的www-data用户。这样做的目的是实现权限分离，文件分离，从而让服务器可以更方便的被维护，以及明确使用途径。不过考虑到mjj大部分都是使用VPS的，可能很难遇到需要chown的情况吧。不要chmod +777！不要chmod +777！不要chmod +777！人才是服务器安全的最大漏洞！7 Systemd入门和配置7.1 开机自启和进程守护Systemd是由Redhat家的Lennart Poettering开发的，其人以创造性和不靠谱闻名，Systemd在最开始的时候，和init相比没有明显优势，经过多次迭代才有了今天的稳定性和适用性，现在就让老旧的init进入历史垃圾桶吧。事实上，在Linux系统启动的时候，一旦kernel运行了，Systemd就会跟随启动，之后由Systemd唤醒并维护各个程序的正常运行，比如网卡，显示器，SSH服务等。你会在/etc/systemd/system/文件夹中发现一个叫做sshd.service的文件，并且还是enable模式的，这意味着SSH是开机自启的，并且系统会一直监控这这个程序，如果程序崩溃，系统会尝试自动重启它以确保能够正常运行。以著名的内网穿透frp的服务器端的Systemd文件为例（下节将详细介绍如何搭建frp），将frps.service放到/etc/systemd/system/文件夹中，使用以下命令systemctl enable frps.service systemctl start frps.service systemctl status frps.service systemctl restart frps.servicesystemctl是systemd在系统中的程序名字，enable是指让这个程序能够开机自启，start为让程序现就运行，status是查看这个程序现在的状态，restart是重启程序。当然，我们也可以自己写systemd的service文件，这里以 https://github.com/cnsilvan/UnblockNeteaseMusic 解锁网易云音乐的程序做参考[Unit] Description=UnblockNeteaseMusic After=network.target Wants=network.target [Service] Type=simple WorkingDirectory=/usr/local/UnblockNeteaseMusic ExecStart=/usr/bin/node app.js -e http://music.163.com -s -p 8888 RestartPreventExitStatus=23 Restart=always [Install] WantedBy=multi-user.target一共分为三组，分别为Unit，Service和Install。Unit是这个服务的名称，示例中为UnblockNeteaseMusic而After和Wants指明的network.target意味希望这个程序在网络服务启动后再启动，毕竟是个网络功能，不能还没有网就启动了。Service是核心部分，Type指定了类型,Simple是默认的类型，发现有网了就启动。此外，常见的还有fork和idle，前者意味着程序依赖于另外一个程序的运行，通常还会配置PIDFile，后者是等系统空闲了再启动，属于一点都不急的。WorkingDirectory是工作目录，ExecStart是执行的命令，实例中，是用位于/usr/bin/的nodejs执行位于工作目录的app.js这个文件，并且还带了参数http://music.163.com -s -p 8888。RestartPreventExitStatus是指如果报错信息为23则不会再重启了，具体报错信息是运行的程序决定的。Restart=always指只要不是23的报错信息，那就一旦服务停了，Systemd就会去重启。最后一部分，Install中的WantedBy=multi-user.target指网络服务已经正常启动，也可以让用户登录了，但是并没有开启GUI服务，这个部分不用去探究。7.2 Timer代替Crontab我写了一个自动登录百度贴吧并签到的shell脚本，想每天都运行一次帮我拿积分，但是又不想用crontab实现定时任务，那么Systemd也是有类似的功能的，名字叫做Timer，即定时器。这个功能需要两个文件，比较繁琐。需要再/etc/systemd/system/中写两份配置文件，tieba.service和tieba.timer，前缀必须一样，后缀不同。前者很简单，就是个脚本（如下），名字和程序的路径：[Unit] Description=Tieba Sign [Service] ExecStart=/home/tieba.sh后者tieba.timer需要详细解释：[Unit] Description=Tieba Sign Timer [Timer] OnCalendar=*-*-* 12:00:00 [Install] WantedBy=timers.targetTimer的名称需要是service名字后面加一个Timer，用以提高准确性。OnCalendar类似于corntab的* * * * *，实例中的意味每天中午12点的时候执行以下tieba.service中的位于/home文件夹的tieba.sh这个程序。此处的WantedBy是timers.target，指明是个定时器。8 手动配置系统：以frp为例frp是个内网穿透软件，可以将局域网设备通过frp服务端映射出来，实现公网服务，常见的有SSH、http/https服务等。这里以将内网设备的SSH映射到有公网IP的服务器上为例，从而不在家也能服务家里面的服务器了。在这里下载最新版的安装包 https://github.com/fatedier/frp/releases如图所示，0.38.0是版本号；后面的是系统，darwin是MacOS，freebsd是UNIX的一个分支，这里我们选择linux；紧跟着的是CPU架构，由于本次服务器的客户端是装了64位系统的树莓派4B（arm架构的CPU），所以选择frp_0.38.0_linux_arm64.tar.gz，而服务端是普通的VPS，所以选择frp_0.38.0_linux_amd64.tar.gz。服务端配置注意：版本号和CPU架构须按照实际情况决定。wget https://github.com/fatedier/frp/releases/download/v0.38.0/frp_0.38.0_linux_amd64.tar.gz # 使用wget下载软件包 tar -zxvf frp_0.38.0_linux_amd64.tar.gz # 解压下载的软件包 cd frp_0.38.0_linux_amd64/ # 进入解压后的文件夹 mkdir /etc/frp/ # 新建一个frp的文件夹 mv frps.ini /etc/frp/frps.ini # 把服务器端的配置文件放到刚才新建的文件夹 mv frps /bin/ # 把服务器端软件放到/bin中 mv systemd/frps.service /etc/systemd/system/frps.service # 放置Systemd文件 systemctl enable frps.service # 设置开机自启 systemctl start frps.service # 立即运行客户端配置wget https://github.com/fatedier/frp/releases/download/v0.38.0/frp_0.38.0_linux_arm.tar.gz tar -zxvf frp_0.38.0_linux_arm.tar.gz cd frp_0.38.0_linux_arm/ mkdir /etc/frp/ mv frpc.ini /etc/frp/frpc.ini mv frpc /bin/ mv systemd/frpc.service /etc/systemd/system/frpc.service上述与服务器配置类似，就不重复了，但需要额外修改服务端的配置文件，让它知道该和谁连接，打开/etc/frp/frpc.ini配置文件[common] server_addr = 服务器ip server_port = 7000 [raspi] type = tcp local_ip = 127.0.0.1 local_port = 本地服务器的SSH端口 remote_port = 远程端口其中，需要填写服务器端的IP，7000端口是握手和保活用的，默认就好了。[raspi]是客户端的名字，不可以重复，local_port是客户端的SSH端口，remote_port是远程的端口，此处假设是6000。systemctl enable frpc.service systemctl start frpc.service设置开机自启并立即运行，此时在SSH软件上，通过 服务器IP:6000 就可以连接到这台内网的树莓派了。9 网站环境搭建网站搭建，说简单也简单，安装一个nginx放个html页面就算是了，但也可以做的极其复杂以至于需要一个团队，比如淘宝。这里提供了两个搭建网站的方法：面板和手动搭建。对于小白用户，还是推荐用用面板吧，不然出问题，网站被黑都不知道如何解决。9.1 宝塔解人忧宝塔面板是个伪开源的一键式建站面板，国内版可以在 https://www.bt.cn/ 中找到安装方式，目前的安装命令是wget -O install.sh http://download.bt.cn/install/install-ubuntu_6.0.sh && bash install.sh 。需要注意的是，国内版需要登陆并且验证手机号后才能操作，宝塔也有强制后台升级的前科。除此之外，还有国际版的叫做aapanel，安装地址为 https://www.aapanel.com/install.html ，安装命令是wget -O install.sh http://www.aapanel.com/script/install_6.0_en.sh && bash install.sh。相对而言，国际版的隐私保护会更好一些，不会要求手机号等信息，但是默认语言是英文，如果会哪怕一点点英文，都推荐使用国际版的。宝塔有一点不好的地方是动辄编译（原先是在CentOS上开发的，所以有这个臭毛病），面板是python3写的，安装起来很快，但是要安装一些服务的话，如果VPS性能不好，则需要花费相当长一段时间来编译安装，普遍30分钟起步。9.2 手动搭建宝塔面板是将网站搭建可视化了，本质上和手动搭建没有区别。这里主要是介绍常见的相关软件和Let's Encrypt配置SSL证书的方法。9.2.1 Apache和NginxApache和Nginx都是Web服务器。前者是老牌Web服务器软件，对PHP有着优秀的支持，并且动态响应优秀，但是对性能和内存要求高。后者是俄罗斯出品，对静态网站支持良好，性能消耗也更小，反代和简单的网站都倾向于使用Nginx，甚至还有一系列基于Nginx衍生出来的版本，比如Tengine就是淘宝从Nginx衍生出来的，用以支撑淘宝的各种服务。除此之外，还有个Caddy也用的比较多，这是由golang语言写出来的，所以对多线程高并发的支持很好，并且自带SSL证书申请的功能。入门用户首选Nginx，毕竟网站没有什么服务，对VPS的性能消耗也少点。当然，选择Apache也完全可以，入门用户其实很难用到需要对比选择Apache和Nginx的时候。Caddy的话，先不推荐入门用户了。安装Apache使用以下命令apt install apache2安装Nginx使用以下命令apt install nginx这两个软件安装完后，都会开机自启和立刻运行，浏览器中输入http://ip就可以看到默认的网页，比如Nginx的是这样：9.2.2 PHP安装了Nginx之后，可以实现静态网页，但是常见的网站平台，比如Wordpress和typecho都是PHP写的，所以还需要安装PHP才能运行。apt install php-fpm安装完php还不算完事，还得让Nginx知道，也就是需要更改Nginx的配置文件。进入目录/etc/nginx/sites-available/中，将默认的文件default重命名为网站的域名，比如mjj.hostloc.com，即mv default mjj.hostloc.com，打开mjj.hostloc.com，在下述的第二行末尾加入index.php# Add index.php to the list if you are using PHP index index.html index.htm index.nginx-debian.html index.php; # 注意加入了index.php并且将下述的_改成网站域名server_name _; # 改成 server_name mjj.hostloc.com;随后，重新软链接，并重启Nginxrm /etc/nginx/sites-enabled/default ln -s /etc/nginx/sites-available/mjj.hostloc.com /etc/nginx/sites-enabled/mjj.hostloc.com systemctl restart nginx注意域名不要填错了，重启完后，Nginx将能够和PHP一起支持动态网站。9.2.3 MySQL和MariaDBMySQL是一个市场占有率极大的数据库软件，应用场景极其广泛，最开始是SUN公司开发的，2009年被甲骨文收购。甲骨文作恶多端，所以MySQL的一部分作者则独立出来，直接做了一个复刻版的，被命名为MariaDB，Maria是作者女儿的名字，Linux社区逐步放弃MySQL而采用MariaDB。所以在近期发布的各Linux版本中，默认是没有MySQL的，一律采用MariaDB。apt install mariadb-server # 安装数据库 mysql_secure_installation # 首次配置由于是首次使用，所以在如下提示中，直接enter键就可以了，因为数据库的root用户此时并没有密码NOTE: RUNNING ALL PARTS OF THIS SCRIPT IS RECOMMENDED FOR ALL MariaDB SERVERS IN PRODUCTION USE! PLEASE READ EACH STEP CAREFULLY! In order to log into MariaDB to secure it, we'll need the current password for the root user. If you've just installed MariaDB, and you haven't set the root password yet, the password will be blank, so you should just press enter here. Enter current password for root (enter for none): 随后，会询问是否要设置数据库的root密码，怎么说呢，反正就建个站而已（不涉及多用户多服务），有没有无所谓，我习惯性的不设置（输入N）OK, successfully used password, moving on... Setting the root password ensures that nobody can log into the MariaDB root user without the proper authorisation. Set root password? [Y/n] N现在，新建一个用户和对应的数据库mysql # 进入数据库，如果有root密码，则是mysql -u root -p CREATE DATABASE name; # 新建数据库，name是数据库名字 Query OK, 1 row affected (0.00 sec) #此段为mySQL反馈提示，不需要输入。 CREATE USER user@localhost; # 新建用户，user是用户名字 Query OK, 0 rows affected (0.00 sec) #此段为mySQL反馈提示，不需要输入。 SET PASSWORD FOR user@localhost= PASSWORD("密码"); # 给用户设置一个密码 Query OK, 0 rows affected (0.00 sec) #此段为mySQL反馈提示，不需要输入。 GRANT ALL PRIVILEGES ON name.* TO user@localhost IDENTIFIED BY '密码'; # 把name这个数据库和user这个用户关联 Query OK, 0 rows affected (0.00 sec) #此段为mySQL反馈提示，不需要输入。 FLUSH PRIVILEGES; # 完成设置 exit # 退出数据库9.2.4 Let's Encrypt，SSL/TLShttp连接，由于不是加密的，所以任何人都可以查看内容，这对于一些金融服务有着巨大的危害，比如使用信用卡在网上购物的时候，账号和密码会被获知。所以网景（Firefox浏览器的前身）提出了SSL（安全套接层/Secure Sockets Layer）这个概念（后来演变升级为TLS，即传输层安全性协议/Transport Layer Security），http变成了https，电脑会内置证书，而网站也会有一个证书，只有两者相互验证成功，才能正常浏览玩网页，并且全程加密（DNS部分并不是加密的，所以有个DoH，dns over https）。SSL/TLS证书是个垄断行业，电脑内置的证书就那么几家，如果想网站被大多数浏览器/系统接受，那就只能去申请其中某家的证书，这里面层层签发转售，几近无本万利。不过好在还是有很多免费的SSL/TLS证书的，比如Let's Encrypt提供三个月的免费证书，而亚洲诚信通过第三方公司，提供一年免费的证书。这里以Let's Encrypt为例演示，相关链接为 https://certbot.eff.org/instructions ：Let's Encrypt提供的SSL/TLS工具叫做cerbot，可以通过snap或者pip安装。snap是Ubuntu强推的一种软件部署和软件包管理系统，把所有需要的东西都放一起。pip是通过python3的pip安装，pip和snap没有功能上的区别，不想被Ubuntu强推就使用pip。snap安装cerbot申请SSL/TLS证书apt install snapd snap install core snap refresh core snap install --classic certbot ln -s /snap/bin/certbot /usr/bin/certbot certbot --nginx然后按照提示，输入邮箱和同意服务协议，并且在提示域名的时候，注意不要输错。pip安装cerbot申请SSL/TLS证书apt install python3 python3-venv libaugeas0 python3 -m venv /opt/certbot/ /opt/certbot/bin/pip install --upgrade pip /opt/certbot/bin/pip install certbot certbot-nginx ln -s /opt/certbot/bin/certbot /usr/bin/certbot certbot --nginx echo "0 0,12 * * * root /opt/certbot/bin/python -c 'import random; import time; time.sleep(random.random() * 3600)' && certbot renew -q" | sudo tee -a /etc/crontab > /dev/null相比于snap自动每三个月更新证书，pip需要通过crontab加一个定时任务（上述最后一行），另外，也需要偶尔检查以下certbot有没有更新，即使用此命令/opt/certbot/bin/pip install --upgrade certbot certbot-nginx10 Docker快速入门Docker的本意是“码头工人”，即搬运别人打包好的集装箱。之所以取这个名字，是因为Docker的功能与此类似：将系统和里面的应用一起打包好，别人“搬走”就能直接使用——可以将Docker粗略的理解成一个包含了系统和应用的虚拟机（严格来说，Docker是使用了沙箱机制的虚拟化容器）。常见的例子就是别人把某一个软件配置好了，用户直接下载下来，简单设置一下就可以使用了，不需要繁杂的配置过程，所以在批量服务中有着广泛的应用场景。Docker分为社区版/CE（Community Edition，免费的）和企业版/EE（Enterprise Edition，收费的），两者功能无本质区别，以下默认使用社区版。10.1 安装Docker环境apt update # 同步更新源 apt install -y ca-certificates curl gnupg lsb-release # 安装必要依赖软件添加GPG密钥，注意这里和上面一样，必须是root权限（如下命令）。这里简单介绍一下GPG，全称是GnuPG，真·全称是GNU Privacy Guard，一个密码学软件，用来验证通信中的安全性，防止传输过程中被篡改，前身是Pretty Good Privacy/PGP。curl -fsSL https://download.docker.com/linux/debian/gpg | gpg --dearmor -o /usr/share/keyrings/docker-archive-keyring.gpg选择使用稳定版，如果需要nightly或者test版，可以把下面的stable改成对应的版本。echo "deb [arch=$(dpkg --print-architecture) signed-by=/usr/share/keyrings/docker-archive-keyring.gpg] https://download.docker.com/linux/debian $(lsb_release -cs) stable" | tee /etc/apt/sources.list.d/docker.list > /dev/null更新并安装Dockerapt update apt install -y docker-ce docker-ce-cli containerd.io期间会下载几百兆的文件，网络不好的话，可能会需要一段时间，当完成安装后，使用docker run hello-world命令来测试功能是否正常，理论上会输出下图内容：至此，系统已经安装好了Docker环境，可以自己写一个Docker的应用，或者直接拉取别人写好的为自己所用。10.2 安装别人打包好的的Docker先说一下常用的Docker命令，然后以安装Docker版本的Nextcloud为例。Nextcloud是一个开源的网盘系统，类似于私有版本的百度云，可以自己搭建从而确保数据都在自己手上而不会被8秒。10.2.1 常用Docker命令docker ps 列出所有正在运行的容器，如果需要查看所有的容器（包括未运行或者启动失败的）则使用docker ps -la，这点类似于ls和ls -la的区别。docker start/stop/restart CONTAINER ID 开启/停止/重启特定容器，后面要加上指定的ID，CONTAINER ID见下文。docker rm CONTAINER ID 删除容器，如果是删除镜像，则需要把rm换成rmi10.2.2 安装Docker版Nextcloud在 https://hub.docker.com/ 中直接搜索Nextcloud，找到官方版本的镜像，点击进去，在右侧有拉取镜像的命令，直接运行即可。安装过程中会下载各个组件，等全部显示Pull conplete即表示下载完成，之后会自动校验并提示完成。使用docker run -d -p 80:80 nextcloud 运行，此时使用docker ps可以查看到具体的详细信息CONTAINER ID类似于身份证号码；IMAGE是身份证上的姓名；COMMAND是实际运行的程序；CREATED是创建的时间；STATUS是此时的运行状态；PORTS是端口，上述我们把容器的80端口定向到服务器的80，并且默认ipv4和ipv6都可以访问，接受所有IP的访问（0.0.0.0代表接受所有IP）；NAMES是容器的名字，可以理解为外号。之后就是通过IP或者绑定的域名访问，进行最后的安装。这里就能看出来Docker的优势了：用户无需了解具体操作和搭建步骤，提供者负责维护，这可以极大的简化用户的使用步骤，还可以标准化环境，无论使用Debain还是REHL，镜像/容器都是提供者给定的。如果不再需要Nextcloud，则首先停止容器，随后再删除：docker stop c30d348f1ef1 docker rm c30d348f1ef110.3 建自己的DockerDocker通过Unix socket与它的引擎进行通信，出于安全考虑，一般只有root用户和在docker组的用户才能正常访问Unix socket。所以，如果想建一个完善的Docker应用，那么建议额外新增一个用户，并加入docker用户组。
Halo博客搭建指南快速开始Fat Jar下载最新的 Halo 运行包：curl -L https://github.com/halo-dev/halo/releases/download/v1.5.3/halo-1.5.3.jar --output halo.jar其他地址java -jar halo.jarDockerdocker run -it -d --name halo -p 8090:8090 -v ~/.halo:/root/.halo --restart=always halohub/halo:1.5.3详细部署文档请查阅：使用 Docker 部署 Halo使用 Docker 部署 Halo 和 MySQL使用 Docker Compose 部署 Halo项目部署环境检查目前运行 Halo 的最低依赖要求为 JRE 11，请务必确保在进行下面操作之前已经正确安装了 JRE。目前介绍两种 Linux 发行版的安装方式，均为 OpenJRE，不推荐 Oracle 版本。CentOSsudo yum install java-11-openjdk -y检查版本：java -version如果输出以下类似内容即代表成功openjdk version "11.0.10" 2021-01-19 LTS OpenJDK Runtime Environment 18.9 (build 11.0.10+9-LTS) OpenJDK 64-Bit Server VM 18.9 (build 11.0.10+9-LTS, mixed mode, sharing)Ubuntu/Debiansudo apt-get install openjdk-11-jre -y检查版本：java -version如果输出以下类似内容即代表成功openjdk version "11.0.10" 2021-01-19 OpenJDK Runtime Environment (build 11.0.10+9-Ubuntu-0ubuntu1.20.04) OpenJDK 64-Bit Server VM (build 11.0.10+9-Ubuntu-0ubuntu1.20.04, mixed mode)下载项目创建存放 运行包 的目录，这里以 ~/app 为例mkdir ~/app && cd ~/app下载运行包wget https://dl.halo.run/release/halo-1.5.3.jar -O halo.jar如果下载速度不理想，可以 在这里 选择其他下载地址。创建 工作目录mkdir ~/.halo && cd ~/.halo下载示例配置文件到 工作目录wget https://dl.halo.run/config/application-template.yaml -O ./application.yaml 编辑配置文件，配置数据库或者端口等，如需配置请参考 配置参考vim application.yaml测试运行 Halocd ~/app && java -jar halo.jar如看到类似以下日志输出，则代表启动成功。run.halo.app.listener.StartedListener : Halo started at http://127.0.0.1:8090 run.halo.app.listener.StartedListener : Halo admin started at http://127.0.0.1:8090/admin run.halo.app.listener.StartedListener : Halo has started successfully!打开 http://ip:端口号 即可看到安装引导界面。运行包指 Halo 构建所产生的 Jar 包，后缀为 .jar。可能与其他网站应用有所区别的是，Halo 仅仅只有这一个文件。而且所有数据统一保存在下面所说的 工作目录。工作目录指 Halo 所依赖的工作目录，在 Halo 运行的时候会在系统当前用户目录下产生一个 .halo 的文件夹，绝对路径为 ~/.halo。由于这个工作目录是固定的，所以上面所说的 运行包不限制所存放的位置，里面通常包含下列目录或文件：db：存放 H2 Database 的物理文件，如果您使用 MySQL 数据库，那么不会存在这个目录。templates/themes：里面包含用户所下载的主题。static：相当于网站的根目录。logs：运行日志目录。upload：附件目录。application.yaml：配置文件。作为服务运行下载 Halo 官方的 halo.service 模板wget https://dl.halo.run/config/halo.service -O /etc/systemd/system/halo.service修改 halo.servicevim /etc/systemd/system/halo.serviceYOUR_JAR_PATH：Halo 运行包的绝对路径，例如 /home/halo/app/halo.jar，注意：此路径不支持 ~ 符号。USER：运行 Halo 的系统用户，如果有创建新的用户来运行 Halo，修改为你创建的用户名称即可。反之请删除 User=USER。[Unit] Description=Halo Service Documentation=https://halo.run After=network-online.target Wants=network-online.target [Service] Type=simple User=USER ExecStart=/usr/bin/java -server -Xms256m -Xmx256m -jar YOUR_JAR_PATH ExecStop=/bin/kill -s QUIT $MAINPID Restart=always StandOutput=syslog StandError=inherit [Install] WantedBy=multi-user.target√> 请确保 /usr/bin/java 是正确无误的。建议将 ExecStart 中的命令复制出来运行一下，保证命令有效。重新加载 systemdsystemctl daemon-reload运行服务systemctl start halo在系统启动时启动服务systemctl enable halo您可以查看服务日志检查启动状态journalctl -n 20 -u halo反向代理Nginxupstream halo { server 127.0.0.1:8090; } server { listen 80; listen [::]:80; server_name www.yourdomain.com; client_max_body_size 1024m; location / { proxy_pass http://halo; proxy_set_header HOST $host; proxy_set_header X-Forwarded-Proto $scheme; proxy_set_header X-Real-IP $remote_addr; proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for; } }!> Nginx 默认的 client_max_body_size 配置大小为 1m，可能会导致你在 Halo 后台上传文件被 Nginx 限制，所以此示例配置文件加上了 client_max_body_size 1024m; 这行配置。当然，1024m 可根据你的需要自行修改。使用宝塔面板使用 Supervisor 托管 Halo 进程打开 Supervisor 管理器的设置，点击 添加守护进程 按钮。需要填写的表单信息如下：名称：随意启动用户：如果您创建了用于运行 Halo 的用户，则选择您创建的用户即可。否则选择默认的 root。运行目录：运行包的存放目录，按照实际情况填写，需要保证你所选的目录包含运行包。启动命令：java -server -Xms256m -Xmx256m -jar halo.jar填写完成之后点击 确定 按钮即可。添加站点并配置 Nginx点击左侧的 网站 菜单项，点击 添加站点 按钮。需要填写的表单信息如下：域名：填写您已经解析到当前服务器公网 IP 的域名。PHP版本：纯静态填写完成之后点击 提交 按钮即可。设置 SSL在配置反向代理之前，我们推荐先设置好 SSL 证书。可选择 宝塔 SSL 或者 Let's Encrypt 进行证书申请。需要开启右上角的 强制 HTTPS。修改配置文件在根节点添加：upstream halo { server 127.0.0.1:8090; }其中的 8090 为 Halo 的运行端口，请按需修改。在 server 节点添加：location / { proxy_pass http://halo; proxy_set_header HOST $host; proxy_set_header X-Forwarded-Proto $scheme; proxy_set_header X-Real-IP $remote_addr; proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for; }修改 server 节点中的 location ~ .*\.(gif|jpg|jpeg|png|bmp|swf)$ 节点：location ~ .*\.(gif|jpg|jpeg|png|bmp|swf)$ { proxy_pass http://halo; expires 30d; error_log /dev/null; access_log off; }修改 server 节点中的 location ~ .*\.(js|css)?$ 节点：location ~ .*\.(js|css)?$ { proxy_pass http://halo; expires 12h; error_log /dev/null; access_log off; }完整配置文件示例（仅包含关键部分）：upstream halo { server 127.0.0.1:8090; } server { ... location ~ .*\.(gif|jpg|jpeg|png|bmp|swf)$ { proxy_pass http://halo; expires 30d; error_log /dev/null; access_log off; } location ~ .*\.(js|css)?$ { proxy_pass http://halo; expires 12h; error_log /dev/null; access_log off; } location / { proxy_pass http://halo; proxy_set_header HOST $host; proxy_set_header X-Forwarded-Proto $scheme; proxy_set_header X-Real-IP $remote_addr; proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for; } ... }随后点击保存即可。如果配置不生效，请重载 Nginx 或者 重启 Nginx。最后，访问域名即可进行 Halo 的初始化。
正则表达式正则表达式入门介绍对于没接触过正则的同事，这里提供学习的网站 ，并建议认真学习两个课时，本文的重点在后面，并不详细抄袭网上一大堆的正则的语法。下面先给出一个简单的示例：^ 为匹配输入字符串的开始位置。[0-9]+匹配多个数字， [0-9] 匹配单个数字，+ 匹配一个或者多个。abc$匹配字母 abc 并以 abc 结尾，$ 为匹配输入字符串的结束位置。我们在写用户注册表单时，只允许用户名包含字符、数字、下划线和连接字符(-)，并设置用户名的长度，我们就可以使用以下正则表达式来设定。以上的正则表达式可以匹配 runoob、runoob1、run-oob、run_oob， 但不匹配 ru，因为它包含了小写的字母而且太短了，也不匹配 runoob$, 因为它包含特殊字符。语法所谓正则的语法，主要是记住一大堆的符号，包括特殊字符、限定符、定位符，通过普通字符（数字、字母等）和其他符号的结合，表达出待匹配的字符模式。注：不同语言的正则表达式语法似乎不尽相同，具体应用时还是要了解一下该语言的具体情况。验证工具写正则遇到困难时不妨用下面的工具验证试验，十分好用。验证网站re模块使用其他语言的大致相同，本文略略介绍一下python中re模块的使用。使用re的一般步骤是将正则表达式的字符串形式编译为Pattern实例使用Pattern实例处理文本并获得匹配结果（一个Match实例）此处常用的函数方法包括：match， search， split，findall，finditer, sub, subn使用Match实例获得信息，进行其他的操作。此处常用match 实例的string属性获得匹配时使用的文本，或者group方法等获得一个或多个分组截获的字符串。正则表达式进阶学完上述知识，有了一些经验后，很容易认为正则的功能大致如此，实际上还有很多可学的东西，虽然很可能在工作上不常用。窃以为，正则表达式的高级用法主要是1）捕获与分组 ，2）零宽断言（叫环视可能好理解）。分组就是对正则表达式进行用“()”分割后命名，默认的分组命名方式是：整个正则表达式为分组0，从左到右分组为1、2、3以此类推。也可以自己进行命名，语法如下：代码描述(exp)匹配exp，并捕获文本到自动命名的组内(?exp)匹配exp，并捕获文本到name的组里面，尖括号可以换成''(?:exp)匹配exp，不捕获匹配的文本，也不给此分组分配组号零宽断言从概念理解到实际应用上都是难点，但是是个好用的东西，如果你不知道，一定会妨碍你写正则。断言就是判断当前位置的前后是否匹配，但是不消耗任何字符（零宽），普通的断言，比如\d+(匹配一个或者多个数字)，它所匹配的内容是由长度的。代码描述(?=exp)正预测先行断言，断言自身出现的位置的后面可以匹配后面跟的表达式(?<=exp)正回顾后发断言，它断言自身出现的位置的前面可以匹配后面跟的表达式(?!exp)负预测先行断言，它断言自身出现的位置的后面不可以匹配后面跟的表达式(?<!exp)负回顾后发断言，它断言自身出现的位置的后面不可以匹配后面跟的表达式啰嗦一句，注意贪婪、非贪婪的使用，注意匹配的优先级等问题正则表达式练习练习网站如下：正则高尔夫编程胶囊给出一些例子如下WarmupfooAnchorsk$It never endsu\b #不让用$RangesBackrefs(...).*\1Abba^(?!.*(.)(.)\2\1)A man, a plan(.)(.).?\2\1.?$ #并不是最优 ^(.)[^p].*\1$ #最优Prime^(?!(xx+)\1+$) #正则匹配素数 ^(?!(..+)\1+$) #优解Four(.)(.\1){3}Powers^(?!(.(..)+)\1*$) #匹配幂常用正则表达式一、校验数字的表达式数字：^[0-9]*$ n位的数字：^\d{n}$ 至少n位的数字：^\d{n,}$ m-n位的数字：^\d{m,n}$ 零和非零开头的数字：^(0|[1-9][0-9]*)$ 非零开头的最多带两位小数的数字：^([1-9][0-9]*)+(\.[0-9]{1,2})?$ 带1-2位小数的正数或负数：^(\-)?\d+(\.\d{1,2})$ 正数、负数、和小数：^(\-|\+)?\d+(\.\d+)?$ 有两位小数的正实数：^[0-9]+(\.[0-9]{2})?$ 有1~3位小数的正实数：^[0-9]+(\.[0-9]{1,3})?$ 非零的正整数：^[1-9]\d*$ 或 ^([1-9][0-9]*){1,3}$ 或 ^\+?[1-9][0-9]*$ 非零的负整数：^\-[1-9][]0-9"*$ 或 ^-[1-9]\d*$ 非负整数：^\d+$ 或 ^[1-9]\d*|0$ 非正整数：^-[1-9]\d*|0$ 或 ^((-\d+)|(0+))$ 非负浮点数：^\d+(\.\d+)?$ 或 ^[1-9]\d*\.\d*|0\.\d*[1-9]\d*|0?\.0+|0$ 非正浮点数：^((-\d+(\.\d+)?)|(0+(\.0+)?))$ 或 ^(-([1-9]\d*\.\d*|0\.\d*[1-9]\d*))|0?\.0+|0$ 正浮点数：^[1-9]\d*\.\d*|0\.\d*[1-9]\d*$ 或 ^(([0-9]+\.[0-9]*[1-9][0-9]*)|([0-9]*[1-9][0-9]*\.[0-9]+)|([0-9]*[1-9][0-9]*))$ 负浮点数：^-([1-9]\d*\.\d*|0\.\d*[1-9]\d*)$ 或 ^(-(([0-9]+\.[0-9]*[1-9][0-9]*)|([0-9]*[1-9][0-9]*\.[0-9]+)|([0-9]*[1-9][0-9]*)))$ 浮点数：^(-?\d+)(\.\d+)?$ 或 ^-?([1-9]\d*\.\d*|0\.\d*[1-9]\d*|0?\.0+|0)$二、校验字符的表达式汉字：^[\u4e00-\u9fa5]{0,}$ 英文和数字：^[A-Za-z0-9]+$ 或 ^[A-Za-z0-9]{4,40}$ 长度为3-20的所有字符：^.{3,20}$ 由26个英文字母组成的字符串：^[A-Za-z]+$ 由26个大写英文字母组成的字符串：^[A-Z]+$ 由26个小写英文字母组成的字符串：^[a-z]+$ 由数字和26个英文字母组成的字符串：^[A-Za-z0-9]+$ 由数字、26个英文字母或者下划线组成的字符串：^\w+$ 或 ^\w{3,20}$ 中文、英文、数字包括下划线：^[\u4E00-\u9FA5A-Za-z0-9_]+$ 中文、英文、数字但不包括下划线等符号：^[\u4E00-\u9FA5A-Za-z0-9]+$ 或 ^[\u4E00-\u9FA5A-Za-z0-9]{2,20}$ 可以输入含有^%&',;=?$\"等字符：[^%&',;=?$\x22]+ 禁止输入含有~的字符：[^~]+三、特殊需求表达式Email地址：^\w+([-+.]\w+)*@\w+([-.]\w+)*\.\w+([-.]\w+)*$ 域名：[a-zA-Z0-9][-a-zA-Z0-9]{0,62}(\.[a-zA-Z0-9][-a-zA-Z0-9]{0,62})+\.? InternetURL：[a-zA-z]+://[^\s]* 或 ^http://([\w-]+\.)+[\w-]+(/[\w-./?%&=]*)?$ 手机号码：^(13[0-9]|14[01456879]|15[0-35-9]|16[2567]|17[0-8]|18[0-9]|19[0-35-9])\d{8}$ 电话号码("XXX-XXXXXXX"、"XXXX-XXXXXXXX"、"XXX-XXXXXXX"、"XXX-XXXXXXXX"、"XXXXXXX"和"XXXXXXXX)：^(\(\d{3,4}-)|\d{3.4}-)?\d{7,8}$ 国内电话号码(0511-4405222、021-87888822)：\d{3}-\d{8}|\d{4}-\d{7} 电话号码正则表达式（支持手机号码，3-4位区号，7-8位直播号码，1－4位分机号）: ((\d{11})|^((\d{7,8})|(\d{4}|\d{3})-(\d{7,8})|(\d{4}|\d{3})-(\d{7,8})-(\d{4}|\d{3}|\d{2}|\d{1})|(\d{7,8})-(\d{4}|\d{3}|\d{2}|\d{1}))$) 身份证号(15位、18位数字)，最后一位是校验位，可能为数字或字符X：(^\d{15}$)|(^\d{18}$)|(^\d{17}(\d|X|x)$) 帐号是否合法(字母开头，允许5-16字节，允许字母数字下划线)：^[a-zA-Z][a-zA-Z0-9_]{4,15}$ 密码(以字母开头，长度在6~18之间，只能包含字母、数字和下划线)：^[a-zA-Z]\w{5,17}$ 强密码(必须包含大小写字母和数字的组合，不能使用特殊字符，长度在 8-10 之间)：^(?=.*\d)(?=.*[a-z])(?=.*[A-Z])[a-zA-Z0-9]{8,10}$ 强密码(必须包含大小写字母和数字的组合，可以使用特殊字符，长度在8-10之间)：^(?=.*\d)(?=.*[a-z])(?=.*[A-Z]).{8,10}$ 日期格式：^\d{4}-\d{1,2}-\d{1,2} 一年的12个月(01～09和1～12)：^(0?[1-9]|1[0-2])$ 一个月的31天(01～09和1～31)：^((0?[1-9])|((1|2)[0-9])|30|31)$ 钱的输入格式： 有四种钱的表示形式我们可以接受:"10000.00" 和 "10,000.00", 和没有 "分" 的 "10000" 和 "10,000"：^[1-9][0-9]*$ 这表示任意一个不以0开头的数字,但是,这也意味着一个字符"0"不通过,所以我们采用下面的形式：^(0|[1-9][0-9]*)$ 一个0或者一个不以0开头的数字.我们还可以允许开头有一个负号：^(0|-?[1-9][0-9]*)$ 这表示一个0或者一个可能为负的开头不为0的数字.让用户以0开头好了.把负号的也去掉,因为钱总不能是负的吧。下面我们要加的是说明可能的小数部分：^[0-9]+(.[0-9]+)?$ 必须说明的是,小数点后面至少应该有1位数,所以"10."是不通过的,但是 "10" 和 "10.2" 是通过的：^[0-9]+(.[0-9]{2})?$ 这样我们规定小数点后面必须有两位,如果你认为太苛刻了,可以这样：^[0-9]+(.[0-9]{1,2})?$ 这样就允许用户只写一位小数.下面我们该考虑数字中的逗号了,我们可以这样：^[0-9]{1,3}(,[0-9]{3})*(.[0-9]{1,2})?$ 1到3个数字,后面跟着任意个 逗号+3个数字,逗号成为可选,而不是必须：^([0-9]+|[0-9]{1,3}(,[0-9]{3})*)(.[0-9]{1,2})?$ 备注：这就是最终结果了,别忘了"+"可以用"*"替代如果你觉得空字符串也可以接受的话(奇怪,为什么?)最后,别忘了在用函数时去掉去掉那个反斜杠,一般的错误都在这里 xml文件：^([a-zA-Z]+-?)+[a-zA-Z0-9]+\\.[x|X][m|M][l|L]$ 中文字符的正则表达式：[\u4e00-\u9fa5] 双字节字符：[^\x00-\xff] (包括汉字在内，可以用来计算字符串的长度(一个双字节字符长度计2，ASCII字符计1)) 空白行的正则表达式：\n\s*\r (可以用来删除空白行) HTML标记的正则表达式：<(\S*?)[^>]*>.*?|<.*? /> ( 首尾空白字符的正则表达式：^\s*|\s*$或(^\s*)|(\s*$) (可以用来删除行首行尾的空白字符(包括空格、制表符、换页符等等)，非常有用的表达式) 腾讯QQ号：[1-9][0-9]{4,} (腾讯QQ号从10000开始) 中国邮政编码：[1-9]\d{5}(?!\d) (中国邮政编码为6位数字) IPv4地址：((2(5[0-5]|[0-4]\d))|[0-1]?\d{1,2})(\.((2(5[0-5]|[0-4]\d))|[0-1]?\d{1,2})){3}
Debian安装配置Mariadb指南熟悉了MySQL后，感受一下Debian下的MairaDB的体验#安装MariaDB的服务端 apt install -y mariadb-server systemctl start mariadb systemctl enable mariadb systemctl status mariadb #初始化设置 mysql_secure_installation cd /etc/mysql/mariadb.conf.d vim 50-server.cnf #修改绑定ip为0.0.0.0 #bind-address systemctl restart mariadb mysql -u root -p #赋权给宿主机访问 use mysql; grant all privileges on *.* to 'root'@'%' identified by "2465" with grant option; flush privileges; select user from user;
到底什么是面向对象编程和面向过程编程
一、先来两小段通俗解释面向过程（Procedure Oriented 简称PO ：如C语言）：从名字可以看出它是注重过程的。当解决一个问题的时候，面向过程会把事情拆分成： 一个个函数和数据（用于方法的参数） 。然后按照一定的顺序，执行完这些方法（每个方法看作一个过程），等方法执行完了，事情就搞定了。面向对象（Object Oriented简称OO ：如C++，JAVA等语言）：看名字它是注重对象的。当解决一个问题的时候，面向对象会把事物抽象成对象的概念，就是说这个问题里面有哪些对象，然后给对象赋一些属性和方法，然后让每个对象去执行自己的方法，问题得到解决。二、用3个例子说明两者的区别例子一：问题： 洗衣机里面放有脏衣服，怎么洗干净？面向过程的解决方法：1、执行加洗衣粉方法；2、执行加水方法；3、执行洗衣服方法；4、执行清洗方法；5、 执行烘干方法；以上就是将解决这个问题的过程拆成一个个方法（是没有对象去调用的），通过一个个方法的执行来解决问题。面向对象的解决方法：1、我先弄出两个对象：“洗衣机”对象和“人”对象2、针对对象“洗衣机”加入一些属性和方法：“洗衣服方法”“清洗方法”、“烘干方法”3、针对对象“人”加入属性和方法：“加洗衣粉方法”、“加水方法”4、然后执行人.加洗衣粉人.加水洗衣机.洗衣服洗衣机.清洗洗衣机.烘干解决同一个问题 ，面向对象编程就是先抽象出对象，然后用对象执行方法的方式解决问题。例子二 ： 打麻将例子 你 我 他面向过程： 打麻将 （你，我，他）---------解决问题 拆成一个动作，把数据丢进去面向对象： 我.打麻将（你，他） or 你.打麻将（我，他） or 他.打麻将(我，你)---------解决问题 抽象出对象，对象执行动作 。例子三：最后在用一个网上常见的五子棋例子来说明一下：面向过程的设计思路就是首先分析问题的步骤：1、开始游戏，2、黑子先走，3、绘制画面，4、判断输赢，5、轮到白子，6、绘制画面，7、判断输赢，8、返回步骤2，9、输出最后结果。把上面每个步骤用不同的方法来实现。面向对象的设计则是从另外的思路来解决问题。整个五子棋可以分为1、黑白双方，这两方的行为是一模一样的，2、棋盘系统，负责绘制画面，3、规则系统，负责判定诸如犯规、输赢等。第一类对象（玩家对象）负责接受用户输入，并告知第二类对象（棋盘对象）棋子布局的变化，棋盘对象接收到了棋子的变化就要负责在屏幕上面显示出这种变化，同时利用第三类对象（规则系统）来对棋局进行判定。可以明显地看出，面向对象是以功能来划分问题，而不是步骤。同样是绘制棋局，这样的行为在面向过程的设计中分散在了多个步骤中，很可能出现不同的绘制版本，因为通常设计人员会考虑到实际情况进行各种各样的简化。而面向对象的设计中，绘图只可能在棋盘对象中出现，从而保证了绘图的统一。三：面向过程与面向对象的优缺点：用面向过程的方法写出来的程序是一份蛋炒饭，而用面向对象写出来的程序是一份盖浇饭。蛋炒饭制作的细节不说了，最后的一道工序肯定是把米饭和鸡蛋混在一起炒匀。盖浇饭呢，则是把米饭和盖菜分别做好，你如果要一份红烧肉盖饭呢，就给你浇一份红烧肉；如果要一份青椒土豆盖浇饭，就给浇一份青椒土豆丝。蛋炒饭的好处就是入味均匀，吃起来香。如果恰巧你不爱吃鸡蛋，只爱吃青菜的话，那么唯一的办法就是全部倒掉，重新做一份青菜炒饭了。盖浇饭就没这么多麻烦，你只需要把上面的盖菜拨掉，更换一份盖菜就可以了。盖浇饭的缺点是入味不均，可能没有蛋炒饭那么香。到底是蛋炒饭好还是盖浇饭好呢？其实这类问题都很难回答，非要比个上下高低的话，就必须设定一个场景，否则只能说是各有所长。如果大家都不是美食家，没那么多讲究，那么从饭馆角度来讲的话，做盖浇饭显然比蛋炒饭更有优势，他可以组合出来任意多的组合，而且不会浪费。盖浇饭的好处就是‘’菜”“饭”分离，从而提高了制作盖浇饭的灵活性。饭不满意就换饭，菜不满意换菜。用软件工程的专业术语就是”可维护性“比较好，”饭” 和”菜”的耦合度比较低。蛋炒饭将”蛋”“饭”搅和在一起，想换”蛋”“饭”中任何一种都很困难，耦合度很高，以至于”可维护性”比较差。软件工程追求的目标之一就是可维护性，可维护性主要表现在3个方面：可理解性、可测试性和可修改性。面向对象的好处之一就是显著的改善了软件系统的可维护性。总结来说：面向过程优点：性能比面向对象高，因为类调用时需要实例化，开销比较大，比较消耗资源;比如单片机、嵌入式开发、 Linux/Unix等一般采用面向过程开发，性能是最重要的因素。缺点：没有面向对象易维护、易复用、易扩展面向对象优点：易维护、易复用、易扩展，由于面向对象有封装、继承、多态性的特性，可以设计出低耦合的系统，使系统 更加灵活、更加易于维护缺点：性能比面向过程低四、面向对象编程的特性三大基本特性：封装，继承，多态封装封装，就是把客观事物封装成抽象的类，并且类可以把自己的数据和方法只让可信的类或者对象操作，对不可信的进行信息隐藏。一个类就是一个封装了数据以及操作这些数据的代码的逻辑实体。在一个对象内部，某些代码或某些数据可以是私有的，不能被外界访问。通过这种方式，对象对内部数据提供了不同级别的保护，以防止程序中无关的部分意外的改变或错误的使用了对象的私有部分。继承继承，指可以让某个类型的对象获得另一个类型的对象的属性的方法。它支持按级分类的概念。继承是指这样一种能力：它可以使用现有类的所有功能，并在无需重新编写原来的类的情况下对这些功能进行扩展。 通过继承创建的新类称为“子类”或“派生类”，被继承的类称为“基类”、“父类”或“超类”。继承的过程，就是从一般到特殊的过程。要实现继承，可以通过 “继承”（Inheritance）和“组合”（Composition）来实现。继承概念的实现方式有二类：实现继承与接口继承。实现继承是指直接使用父类的属性和方法而无需额外编码的能力；接口继承是指仅使用属性和方法的名称、但是子类必须提供实现的能力。多态多态，是指一个类实例的相同方法在不同情形有不同表现形式。多态机制使具有不同内部结构的对象可以共享相同的外部接口。这意味着，虽然针对不同对象的具体操作不同，但通过一个公共的类，它们（那些操作）可以通过相同的方式予以调用。五、五大基本原则：SPR, OCP, LSP, DIP, ISP单一职责原则SRP(Single Responsibility Principle)是指一个类的功能要单一，不能包罗万象。如同一个人一样，分配的工作不能太多，否则一天到晚虽然忙忙碌碌的，但效率却高不起来。开放封闭原则OCP(Open－Close Principle)一个模块在扩展性方面应该是开放的而在更改性方面应该是封闭的。比如：一个网络模块，原来只服务端功能，而现在要加入客户端功能，那么应当在不用修改服务端功能代码的前提下，就能够增加客户端功能的实现代码，这要求在设计之初，就应当将服务端和客户端分开，公共部分抽象出来。里式替换原则LSP(the Liskov Substitution Principle LSP)子类应当可以替换父类并出现在父类能够出现的任何地方。比如：公司搞年度晚会，所有员工可以参加抽奖，那么不管是老员工还是新员工，也不管是总部员工还是外派员工，都应当可以参加抽奖，否则这公司就不和谐了。依赖倒置原则DIP(the Dependency Inversion Principle DIP)具体依赖抽象，上层依赖下层。假设B是较A低的模块，但B需要使用到A的功能，这个时候，B不应当直接使用A中的具体类： 而应当由B定义一个抽象接口，并由A来实现这个抽象接口，B只使用这个抽象接口：这样就达到了依赖倒置的目的，B也解除了对A的依赖，反过来是A依赖于B定义的抽象接口。通过上层模块难以避免依赖下层模块，假如B也直接依赖A的实现，那么就可能造成循环依赖。一个常见的问题就是编译A模块时需要直接包含到B模块的cpp文件，而编译B时同样要直接包含到A的cpp文件。接口分离原则ISP(the Interface Segregation Principle ISP)模块间要通过抽象接口隔离开，而不是通过具体的类强耦合起来
How to Rebase a Pull RequestWhen many different people are working on a project simultaneously, pull requests can go stale quickly. A "stale" pull request is one that is no longer up to date with the main line of development, and it needs to be updated before it can be merged into the project. The most common reason why pull requests go stale is due to conflicts: if two pull requests both modify similar lines in the same file, and one pull request gets merged, the unmerged pull request will now have a conflict. Sometimes, a pull request can go stale without conflicts: perhaps changes in a different file in the codebase require corresponding changes in your pull request to conform to the new architecture, or perhaps the branch was created when someone had accidentally merged failing unit tests to the master branch. Regardless of the reason, if your pull request has gone stale, you will need to rebase your branch onto the latest version of the master branch before it can be merged.What is a rebase?To understand this, we need to understand a bit about how Git works. A Git repository is a tree structure, where the nodes of the tree are commits. Here's an example of a very simple repository: it has four commits on the master branch, and each commit has an ID (in this case, a, b, c, and d). You'll notice that d is currently the latest commit (or HEAD) of the master branch.Here, we have two branches: master and my-branch. You can see that master and my-branch both contain commits a and b, but then they start to diverge: master contains c and d, while my-branch contains e and f. b is said to be the "merge base" of my-branch in comparison to master -- or more commonly, just the "base". It makes sense: you can see that my-branch was based on a previous version of master.So let's say that my-branch has gone stale, and you want to bring it up to date with the latest version of master. To put it another way, my-branch needs to contain c and d. You could do a merge, but that causes the branch to contain weird merge commits that make reviewing the pull request much more difficult. Instead, you can do a rebase.When you rebase, Git finds the base of your branch (in this case, b), finds all the commits between that base and HEAD (in this case, e and f), and re-plays those commits on the HEAD of the branch you're rebasing onto (in this case, master). Git actually creates new commits that represent what your changes look like on top of master: in the diagram, these commits are called e′ and f′. Git doesn't erase your previous commits: e and f are left untouched, and if something goes wrong with the rebase, you can go right back to the way things used to be.Another thing to notice, however, is that Git treats branches as merely labels. The master branch is whatever commit the master label is pointing to, as well as all of that commit's parents. When you rebase a branch, Git moves the branch label to point at the newly-created commits: my-branch is no longer pointing at f, it's now pointing at f′. Going back to the way things used to be just consists of changing that branch label so that it points back at f.Changing HistoryYou'll notice that there is not a direct path from f to f′: from the point of view of anyone else watching my-branch, history has suddenly changed. In effect, c and d have been injected into my-branch's history, as if they had been there the entire time. Unlike most version control systems, Git allows you to change the history of your project -- but it is very cautious about letting you do so. We'll come back to this point later.How do I rebase?So, now that you understand what a rebase is, the next step is learning how to do it. Let's say you have a fork of edx-platform, and you've created a branch, like so:$ git clone https://github.com/my-username/edx-platform.git $ cd edx-platform $ git checkout -b my-branchYou've made some commits in your branch, pushed them to GitHub, and created a pull request. You're going through the code review process, responding to comments, and someone asks you to rebase your pull request. Here's what you do:Add the official repo as a remote (first time only)A "remote", in Git terminology, is another clone of the repository that you can share commits with. When you forked the official edx/edx-platform project, you created a new Git repository called my-username/edx-platform, but these two repositories can share commits with each other.To add edx as a remote, run this command in your repository:$ git remote add edx https://github.com/edx/edx-platform.gitYou can verify that you did this successfully by running $ git remote -v: you should see edx in the list of remotes. Note: this step only needs to be performed once per clone.Fetch the latest version of masterYour computer needs to download information from GitHub about the official repo, so that it knows what's on the latest version of the master branch. Once you've got your remote set up, this is simple. Run this command in your repository:$ git fetch edxSquash your changesThis step is not always necessary, but is required when your commit history is full of small, unimportant commits (such as "Fix pep8", "Add tests", or "ARUURUGHSFDFSDFSDGLJKLJ:GK"). It involves taking all the commits you've made on your branch, and squashing them all into one, larger commit. Doing this makes it easier for you to resolve conflicts while performing the rebase, and easier for us to review your pull request.To do this, we're going to do an interactive rebase. You can also use interactive rebase to change the wording on commit messages (for example, to provide more detail), or reorder commits (use caution here: reordering commits can cause some nasty merge conflicts).If you know the number of commits on your branch that you want to rebase, you can simply run:$ git rebase -i HEAD~nwhere n is the number of commits to rebase.If you don't know how many commits are on your branch, you'll first need to find the commit that is base of your branch. You can do this by running:$ git merge-base my-branch edx/masterThat command will return a commit hash. Use that commit hash in constructing this next command:$ git rebase -i ${HASH}Note that you should replace ${HASH} with the actual commit hash from the previous command. For example, if your merge base is abc123, you would run $ git rebase -i abc123. (Your hash will be a lot longer than 6 characters. Also, do NOT include a $!)Once you've run a git rebase -i command, your text editor will open with a file that lists all the commits in your branch, and in front of each commit is the word "pick". It looks something like this:pick 1fc6c95 do something pick 6b2481b do something else pick dd1475d changed some things pick c619268 fixing typosFor every line except the first, you want to replace the word "pick" with the word "squash". It should end up looking like this:pick 1fc6c95 do something squash 6b2481b do something else squash dd1475d changed some things squash c619268 fixing typosSave and close the file, and a moment later a new file should pop up in your editor, combining all the commit messages of all the commits. Reword this commit message as you want, and then save and close that file as well. This commit message will be the commit message for the one, big commit that you are squashing all of your larger commits into. Once you've saved and closed that file, your commits have been squashed together, and you're done with this step!Rewording commitsTo reword commits, perform an interactive rebase as described in the above section. This time, instead of using the squash command, use the command reword. For example you might perform an interactive rebase and replace this:pick 1fc6c95 nblargh testing new thing pick 6b2481b Awesome New Feature: FED and Jasmine testswith this:reword 1fc6c95 nblargh testing new thing pick 6b2481b Awesome New Feature: FED and Jasmine testsSave and close the file, and a moment later a new file should pop up in your editor, showing you the current wording of the commit message. Reword this commit message as you want, and then save and close that file as well. This commit message will be the new commit message for your commit, thus your history can have more useful commit messages such as:1fc6c95 Awesome New Feature: API Endpoints and Unit Tests 6b2481b Awesome New Feature: FED and Jasmine testsPerform a rebaseTo rebase your branch atop of the latest version of edx-platform, run this command in your repository:$ git rebase edx/masterGit will start replaying your commits onto the latest version of master. You may get conflicts while doing so: if you do, Git will pause and ask you to resolve the conflicts before continuing. This is exactly like resolving conflicts with a merge: you can use git status to see which files are in conflict, edit the files to resolve the conflicts, and then use git add to indicate that the conflicts have been resolved. However, instead of running git commit, you instead want to run git rebase --continue to indicate to Git that it should continue replaying your commits. If you've squashed your commits before doing this step, you'll only have to pause to resolve conflicts once -- if you didn't squash, you may have to resolve your conflicts multiple times. If you are on Git version <2.0 and you are stuck with the message "You must edit all merge conflicts and then mark them as resolved using Git add" even though you resolved and added the file, run git diff and try again.Force-push to update your pull requestAs explained above, when you do a rebase, you are changing the history on your branch. As a result, if you try to do a normal git push after a rebase, Git will reject it because there isn't a direct path from the commit on the server to the commit on your branch. Instead, you'll need to use the -f or --force flag to tell Git that yes, you really know what you're doing. When doing force pushes, it is highly recommended that you set your push.default config setting to simple, which is the default in Git 2.0. To make sure that your config is correct, run:$ git config --global push.default simpleOnce it's correct, you can just run:$ git push -fAnd check your pull request. It should be updated!