diff --git a/docs/云计算/Azure/核心体系.md b/docs/云计算/Azure/核心体系.md index 2785f09f..1c9a7b7f 100644 --- a/docs/云计算/Azure/核心体系.md +++ b/docs/云计算/Azure/核心体系.md @@ -77,4 +77,4 @@ Azure 拥有的全球区域数量比其他任何云提供商都要多。 通过 - 如果发生大规模 Azure 服务中断,则优先考虑每个区域对中的一个区域,确保针对该区域对中托管的应用程序尽快恢复至少一个区域。 - 对配对区域逐一进行计划内 Azure 更新,以尽量减少停机时间并降低应用程序中断风险。 -- 出于税务和执法管辖权方面的考虑,数据仍以配对的形式驻留在同一地域内(巴西南部除外)。 \ No newline at end of file +- 出于税务和执法管辖权方面的考虑,数据仍以配对的形式驻留在同一地域内(巴西南部除外)。 diff --git a/docs/云计算/基本概念.md b/docs/云计算/基本概念.md index 0b4541f8..e060ae33 100644 --- a/docs/云计算/基本概念.md +++ b/docs/云计算/基本概念.md @@ -9,8 +9,8 @@ data: 2022年4月14日 - **高可用性**:根据你选择的服务级别协议 (SLA),基于云的应用可以提供持续的用户体验,即使在出现故障时也不会有明显的停机时间。 - **可伸缩性**:云中的应用可以垂直或水平缩放: - - 垂直缩放可以通过向虚拟机添加 RAM 或 CPU 增加计算容量。 - - 水平缩放可以通过添加资源实例(例如将 VM 添加到配置中)来增加计算能力。 + - 垂直缩放可以通过向虚拟机添加 RAM 或 CPU 增加计算容量。 + - 水平缩放可以通过添加资源实例(例如将 VM 添加到配置中)来增加计算能力。 - **弹性**:可以将基于云的应用配置根据需要自动缩放,使应用始终具有所需的资源。 - **敏捷性**:根据应用需求的变化,快速部署和配置基于云的资源。 - **地区分发**:可以将应用和数据部署到全球各地的区域数据中心,从而确保客户在其区域中始终具有最佳性能。 @@ -52,15 +52,15 @@ data: 2022年4月14日 ## 云服务模型 -**IaaS - 基础结构即服务** +### IaaS - 基础结构即服务 此云服务模型是最接近于管理物理服务器的;云提供商将保持硬件是最新的,但是操作系统维护和网络配置则需要作为云租户的你完成。 例如,Azure 虚拟机是在 Microsoft 数据中心中运行的完全可操作的虚拟计算设备。 这种云服务模型的优点是快速部署新的计算设备。 设置新虚拟机比采购、安装和配置物理服务器快得多。 -**PaaS - 平台即服务** +### PaaS - 平台即服务 这种云服务模型是一种托管主机环境。 云提供商管理虚拟机和网络资源,云租户将其应用程序部署到托管主机环境中。 例如,Azure 应用服务提供托管的主机环境,开发人员可在其中上传其 Web 应用程序而无需担心物理硬件和软件要求。 -**SaaS - 软件即服务** +### SaaS - 软件即服务 在这种云服务模型中,云提供商管理应用程序环境的所有方面,如虚拟机、网络资源、数据存储和应用程序。 云租户只需向由云提供商管理的应用程序提供数据。 例如,Microsoft Office 365 提供在云中运行的 Microsoft Office 的完全可用版本。 你只需创建内容,Office 365 会处理其他所有事项。 @@ -82,7 +82,7 @@ IaaS 是最灵活的云服务类别。 它旨在让你完全控制运行应用 - **技能**: 部署、使用和获取公有云的优势不需要深厚的技术技能。 组织可以利用云提供商的技能和专业知识来确保工作负载的安全性和高可用性。 -+ **云优势**: 组织可以利用云提供商的技能和专业知识来确保工作负载的安全性和高可用性。 +- **云优势**: 组织可以利用云提供商的技能和专业知识来确保工作负载的安全性和高可用性。 - **灵活性**: IaaS 是最灵活的云服务,因为你可以控制配置和管理运行应用程序的硬件。 @@ -106,7 +106,7 @@ PaaS 具有与 IaaS 相同的优势和注意事项,但还有一些其他优势 #### 缺点 -+ **平台限制**:云平台可能存在一些限制,可能会影响应用程序的运行。 评估哪种 PaaS 平台最适合某个工作负载时,请确保考虑这方面的所有限制。 +- **平台限制**:云平台可能存在一些限制,可能会影响应用程序的运行。 评估哪种 PaaS 平台最适合某个工作负载时,请确保考虑这方面的所有限制。 ### SaaS @@ -138,4 +138,4 @@ SaaS 具有与 IaaS 相同的优势,但还有一些其他优势值得注意。 与 PaaS 类似,无服务器计算使开发人员无需管理基础结构,从而能够更快地构建应用程序。 借助无服务器应用程序,云服务提供商自动预配、缩放和管理运行代码所需的基础结构。 无服务器体系结构具有高度可缩放性和事件驱动性,只在出现特定函数或触发器时使用资源。 -请注意,服务器仍会运行代码。 “无服务器”这一名称源于一个事实,即与基础结构预配和管理相关的任务对开发人员不可见。 此方法使开发人员能够将精力集中在业务逻辑上,并为业务核心提供更多价值。 无服务器计算可帮助团队提高工作效率,更快地将产品推向市场,使组织能够更好地优化资源并专注于创新。 \ No newline at end of file +请注意,服务器仍会运行代码。 “无服务器”这一名称源于一个事实,即与基础结构预配和管理相关的任务对开发人员不可见。 此方法使开发人员能够将精力集中在业务逻辑上,并为业务核心提供更多价值。 无服务器计算可帮助团队提高工作效率,更快地将产品推向市场,使组织能够更好地优化资源并专注于创新。 diff --git a/docs/产品/两个万能公式打造你讲故事的能力.md b/docs/产品/两个万能公式打造你讲故事的能力.md index 169fc8e0..dccaf4b6 100644 --- a/docs/产品/两个万能公式打造你讲故事的能力.md +++ b/docs/产品/两个万能公式打造你讲故事的能力.md @@ -24,7 +24,7 @@ data: 2022年5月19日 皮克斯的编剧 Emma Coats 曾经分享过一个皮克斯讲故事的模型,具体如下—— -“Once upon a time there was ___. Every day, ___. One day ___. Because of that, ___. Because of that, ___. Until finally ___.” +“Once upon a time there was ___. Every day,___. One day ___. Because of that,___. Because of that, ___. Until finally___.” 翻译成中文就是: @@ -239,4 +239,4 @@ XX,名校毕业,年纪轻轻事业顺风顺水,但在老公的催促下做 **别误会,我并非教大家钻营这些雕虫小技,创业也好,工作也罢,打铁还需自身硬。** -但在有实力的前提下,思考叙事的逻辑,运用故事的力量,会让我们事半功倍。 \ No newline at end of file +但在有实力的前提下,思考叙事的逻辑,运用故事的力量,会让我们事半功倍。 diff --git a/docs/安全/GPG/GPG 简明笔记.md b/docs/安全/GPG/GPG 简明笔记.md index 6febeb78..66dcc295 100644 --- a/docs/安全/GPG/GPG 简明笔记.md +++ b/docs/安全/GPG/GPG 简明笔记.md @@ -18,7 +18,7 @@ linux 默认安装 GPG,windows 和 mac 安装方法大同小异。 ### 配置 -``` +```shell # GPG 配置文件介绍 ~/.gnupg - 配置目录 ~/.gnupg/gpg.conf – 配置文件 @@ -29,11 +29,11 @@ linux 默认安装 GPG,windows 和 mac 安装方法大同小异。 ### 生成密钥 -``` +```shell gpg --gen-key ``` -``` +```shell 1.请选择您要使用的密钥种类: (1) RSA and RSA (default) (2) DSA and Elgamal @@ -82,13 +82,14 @@ from the Real Name, Comment and Email Address in this form: 公钥 -``` +```shell gpg --list-keys gpg -k ``` + 私钥 -``` +```shell gpg --list-secret-keys gpg -K ``` @@ -97,29 +98,29 @@ gpg -K 公钥 -``` +```shell gpg --armor --output public-key.txt --export [用户ID] ``` 私钥 -``` +```shell gpg --armor --output private-key.txt --export-secret-keys [用户ID] ``` -*--armor 生成 asc 后缀的 ASCII 类型的文本文件,否则生成 gpg 后缀的二进制文件* +--armor 生成 asc 后缀的 ASCII 类型的文本文件,否则生成 gpg 后缀的二进制文件 ### 导入 本地公钥文件 -``` +```shell gpg --import [密钥文件] ``` 服务器公钥文件 -``` +```shell gpg --keyserver [服务器] --search-keys [用户ID] ``` @@ -127,12 +128,13 @@ gpg --keyserver [服务器] --search-keys [用户ID] 发布至公开服务器 -``` +```shell gpg --send-keys [用户ID] --keyserver [服务器] ``` 发布用户指纹 -``` + +```shell gpg --fingerprint [用户ID] ``` @@ -140,13 +142,13 @@ gpg --fingerprint [用户ID] 删除指定公钥 -``` +```shell gpg --delete-key [用户id] ``` 删除指定密钥 -``` +```shell gpg --delete-secret-keys [用户id] ``` @@ -156,40 +158,39 @@ gpg --delete-secret-keys [用户id] 加密文件 -``` +```shell gpg --recipient [用户ID] --output demo.en.txt --encrypt demo.txt ``` 解密文件 -``` +```shell gpg --decrypt demo.en.txt --output demo.de.txt gpg demo.en.txt ``` 签名文件(GPG 格式) -``` +```shell gpg --sign test.txt ``` 签名文件(ASCII 格式) -``` +```shell gpg --clearsign test.txt ``` 生成单独签名 -``` +```shell gpg -a --detach-sign test.txt ``` -*-a 生成 ASCII 格式* +-a 生成 ASCII 格式 验证签名 -``` +```shell gpg --verify test.txt.asc test.txt ``` - diff --git a/docs/安全/SSH/rsync 命令.md b/docs/安全/SSH/rsync 命令.md index 4080a5f1..469e01eb 100644 --- a/docs/安全/SSH/rsync 命令.md +++ b/docs/安全/SSH/rsync 命令.md @@ -41,7 +41,7 @@ rsync 可以用于本地计算机的两个目录之间的同步。下面就用 本机使用 rsync 命令时,可以作为`cp`和`mv`命令的替代方法,将源目录拷贝到目标目录。 ```bash -$ rsync -r source destination +rsync -r source destination ``` 上面命令中,`-r`表示递归,即包含子目录。注意,`-r`是必须的,否则 rsync 运行不会成功。`source`目录表示源目录,`destination`表示目标目录。上面命令执行以后,目标目录下就会出现`destination/source`这个子目录。 @@ -49,7 +49,7 @@ $ rsync -r source destination 如果有多个文件或目录需要同步,可以写成下面这样。 ```bash -$ rsync -r source1 source2 destination +rsync -r source1 source2 destination ``` 上面命令中,`source1`、`source2`都会被同步到`destination`目录。 @@ -59,7 +59,7 @@ $ rsync -r source1 source2 destination `-a`参数可以替代`-r`,除了可以递归同步以外,还可以同步元信息(比如修改时间、权限等)。由于 rsync 默认使用文件大小和修改时间决定文件是否需要更新,所以`-a`比`-r`更有用。下面的用法才是常见的写法。 ```bash -$ rsync -a source destination +rsync -a source destination ``` 目标目录`destination`如果不存在,rsync 会自动创建。执行上面的命令后,源目录`source`被完整地复制到了目标目录`destination`下面,即形成了`destination/source`的目录结构。 @@ -67,7 +67,7 @@ $ rsync -a source destination 如果只想同步源目录`source`里面的内容到目标目录`destination`,则需要在源目录后面加上斜杠。 ```bash -$ rsync -a source/ destination +rsync -a source/ destination ``` 上面命令执行后,`source`目录里面的内容,就都被复制到了`destination`目录里面,并不会在`destination`下面创建一个`source`子目录。 @@ -77,7 +77,7 @@ $ rsync -a source/ destination 如果不确定 rsync 执行后会产生什么结果,可以先用`-n`或`--dry-run`参数模拟执行的结果。 ```bash -$ rsync -anv source/ destination +rsync -anv source/ destination ``` 上面命令中,`-n`参数模拟命令执行的结果,并不真的执行命令。`-v`参数则是将结果输出到终端,这样就可以看到哪些内容会被同步。 @@ -87,7 +87,7 @@ $ rsync -anv source/ destination 默认情况下,rsync 只确保源目录的所有内容(明确排除的文件除外)都复制到目标目录。它不会使两个目录保持相同,并且不会删除文件。如果要使得目标目录成为源目录的镜像副本,则必须使用`--delete`参数,这将删除只存在于目标目录、不存在于源目录的文件。 ```bash -$ rsync -av --delete source/ destination +rsync -av --delete source/ destination ``` 上面命令中,`--delete`参数会使得`destination`成为`source`的一个镜像。 @@ -111,25 +111,25 @@ $ rsync -av --exclude '*.txt' source/ destination 如果要排除某个目录里面的所有文件,但不希望排除目录本身,可以写成下面这样。 ```bash -$ rsync -av --exclude 'dir1/*' source/ destination +rsync -av --exclude 'dir1/*' source/ destination ``` 多个排除模式,可以用多个`--exclude`参数。 ```bash -$ rsync -av --exclude 'file1.txt' --exclude 'dir1/*' source/ destination +rsync -av --exclude 'file1.txt' --exclude 'dir1/*' source/ destination ``` 多个排除模式也可以利用 Bash 的大扩号的扩展功能,只用一个`--exclude`参数。 ```bash -$ rsync -av --exclude={'file1.txt','dir1/*'} source/ destination +rsync -av --exclude={'file1.txt','dir1/*'} source/ destination ``` 如果排除模式很多,可以将它们写入一个文件,每个模式一行,然后用`--exclude-from`参数指定这个文件。 ```bash -$ rsync -av --exclude-from='exclude-file.txt' source/ destination +rsync -av --exclude-from='exclude-file.txt' source/ destination ``` ### `--include`参数 @@ -137,7 +137,7 @@ $ rsync -av --exclude-from='exclude-file.txt' source/ destination `--include`参数用来指定必须同步的文件模式,往往与`--exclude`结合使用。 ```bash -$ rsync -av --include="*.txt" --exclude='*' source/ destination +rsync -av --include="*.txt" --exclude='*' source/ destination ``` 上面命令指定同步时,排除所有文件,但是会包括 TXT 文件。 @@ -149,13 +149,13 @@ $ rsync -av --include="*.txt" --exclude='*' source/ destination rsync 除了支持本地两个目录之间的同步,也支持远程同步。它可以将本地内容,同步到远程服务器。 ```bash -$ rsync -av source/ username@remote_host:destination +rsync -av source/ username@remote_host:destination ``` 也可以将远程内容同步到本地。 ```bash -$ rsync -av username@remote_host:source/ destination +rsync -av username@remote_host:source/ destination ``` rsync 默认使用 SSH 进行远程登录和数据传输。 @@ -163,13 +163,13 @@ rsync 默认使用 SSH 进行远程登录和数据传输。 由于早期 rsync 不使用 SSH 协议,需要用`-e`参数指定协议,后来才改的。所以,下面`-e ssh`可以省略。 ```bash -$ rsync -av -e ssh source/ user@remote_host:/destination +rsync -av -e ssh source/ user@remote_host:/destination ``` 但是,如果 ssh 命令有附加的参数,则必须使用`-e`参数指定所要执行的 SSH 命令。 ```bash -$ rsync -av -e 'ssh -p 2234' source/ user@remote_host:/destination +rsync -av -e 'ssh -p 2234' source/ user@remote_host:/destination ``` 上面命令中,`-e`参数指定 SSH 使用2234端口。 @@ -179,7 +179,7 @@ $ rsync -av -e 'ssh -p 2234' source/ user@remote_host:/destination 除了使用 SSH,如果另一台服务器安装并运行了 rsync 守护程序,则也可以用`rsync://`协议(默认端口873)进行传输。具体写法是服务器与目标目录之间使用双冒号分隔`::`。 ```bash -$ rsync -av source/ 192.168.122.32::module/destination +rsync -av source/ 192.168.122.32::module/destination ``` 注意,上面地址中的`module`并不是实际路径名,而是 rsync 守护程序指定的一个资源名,由管理员分配。 @@ -187,13 +187,13 @@ $ rsync -av source/ 192.168.122.32::module/destination 如果想知道 rsync 守护程序分配的所有 module 列表,可以执行下面命令。 ```bash -$ rsync rsync://192.168.122.32 +rsync rsync://192.168.122.32 ``` rsync 协议除了使用双冒号,也可以直接用`rsync://`协议指定地址。 ```bash -$ rsync -av source/ rsync://192.168.122.32/module/destination +rsync -av source/ rsync://192.168.122.32/module/destination ``` ## 增量备份 @@ -207,7 +207,7 @@ rsync 的最大特点就是它可以完成增量备份,也就是默认只复 `--link-dest`参数用来指定同步时的基准目录。 ```bash -$ rsync -a --delete --link-dest /compare/path /source/path /target/path +rsync -a --delete --link-dest /compare/path /source/path /target/path ``` 上面命令中,`--link-dest`参数指定基准目录`/compare/path`,然后源目录`/source/path`跟基准目录进行比较,找出变动的文件,将它们拷贝到目标目录`/target/path`。那些没变动的文件则会生成硬链接。这个命令的第一次备份时是全量备份,后面就都是增量备份了。 @@ -319,4 +319,3 @@ ln -s "${BACKUP_PATH}" "${LATEST_LINK}" - [Mirror Your Web Site With rsync](https://www.howtoforge.com/mirroring_with_rsync), Falko Timme - [Examples on how to use Rsync](https://linuxconfig.org/examples-on-how-to-use-rsync-for-local-and-remote-data-backups-and-synchonization), Egidio Docile - [How to create incremental backups using rsync on Linux](https://linuxconfig.org/how-to-create-incremental-backups-using-rsync-on-linux), Egidio Docile - diff --git a/docs/安全/SSH/scp 命令.md b/docs/安全/SSH/scp 命令.md index ae918f07..98b0231e 100644 --- a/docs/安全/SSH/scp 命令.md +++ b/docs/安全/SSH/scp 命令.md @@ -24,13 +24,13 @@ data: 2022年4月13日 `scp`的语法类似`cp`的语法。 ```bash -$ scp source destination +scp source destination ``` 上面命令中,`source`是文件当前的位置,`destination`是文件所要复制到的位置。它们都可以包含用户名和主机名。 ```bash -$ scp user@host:foo.txt bar.txt +scp user@host:foo.txt bar.txt ``` 上面命令将远程主机(`user@host`)用户主目录下的`foo.txt`,复制为本机当前目录的`bar.txt`。可以看到,主机与文件之间要使用冒号(`:`)分隔。 @@ -42,7 +42,7 @@ $ scp user@host:foo.txt bar.txt `scp`支持一次复制多个文件。 ```bash -$ scp source1 source2 destination +scp source1 source2 destination ``` 上面命令会将`source1`和`source2`两个文件,复制到`destination`。 @@ -121,7 +121,7 @@ $ scp user1@host1.com:/files/file.txt user2@host2.com:/files `-c`参数用来指定文件拷贝数据传输的加密算法。 ```bash -$ scp -c blowfish some_file your_username@remotehost.edu:~ +scp -c blowfish some_file your_username@remotehost.edu:~ ``` 上面代码指定加密算法为`blowfish`。 @@ -131,7 +131,7 @@ $ scp -c blowfish some_file your_username@remotehost.edu:~ `-C`参数表示是否在传输时压缩文件。 ```bash -$ scp -c blowfish -C local_file your_username@remotehost.edu:~ +scp -c blowfish -C local_file your_username@remotehost.edu:~ ``` **(3)`-F`** @@ -139,7 +139,7 @@ $ scp -c blowfish -C local_file your_username@remotehost.edu:~ `-F`参数用来指定 ssh_config 文件,供 ssh 使用。 ```bash -$ scp -F /home/pungki/proxy_ssh_config Label.pdf root@172.20.10.8:/root +scp -F /home/pungki/proxy_ssh_config Label.pdf root@172.20.10.8:/root ``` **(4)`-i`** @@ -147,7 +147,7 @@ $ scp -F /home/pungki/proxy_ssh_config Label.pdf root@172.20.10.8:/root `-i`参数用来指定密钥。 ```bash -$ scp -vCq -i private_key.pem ~/test.txt root@192.168.1.3:/some/path/test.txt +scp -vCq -i private_key.pem ~/test.txt root@192.168.1.3:/some/path/test.txt ``` **(5)`-l`** @@ -155,7 +155,7 @@ $ scp -vCq -i private_key.pem ~/test.txt root@192.168.1.3:/some/path/test.txt `-l`参数用来限制传输数据的带宽速率,单位是 Kbit/sec。对于多人分享的带宽,这个参数可以留出一部分带宽供其他人使用。 ```bash -$ scp -l 80 yourusername@yourserver:/home/yourusername/* . +scp -l 80 yourusername@yourserver:/home/yourusername/* . ``` 上面代码中,`scp`命令占用的带宽限制为每秒 80K 比特位,即每秒 10K 字节。 @@ -165,7 +165,7 @@ $ scp -l 80 yourusername@yourserver:/home/yourusername/* . `-p`参数用来保留修改时间(modification time)、访问时间(access time)、文件状态(mode)等原始文件的信息。 ```bash -$ scp -p ~/test.txt root@192.168.1.3:/some/path/test.txt +scp -p ~/test.txt root@192.168.1.3:/some/path/test.txt ``` **(7)`-P`** @@ -173,7 +173,7 @@ $ scp -p ~/test.txt root@192.168.1.3:/some/path/test.txt `-P`参数用来指定远程主机的 SSH 端口。如果远程主机使用默认端口22,可以不用指定,否则需要用`-P`参数在命令中指定。 ```bash -$ scp -P 2222 user@host:directory/SourceFile TargetFile +scp -P 2222 user@host:directory/SourceFile TargetFile ``` **(8)`-q`** @@ -181,7 +181,7 @@ $ scp -P 2222 user@host:directory/SourceFile TargetFile `-q`参数用来关闭显示拷贝的进度条。 ```bash -$ scp -q Label.pdf mrarianto@202.x.x.x:. +scp -q Label.pdf mrarianto@202.x.x.x:. ``` **(9)`-r`** @@ -193,6 +193,5 @@ $ scp -q Label.pdf mrarianto@202.x.x.x:. `-v`参数用来显示详细的输出。 ```bash -$ scp -v ~/test.txt root@192.168.1.3:/root/help2356.txt +scp -v ~/test.txt root@192.168.1.3:/root/help2356.txt ``` - diff --git a/docs/安全/SSH/sftp 命令.md b/docs/安全/SSH/sftp 命令.md index bcb5c86f..0218782e 100644 --- a/docs/安全/SSH/sftp 命令.md +++ b/docs/安全/SSH/sftp 命令.md @@ -11,10 +11,10 @@ data: 2022年4月13日 下面的命令连接 FTP 主机。 ```bash -$ sftp username@hostname +sftp username@hostname ``` -执行上面的命令,会要求输入 FTP 的密码。密码验证成功以后,就会出现 FTP 的提示符`sftp> `,下面是一个例子。 +执行上面的命令,会要求输入 FTP 的密码。密码验证成功以后,就会出现 FTP 的提示符`sftp>`,下面是一个例子。 ```bash $ sftp USER@penguin.example.com @@ -35,4 +35,3 @@ FTP 的提示符下面,就可以输入各种 FTP 命令了,这部分完全 - `bye`:退出 sftp。 - `quit`:退出 sftp。 - `exit`:退出 sftp。 - diff --git a/docs/安全/SSH/客户端.md b/docs/安全/SSH/客户端.md index a69aa2f3..90c22b78 100644 --- a/docs/安全/SSH/客户端.md +++ b/docs/安全/SSH/客户端.md @@ -23,7 +23,7 @@ $ sudo dnf install openssh-clients 安装以后,可以使用`-V`参数输出版本号,查看一下是否安装成功。 ```bash -$ ssh -V +ssh -V ``` ## 基本用法 @@ -33,13 +33,13 @@ ssh 最常见的用途就是登录服务器,这要求服务器安装并正在 ssh 登录服务器的命令如下。 ```bash -$ ssh hostname +ssh hostname ``` 上面命令中,`hostname`是主机名,它可以是域名,也可能是 IP 地址或局域网内部的主机名。不指定用户名的情况下,将使用客户端的当前用户名,作为远程服务器的登录用户名。如果要指定用户名,可以采用下面的语法。 ```bash -$ ssh user@hostname +ssh user@hostname ``` 上面的命令中,用户名和主机名写在一起了,之间使用`@`分隔。 @@ -47,13 +47,13 @@ $ ssh user@hostname 用户名也可以使用`ssh`的`-l`参数指定,这样的话,用户名和主机名就不用写在一起了。 ```bash -$ ssh -l username host +ssh -l username host ``` ssh 默认连接服务器的22端口,`-p`参数可以指定其他端口。 ```bash -$ ssh -p 8821 foo.com +ssh -p 8821 foo.com ``` 上面命令连接服务器`foo.com`的8821端口。 @@ -116,7 +116,7 @@ Offending key in /home/me/.ssh/known_hosts:36 如果新的公钥确认可以信任,需要继续执行连接,你可以执行下面的命令,将原来的公钥指纹从`~/.ssh/known_hosts`文件删除。 ```bash -$ ssh-keygen -R hostname +ssh-keygen -R hostname ``` 上面命令中,`hostname`是发生公钥变更的主机名。 @@ -132,7 +132,7 @@ SSH 登录成功后,用户就进入了远程主机的命令行环境,所看 另一种执行远程命令的方法,是将命令直接写在`ssh`命令的后面。 ```bash -$ ssh username@hostname command +ssh username@hostname command ``` 上面的命令会使得 SSH 在登录成功后,立刻在远程主机上执行命令`command`。 @@ -140,7 +140,7 @@ $ ssh username@hostname command 下面是一个例子。 ```bash -$ ssh foo@server.example.com cat /etc/hosts +ssh foo@server.example.com cat /etc/hosts ``` 上面的命令会在登录成功后,立即远程执行命令`cat /etc/hosts`。 @@ -252,7 +252,7 @@ $ ssh -c blowfish -c 3des server.example.com `-C`参数表示压缩数据传输。 ```bash -$ ssh -C server.example.com +ssh -C server.example.com ``` **-D** @@ -260,7 +260,7 @@ $ ssh -C server.example.com `-D`参数指定本机的 Socks 监听端口,该端口收到的请求,都将转发到远程的 SSH 主机,又称动态端口转发,详见《端口转发》一章。 ```bash -$ ssh -D 1080 server +ssh -D 1080 server ``` 上面命令将本机 1080 端口收到的请求,都转发到服务器`server`。 @@ -274,7 +274,7 @@ $ ssh -D 1080 server `-F`参数指定配置文件。 ```bash -$ ssh -F /usr/local/ssh/other_config +ssh -F /usr/local/ssh/other_config ``` 上面命令指定使用配置文件`other_config`。 @@ -284,7 +284,7 @@ $ ssh -F /usr/local/ssh/other_config `-i`参数用于指定私钥,意为“identity_file”,默认值为`~/.ssh/id_dsa`(DSA 算法)和`~/.ssh/id_rsa`(RSA 算法)。注意,对应的公钥必须存放到服务器,详见《密钥登录》一章。 ```bash -$ ssh -i my-key server.example.com +ssh -i my-key server.example.com ``` **-l** @@ -302,7 +302,7 @@ $ ssh sally@server.example.com `-L`参数设置本地端口转发,详见《端口转发》一章。 ```bash -$ ssh -L 9999:targetServer:80 user@remoteserver +ssh -L 9999:targetServer:80 user@remoteserver ``` 上面命令中,所有发向本地`9999`端口的请求,都会经过`remoteserver`发往 targetServer 的 80 端口,这就相当于直接连上了 targetServer 的 80 端口。 @@ -312,7 +312,7 @@ $ ssh -L 9999:targetServer:80 user@remoteserver `-m`参数指定校验数据完整性的算法(message authentication code,简称 MAC)。 ```bash -$ ssh -m hmac-sha1,hmac-md5 server.example.com +ssh -m hmac-sha1,hmac-md5 server.example.com ``` 上面命令指定数据校验算法为`hmac-sha1`或`hmac-md5`。 @@ -326,7 +326,7 @@ $ ssh -m hmac-sha1,hmac-md5 server.example.com `-o`参数用来指定一个配置命令。 ```bash -$ ssh -o "Keyword Value" +ssh -o "Keyword Value" ``` 举例来说,配置文件里面有如下内容。 @@ -339,13 +339,13 @@ Port 220 通过`-o`参数,可以把上面两个配置命令从命令行传入。 ```bash -$ ssh -o "User sally" -o "Port 220" server.example.com +ssh -o "User sally" -o "Port 220" server.example.com ``` 使用等号时,配置命令可以不用写在引号里面,但是等号前后不能有空格。 ```bash -$ ssh -o User=sally -o Port=220 server.example.com +ssh -o User=sally -o Port=220 server.example.com ``` **-p** @@ -353,7 +353,7 @@ $ ssh -o User=sally -o Port=220 server.example.com `-p`参数指定 SSH 客户端连接的服务器端口。 ```bash -$ ssh -p 2035 server.example.com +ssh -p 2035 server.example.com ``` 上面命令连接服务器的2035端口。 @@ -374,7 +374,7 @@ root’s password: `-R`参数指定远程端口转发,详见《端口转发》一章。 ```bash -$ ssh -R 9999:targetServer:902 local +ssh -R 9999:targetServer:902 local ``` 上面命令需在跳板服务器执行,指定本地计算机`local`监听自己的 9999 端口,所有发向这个端口的请求,都会转向 targetServer 的 902 端口。 @@ -384,7 +384,7 @@ $ ssh -R 9999:targetServer:902 local `-t`参数在 ssh 直接运行远端命令时,提供一个互动式 Shell。 ```bash -$ ssh -t server.example.com emacs +ssh -t server.example.com emacs ``` **-v** @@ -392,7 +392,7 @@ $ ssh -t server.example.com emacs `-v`参数显示详细信息。 ```bash -$ ssh -v server.example.com +ssh -v server.example.com ``` `-v`可以重复多次,表示信息的详细程度,比如`-vv`和`-vvv`。 @@ -421,7 +421,7 @@ ssh: SSH Secure Shell 3.2.3 (non-commercial version) on i686-pc-linux-gnu `-X`参数表示打开 X 窗口转发。 ```bash -$ ssh -X server.example.com +ssh -X server.example.com ``` **-1,-2** @@ -431,7 +431,7 @@ $ ssh -X server.example.com `-2`参数指定使用 SSH 2 协议。 ```ssh -$ ssh -2 server.example.com +ssh -2 server.example.com ``` **-4,-6** @@ -439,13 +439,13 @@ $ ssh -2 server.example.com `-4`指定使用 IPv4 协议,这是默认值。 ```bash -$ ssh -4 server.example.com +ssh -4 server.example.com ``` `-6`指定使用 IPv6 协议。 ```bash -$ ssh -6 server.example.com +ssh -6 server.example.com ``` ## 客户端配置文件 @@ -493,7 +493,7 @@ $ ssh -p 2112 neo@remote.example.com `Host`命令的值可以使用通配符,比如`Host *`表示对所有主机都有效的设置,`Host *.edu`表示只对一级域名为`.edu`的主机有效的设置。它们的设置都可以被单个主机的设置覆盖。 -### 配置命令的语法 +### 配置命令的语法 ssh 客户端配置文件的每一行,就是一个配置命令。配置命令与对应的值之间,可以使用空格,也可以使用等号。 @@ -540,4 +540,3 @@ Compression = yes - `User userName`:指定远程登录的账户名。 - `UserKnownHostsFile /users/smith/.ssh/my_local_hosts_file`:指定当前用户的`known_hosts`文件(服务器公钥指纹列表)的位置。 - `VerifyHostKeyDNS yes`:是否通过检查 SSH 服务器的 DNS 记录,确认公钥指纹是否与`known_hosts`文件保存的一致。 - diff --git a/docs/安全/SSH/密钥登录.md b/docs/安全/SSH/密钥登录.md index d0a5a477..e1b50152 100644 --- a/docs/安全/SSH/密钥登录.md +++ b/docs/安全/SSH/密钥登录.md @@ -31,23 +31,20 @@ SSH 密钥登录分为以下的步骤。 第五步,服务器收到客户端发来的加密签名后,使用对应的公钥解密,然后跟原始数据比较。如果一致,就允许用户登录。 - ## `ssh-keygen`命令:生成密钥 -### 基本用法 - 密钥登录时,首先需要生成公钥和私钥。OpenSSH 提供了一个工具程序`ssh-keygen`命令,用来生成密钥。 直接输入`ssh-keygen`,程序会询问一系列问题,然后生成密钥。 ```bash -$ ssh-keygen +ssh-keygen ``` 通常做法是使用`-t`参数,指定密钥的加密算法。 ```bash -$ ssh-keygen -t dsa +ssh-keygen -t dsa ``` 上面示例中,`-t`参数用来指定密钥的加密算法,一般会选择 DSA 算法或 RSA 算法。如果省略该参数,默认使用 RSA 算法。 @@ -89,14 +86,14 @@ ypZxmK9aCXokFiHoGCXfQ9imUP/w/jfqb9ByDtG97tUJF6nFMP5WzhM= username@shell.isp.com 下面的命令可以列出用户所有的公钥。 ```bash -$ ls -l ~/.ssh/id_*.pub +ls -l ~/.ssh/id_*.pub ``` 生成密钥以后,建议修改它们的权限,防止其他人读取。 ```bash -$ chmod 600 ~/.ssh/id_rsa -$ chmod 600 ~/.ssh/id_rsa.pub +chmod 600 ~/.ssh/id_rsa +chmod 600 ~/.ssh/id_rsa.pub ``` ### 配置项 @@ -116,7 +113,7 @@ $ chmod 600 ~/.ssh/id_rsa.pub 下面命令生成一个4096位 RSA 加密算法的密钥对,并且给出了用户名和主机名。 ```bash -$ ssh-keygen -t rsa -b 4096 -C "your_email@domain.com" +ssh-keygen -t rsa -b 4096 -C "your_email@domain.com" ``` **(3)`-f`** @@ -124,7 +121,7 @@ $ ssh-keygen -t rsa -b 4096 -C "your_email@domain.com" `-f`参数指定生成的私钥文件。 ```bash -$ ssh-keygen -t dsa -f mykey +ssh-keygen -t dsa -f mykey ``` 上面命令会在当前目录生成私钥文件`mykey`和公钥文件`mykey.pub`。 @@ -134,7 +131,7 @@ $ ssh-keygen -t dsa -f mykey `-F`参数检查某个主机名是否在`known_hosts`文件里面。 ```bash -$ ssh-keygen -F example.com +ssh-keygen -F example.com ``` **(5)`-N`** @@ -142,7 +139,7 @@ $ ssh-keygen -F example.com `-N`参数用于指定私钥的密码(passphrase)。 ```bash -$ ssh-keygen -t dsa -N secretword +ssh-keygen -t dsa -N secretword ``` **(6)`-p`** @@ -154,7 +151,7 @@ $ ssh-keygen -t dsa -N secretword `-R`参数将指定的主机公钥指纹移出`known_hosts`文件。 ```bash -$ ssh-keygen -R example.com +ssh-keygen -R example.com ``` **(8)`-t`** @@ -170,7 +167,7 @@ OpenSSH 规定,用户公钥保存在服务器的`~/.ssh/authorized_keys`文件 用户可以手动编辑该文件,把公钥粘贴进去,也可以在本机计算机上,执行下面的命令。 ```bash -$ cat ~/.ssh/id_rsa.pub | ssh user@host "mkdir -p ~/.ssh && cat >> ~/.ssh/authorized_keys" +cat ~/.ssh/id_rsa.pub | ssh user@host "mkdir -p ~/.ssh && cat >> ~/.ssh/authorized_keys" ``` 上面示例中,`user@host`要替换成你所要登录的用户名和主机名。 @@ -178,7 +175,7 @@ $ cat ~/.ssh/id_rsa.pub | ssh user@host "mkdir -p ~/.ssh && cat >> ~/.ssh/author 注意,`authorized_keys`文件的权限要设为`644`,即只有文件所有者才能写。如果权限设置不对,SSH 服务器可能会拒绝读取该文件。 ```bash -$ chmod 644 ~/.ssh/authorized_keys +chmod 644 ~/.ssh/authorized_keys ``` 只要公钥上传到服务器,下次登录时,OpenSSH 就会自动采用密钥登录,不再提示输入密码。 @@ -199,7 +196,7 @@ OpenSSH 自带一个`ssh-copy-id`命令,可以自动将公钥拷贝到远程 用户在本地计算机执行下面的命令,就可以把本地的公钥拷贝到服务器。 ```bash -$ ssh-copy-id -i key_file user@host +ssh-copy-id -i key_file user@host ``` 上面命令中,`-i`参数用来指定公钥文件,`user`是所要登录的账户名,`host`是服务器地址。如果省略用户名,默认为当前的本机用户名。执行完该命令,公钥就会拷贝到服务器。 @@ -207,7 +204,7 @@ $ ssh-copy-id -i key_file user@host 注意,公钥文件可以不指定路径和`.pub`后缀名,`ssh-copy-id`会自动在`~/.ssh`目录里面寻找。 ```bash -$ ssh-copy-id -i id_rsa user@host +ssh-copy-id -i id_rsa user@host ``` 上面命令中,公钥文件会自动匹配到`~/.ssh/id_rsa.pub`。 @@ -218,8 +215,6 @@ $ ssh-copy-id -i id_rsa user@host ## ssh-agent 命令,ssh-add 命令 -### 基本用法 - 私钥设置了密码以后,每次使用都必须输入密码,有时让人感觉非常麻烦。比如,连续使用`scp`命令远程拷贝文件时,每次都要求输入密码。 `ssh-agent`命令就是为了解决这个问题而设计的,它让用户在整个 Bash 对话(session)之中,只在第一次使用 SSH 命令时输入密码,然后将私钥保存在内存中,后面都不需要再输入私钥的密码了。 @@ -227,7 +222,7 @@ $ ssh-copy-id -i id_rsa user@host 第一步,使用下面的命令新建一次命令行对话。 ```bash -$ ssh-agent bash +ssh-agent bash ``` 上面命令中,如果你使用的命令行环境不是 Bash,可以用其他的 Shell 命令代替。比如`zsh`和`fish`。 @@ -235,7 +230,7 @@ $ ssh-agent bash 如果想在当前对话启用`ssh-agent`,可以使用下面的命令。 ```bash -$ eval `ssh-agent` +eval `ssh-agent` ``` 上面命令中,`ssh-agent`会先自动在后台运行,并将需要设置的环境变量输出在屏幕上,类似下面这样。 @@ -262,7 +257,7 @@ Identity added: /home/you/.ssh/id_dsa (/home/you/.ssh/id_dsa) 如果添加的不是默认私钥,`ssh-add`命令需要显式指定私钥文件。 ```bash -$ ssh-add my-other-key-file +ssh-add my-other-key-file ``` 上面的命令中,`my-other-key-file`就是用户指定的私钥文件。 @@ -270,7 +265,7 @@ $ ssh-add my-other-key-file 第三步,使用 ssh 命令正常登录远程服务器。 ```bash -$ ssh remoteHost +ssh remoteHost ``` 上面命令中,`remoteHost`是远程服务器的地址,ssh 使用的是默认的私钥。这时如果私钥设有密码,ssh 将不再询问密码,而是直接取出内存里面的私钥。 @@ -278,13 +273,13 @@ $ ssh remoteHost 如果要使用其他私钥登录服务器,需要使用 ssh 命令的`-i`参数指定私钥文件。 ```bash -$ ssh –i OpenSSHPrivateKey remoteHost +ssh –i OpenSSHPrivateKey remoteHost ``` 最后,如果要退出`ssh-agent`,可以直接退出子 Shell(按下 Ctrl + d),也可以使用下面的命令。 ```bash -$ ssh-agent -k +ssh-agent -k ``` ### `ssh-add`命令 @@ -296,7 +291,7 @@ $ ssh-agent -k `-d`参数从内存中删除指定的私钥。 ```bash -$ ssh-add -d name-of-key-file +ssh-add -d name-of-key-file ``` **(2)`-D`** @@ -304,7 +299,7 @@ $ ssh-add -d name-of-key-file `-D`参数从内存中删除所有已经添加的私钥。 ```bash -$ ssh-add -D +ssh-add -D ``` **(3)`-l`** @@ -312,7 +307,7 @@ $ ssh-add -D `-l`参数列出所有已经添加的私钥。 ```bash -$ ssh-add -l +ssh-add -l ``` ## 关闭密码登录 @@ -326,4 +321,3 @@ PasswordAuthentication no ``` 修改配置文件以后,不要忘了重新启动 sshd,否则不会生效。 - diff --git a/docs/安全/SSH/服务器.md b/docs/安全/SSH/服务器.md index e28c1ff4..f7293783 100644 --- a/docs/安全/SSH/服务器.md +++ b/docs/安全/SSH/服务器.md @@ -21,7 +21,7 @@ $ sudo yum install openssh-server 一般来说,sshd 安装后会跟着系统一起启动。如果当前 sshd 没有启动,可以用下面的命令启动。 ```bash -$ sshd +sshd ``` 上面的命令运行后,如果提示“sshd re-exec requires execution with an absolute path”,就需要使用绝对路径来启动。这是为了防止有人出于各种目的,放置同名软件在`$PATH`变量指向的目录中,代替真正的 sshd。 @@ -49,7 +49,7 @@ $ sudo systemctl restart sshd.service 下面的命令让 sshd 在计算机下次启动时自动运行。 ```bash -$ sudo systemctl enable sshd.service +sudo systemctl enable sshd.service ``` ## sshd 配置文件 @@ -100,7 +100,7 @@ Port 2034 # 此处不允许注释 sshd 启动时会自动读取默认的配置文件。如果希望使用其他的配置文件,可以用 sshd 命令的`-f`参数指定。 ```bash -$ sshd -f /usr/local/ssh/my_config +sshd -f /usr/local/ssh/my_config ``` 上面的命令指定 sshd 使用另一个配置文件`my_config`。 @@ -108,13 +108,13 @@ $ sshd -f /usr/local/ssh/my_config 修改配置文件以后,可以用 sshd 命令的`-t`(test)检查有没有语法错误。 ```bash -$ sshd -t +sshd -t ``` 配置文件修改以后,并不会自动生效,必须重新启动 sshd。 ```bash -$ sudo systemctl restart sshd.service +sudo systemctl restart sshd.service ``` ## sshd 密钥 @@ -347,13 +347,13 @@ SSH 2 版本专用,指定日志输出详细的 Debug 信息(`VerboseMode yes 修改配置文件以后,可以使用下面的命令验证,配置文件是否有语法错误。 ```bash -$ sshd -t +sshd -t ``` 新的配置文件生效,必须重启 sshd。 ```bash -$ sudo systemctl restart sshd +sudo systemctl restart sshd ``` ## sshd 的命令行配置项 @@ -365,7 +365,7 @@ sshd 命令有一些配置项。这些配置项在调用时指定,可以覆盖 `-d`参数用于显示 debug 信息。 ```bash -$ sshd -d +sshd -d ``` (2)`-D` @@ -373,7 +373,7 @@ $ sshd -d `-D`参数指定 sshd 不作为后台守护进程运行。 ```bash -$ sshd -D +sshd -D ``` (3)`-e` @@ -389,7 +389,7 @@ $ sshd -D `-h`参数用于指定密钥。 ```bash -$ sshd -h /usr/local/ssh/my_rsa_key +sshd -h /usr/local/ssh/my_rsa_key ``` (6)`-o` @@ -397,19 +397,19 @@ $ sshd -h /usr/local/ssh/my_rsa_key `-o`参数指定配置文件的一个配置项和对应的值。 ```bash -$ sshd -o "Port 2034" +sshd -o "Port 2034" ``` 配置项和对应值之间,可以使用等号。 ```bash -$ sshd -o "Port = 2034" +sshd -o "Port = 2034" ``` 如果省略等号前后的空格,也可以不使用引号。 ```bash -$ sshd -o Port=2034 +sshd -o Port=2034 ``` `-o`参数可以多个一起使用,用来指定多个配置关键字。 @@ -419,7 +419,7 @@ $ sshd -o Port=2034 `-p`参数指定 sshd 的服务端口。 ```bash -$ sshd -p 2034 +sshd -p 2034 ``` 上面命令指定 sshd 在`2034`端口启动。 @@ -427,10 +427,9 @@ $ sshd -p 2034 `-p`参数可以指定多个端口。 ```bash -$ sshd -p 2222 -p 3333 +sshd -p 2222 -p 3333 ``` (8)`-t` `-t`参数检查配置文件的语法是否正确。 - diff --git a/docs/安全/SSH/端口转发.md b/docs/安全/SSH/端口转发.md index 33a19b53..fac8023a 100644 --- a/docs/安全/SSH/端口转发.md +++ b/docs/安全/SSH/端口转发.md @@ -23,7 +23,7 @@ SSH 除了登录服务器,还有一大用途,就是作为加密通信的中 动态转发需要把本地端口绑定到 SSH 服务器。至于 SSH 服务器要去访问哪一个网站,完全是动态的,取决于原始通信,所以叫做动态转发。 ```bash -$ ssh -D local-port tunnel-host -N +ssh -D local-port tunnel-host -N ``` 上面命令中,`-D`表示动态转发,`local-port`是本地端口,`tunnel-host`是 SSH 服务器,`-N`表示这个 SSH 连接只进行端口转发,不登录远程 Shell,不能执行远程命令,只能充当隧道。 @@ -31,7 +31,7 @@ $ ssh -D local-port tunnel-host -N 举例来说,如果本地端口是`2121`,那么动态转发的命令就是下面这样。 ```bash -$ ssh -D 2121 tunnel-host -N +ssh -D 2121 tunnel-host -N ``` 注意,这种转发采用了 SOCKS5 协议。访问外部网站时,需要把 HTTP 请求转成 SOCKS5 协议,才能把本地端口的请求转发出去。 @@ -39,7 +39,7 @@ $ ssh -D 2121 tunnel-host -N 下面是 SSH 隧道建立后的一个使用实例。 ```bash -$ curl -x socks5://localhost:2121 http://www.example.com +curl -x socks5://localhost:2121 http://www.example.com ``` 上面命令中,curl 的`-x`参数指定代理服务器,即通过 SOCKS5 协议的本地`2121`端口,访问`http://www.example.com`。 @@ -57,7 +57,7 @@ DynamicForward tunnel-host:local-port 它会指定一个本地端口(local-port),所有发向那个端口的请求,都会转发到 SSH 跳板机(tunnel-host),然后 SSH 跳板机作为中介,将收到的请求发到目标服务器(target-host)的目标端口(target-port)。 ```html -$ ssh -L local-port:target-host:target-port tunnel-host +ssh -L local-port:target-host:target-port tunnel-host ``` 上面命令中,`-L`参数表示本地转发,`local-port`是本地端口,`target-host`是你想要访问的目标服务器,`target-port`是目标服务器的端口,`tunnel-host`是 SSH 跳板机。 @@ -65,13 +65,13 @@ $ ssh -L local-port:target-host:target-port tunnel-host 举例来说,现在有一台 SSH 跳板机`tunnel-host`,我们想要通过这台机器,在本地`2121`端口与目标网站`www.example.com`的80端口之间建立 SSH 隧道,就可以写成下面这样。 ```bash -$ ssh -L 2121:www.example.com:80 tunnel-host -N +ssh -L 2121:www.example.com:80 tunnel-host -N ``` 然后,访问本机的`2121`端口,就是访问`www.example.com`的80端口。 ```bash -$ curl http://localhost:2121 +curl http://localhost:2121 ``` 注意,本地端口转发采用 HTTP 协议,不用转成 SOCKS5 协议。 @@ -79,7 +79,7 @@ $ curl http://localhost:2121 另一个例子是加密访问邮件获取协议 POP3。 ```bash -$ ssh -L 1100:mail.example.com:110 mail.example.com +ssh -L 1100:mail.example.com:110 mail.example.com ``` 上面命令将本机的1100端口,绑定邮件服务器`mail.example.com`的110端口(POP3 协议的默认端口)。端口转发建立以后,POP3 邮件客户端只需要访问本机的1100端口,请求就会通过 SSH 跳板机(这里是`mail.example.com`),自动转发到`mail.example.com`的110端口。 @@ -87,7 +87,7 @@ $ ssh -L 1100:mail.example.com:110 mail.example.com 上面这种情况有一个前提条件,就是`mail.example.com`必须运行 SSH 服务器。否则,就必须通过另一台 SSH 服务器中介,执行的命令要改成下面这样。 ```bash -$ ssh -L 1100:mail.example.com:110 other.example.com +ssh -L 1100:mail.example.com:110 other.example.com ``` 上面命令中,本机的1100端口还是绑定`mail.example.com`的110端口,但是由于`mail.example.com`没有运行 SSH 服务器,所以必须通过`other.example.com`中介。本机的 POP3 请求通过1100端口,先发给`other.example.com`的22端口(sshd 默认端口),再由后者转给`mail.example.com`,得到数据以后再原路返回。 @@ -110,7 +110,7 @@ LocalForward client-IP:client-port server-IP:server-port 它跟本地转发正好反过来。建立本地计算机到远程计算机的 SSH 隧道以后,本地转发是通过本地计算机访问远程计算机,而远程转发则是通过远程计算机访问本地计算机。它的命令格式如下。 ```bash -$ ssh -R remote-port:target-host:target-port -N remotehost +ssh -R remote-port:target-host:target-port -N remotehost ``` 上面命令中,`-R`参数表示远程端口转发,`remote-port`是远程计算机的端口,`target-host`和`target-port`是目标服务器及其端口,`remotehost`是远程计算机。 @@ -120,7 +120,7 @@ $ ssh -R remote-port:target-host:target-port -N remotehost 第一个例子是内网某台服务器`localhost`在 80 端口开了一个服务,可以通过远程转发将这个 80 端口,映射到具有公网 IP 地址的`my.public.server`服务器的 8080 端口,使得访问`my.public.server:8080`这个地址,就可以访问到那台内网服务器的 80 端口。 ```bash -$ ssh -R 8080:localhost:80 -N my.public.server +ssh -R 8080:localhost:80 -N my.public.server ``` 上面命令是在内网`localhost`服务器上执行,建立从`localhost`到`my.public.server`的 SSH 隧道。运行以后,用户访问`my.public.server:8080`,就会自动映射到`localhost:80`。 @@ -130,7 +130,7 @@ $ ssh -R 8080:localhost:80 -N my.public.server 由于本机无法访问内网 SSH 跳板机,就无法从外网发起 SSH 隧道,建立端口转发。必须反过来,从 SSH 跳板机发起隧道,建立端口转发,这时就形成了远程端口转发。跳板机执行下面的命令,绑定本地计算机`local`的`2121`端口,去访问`my.private.server:80`。 ```bash -$ ssh -R 2121:my.private.server:80 -N local +ssh -R 2121:my.private.server:80 -N local ``` 上面命令是在 SSH 跳板机上执行的,建立跳板机到`local`的隧道,并且这条隧道的出口映射到`my.private.server:80`。 @@ -140,7 +140,7 @@ $ ssh -R 2121:my.private.server:80 -N local 执行上面的命令以后,跳板机到`local`的隧道已经建立了。然后,就可以从本地计算机访问目标服务器了,即在本机执行下面的命令。 ```bash -$ curl http://localhost:2121 +curl http://localhost:2121 ``` 本机执行上面的命令以后,就会输出服务器`my.private.server`的 80 端口返回的内容。 @@ -171,7 +171,7 @@ $ ssh -R remote-port:target-host:target-port -N test.example.com VPN 用来在外网与内网之间建立一条加密通道。内网的服务器不能从外网直接访问,必须通过一个跳板机,如果本机可以访问跳板机,就可以使用 SSH 本地转发,简单实现一个 VPN。 ```bash -$ ssh -L 2080:corp-server:80 -L 2443:corp-server:443 tunnel-host -N +ssh -L 2080:corp-server:80 -L 2443:corp-server:443 tunnel-host -N ``` 上面命令通过 SSH 跳板机,将本机的`2080`端口绑定内网服务器的`80`端口,本机的`2443`端口绑定内网服务器的`443`端口。 @@ -183,7 +183,7 @@ $ ssh -L 2080:corp-server:80 -L 2443:corp-server:443 tunnel-host -N 首先,在本机新建第一级隧道。 ```bash -$ ssh -L 7999:localhost:2999 tunnel1-host +ssh -L 7999:localhost:2999 tunnel1-host ``` 上面命令在本地`7999`端口与`tunnel1-host`之间建立一条隧道,隧道的出口是`tunnel1-host`的`localhost:2999`,也就是`tunnel1-host`收到本机的请求以后,转发给自己的`2999`端口。 @@ -191,7 +191,7 @@ $ ssh -L 7999:localhost:2999 tunnel1-host 然后,在第一台跳板机(`tunnel1-host`)执行下面的命令,新建第二级隧道。 ```bash -$ ssh -L 2999:target-host:7999 tunnel2-host -N +ssh -L 2999:target-host:7999 tunnel2-host -N ``` 上面命令将第一台跳板机`tunnel1-host`的`2999`端口,通过第二台跳板机`tunnel2-host`,连接到目标服务器`target-host`的`7999`端口。 @@ -201,4 +201,3 @@ $ ssh -L 2999:target-host:7999 tunnel2-host -N ## 参考链接 - [An Illustrated Guide to SSH Tunnels](https://solitum.net/posts/an-illustrated-guide-to-ssh-tunnels/), Scott Wiersdorf - diff --git a/docs/安全/SSH/简介.md b/docs/安全/SSH/简介.md index 62de4854..7643a3e4 100644 --- a/docs/安全/SSH/简介.md +++ b/docs/安全/SSH/简介.md @@ -33,4 +33,4 @@ SSH 的软件架构是服务器-客户端模式(Server - Client)。在这个 本教程约定,大写的 SSH 表示协议,小写的 ssh 表示客户端软件。 -另外,OpenSSH 还提供一些辅助工具软件(比如 ssh-keygen 、ssh-agent)和专门的客户端工具(比如 scp 和 sftp),这个教程也会予以介绍。 \ No newline at end of file +另外,OpenSSH 还提供一些辅助工具软件(比如 ssh-keygen 、ssh-agent)和专门的客户端工具(比如 scp 和 sftp),这个教程也会予以介绍。 diff --git a/docs/安全/SSH/证书登录.md b/docs/安全/SSH/证书登录.md index 6d989714..bd3f50a4 100644 --- a/docs/安全/SSH/证书登录.md +++ b/docs/安全/SSH/证书登录.md @@ -86,7 +86,7 @@ $ ssh-keygen -t rsa -b 4096 -f host_ca -C host_ca 签发证书,除了 CA 的密钥以外,还需要服务器的公钥。一般来说,SSH 服务器(通常是`sshd`)安装时,已经生成密钥`/etc/ssh/ssh_host_rsa_key`了。如果没有的话,可以用下面的命令生成。 ```bash -$ sudo ssh-keygen -f /etc/ssh/ssh_host_rsa_key -b 4096 -t rsa +sudo ssh-keygen -f /etc/ssh/ssh_host_rsa_key -b 4096 -t rsa ``` 上面命令会在`/etc/ssh`目录,生成`ssh_host_rsa_key`(私钥)和`ssh_host_rsa_key.pub`(公钥)。然后,需要把服务器公钥`ssh_host_rsa_key.pub`,复制或上传到 CA 所在的服务器。 @@ -94,7 +94,7 @@ $ sudo ssh-keygen -f /etc/ssh/ssh_host_rsa_key -b 4096 -t rsa 上传以后,CA 就可以使用密钥`host_ca`为服务器的公钥`ssh_host_rsa_key.pub`签发服务器证书。 ```bash -$ ssh-keygen -s host_ca -I host.example.com -h -n host.example.com -V +52w ssh_host_rsa_key.pub +ssh-keygen -s host_ca -I host.example.com -h -n host.example.com -V +52w ssh_host_rsa_key.pub ``` 上面的命令会生成服务器证书`ssh_host_rsa_key-cert.pub`(服务器公钥名字加后缀`-cert`)。这个命令各个参数的含义如下。 @@ -109,13 +109,13 @@ $ ssh-keygen -s host_ca -I host.example.com -h -n host.example.com -V +52w ssh_h 生成证书以后,可以使用下面的命令,查看证书的细节。 ```bash -$ ssh-keygen -L -f ssh_host_rsa_key-cert.pub +ssh-keygen -L -f ssh_host_rsa_key-cert.pub ``` 最后,为证书设置权限。 ```bash -$ chmod 600 ssh_host_rsa_key-cert.pub +chmod 600 ssh_host_rsa_key-cert.pub ``` ## CA 签发用户证书 @@ -123,7 +123,7 @@ $ chmod 600 ssh_host_rsa_key-cert.pub 下面,再用 CA 签发用户证书。这时需要用户的公钥,如果没有的话,客户端可以用下面的命令生成一对密钥。 ```bash -$ ssh-keygen -f ~/.ssh/user_key -b 4096 -t rsa +ssh-keygen -f ~/.ssh/user_key -b 4096 -t rsa ``` 上面命令会在`~/.ssh`目录,生成`user_key`(私钥)和`user_key.pub`(公钥)。 @@ -131,7 +131,7 @@ $ ssh-keygen -f ~/.ssh/user_key -b 4096 -t rsa 然后,将用户公钥`user_key.pub`,上传或复制到 CA 服务器。接下来,就可以使用 CA 的密钥`user_ca`为用户公钥`user_key.pub`签发用户证书。 ```bash -$ ssh-keygen -s user_ca -I user@example.com -n user -V +1d user_key.pub +ssh-keygen -s user_ca -I user@example.com -n user -V +1d user_key.pub ``` 上面的命令会生成用户证书`user_key-cert.pub`(用户公钥名字加后缀`-cert`)。这个命令各个参数的含义如下。 @@ -145,13 +145,13 @@ $ ssh-keygen -s user_ca -I user@example.com -n user -V +1d user_key.pub 生成证书以后,可以使用下面的命令,查看证书的细节。 ```bash -$ ssh-keygen -L -f user_key-cert.pub +ssh-keygen -L -f user_key-cert.pub ``` 最后,为证书设置权限。 ```bash -$ chmod 600 user_key-cert.pub +chmod 600 user_key-cert.pub ``` ## 服务器安装证书 @@ -159,7 +159,7 @@ $ chmod 600 user_key-cert.pub CA 生成服务器证书`ssh_host_rsa_key-cert.pub`以后,需要将该证书发回服务器,可以使用下面的`scp`命令,将证书拷贝过去。 ```bash -$ scp ~/.ssh/ssh_host_rsa_key-cert.pub root@host.example.com:/etc/ssh/ +scp ~/.ssh/ssh_host_rsa_key-cert.pub root@host.example.com:/etc/ssh/ ``` 然后,将下面一行添加到服务器配置文件`/etc/ssh/sshd_config`。 @@ -183,7 +183,7 @@ $ sudo service sshd restart 为了让服务器信任用户证书,必须将 CA 签发用户证书的公钥`user_ca.pub`,拷贝到服务器。 ```bash -$ scp ~/.ssh/user_ca.pub root@host.example.com:/etc/ssh/ +scp ~/.ssh/user_ca.pub root@host.example.com:/etc/ssh/ ``` 上面的命令,将 CA 签发用户证书的公钥`user_ca.pub`,拷贝到 SSH 服务器的`/etc/ssh`目录。 @@ -233,7 +233,7 @@ $ sudo service sshd restart 然后,就可以使用证书,登录远程服务器了。 ```bash -$ ssh -i ~/.ssh/user_key user@host.example.com +ssh -i ~/.ssh/user_key user@host.example.com ``` 上面命令的`-i`参数用来指定用户的密钥。如果证书与密钥在同一个目录,则连接服务器时将自动使用该证书。 @@ -253,7 +253,7 @@ RevokedKeys /etc/ssh/revoked_keys `revoked_keys`文件保存不再信任的用户公钥,由下面的命令生成。 ```bash -$ ssh-keygen -kf /etc/ssh/revoked_keys -z 1 ~/.ssh/user1_key.pub +ssh-keygen -kf /etc/ssh/revoked_keys -z 1 ~/.ssh/user1_key.pub ``` 上面命令中,`-z`参数用来指定用户公钥保存在`revoked_keys`文件的哪一行,这个例子是保存在第1行。 @@ -261,7 +261,7 @@ $ ssh-keygen -kf /etc/ssh/revoked_keys -z 1 ~/.ssh/user1_key.pub 如果以后需要废除其他的用户公钥,可以用下面的命令保存在第2行。 ```bash -$ ssh-keygen -ukf /etc/ssh/revoked_keys -z 2 ~/.ssh/user2_key.pub +ssh-keygen -ukf /etc/ssh/revoked_keys -z 2 ~/.ssh/user2_key.pub ``` ## 参考链接 @@ -269,4 +269,3 @@ $ ssh-keygen -ukf /etc/ssh/revoked_keys -z 2 ~/.ssh/user2_key.pub - [SSH Emergency Access](https://smallstep.com/blog/ssh-emergency-access/), Carl Tashian - [Using OpenSSH Certificate Authentication](https://access.redhat.com/documentation/en-us/red_hat_enterprise_linux/6/html/deployment_guide/sec-using_openssh_certificate_authentication), Red Hat Enterprise Linux Deployment Guide - [How to SSH Properly](https://gravitational.com/blog/how-to-ssh-properly/), Gus Luxton - diff --git a/docs/开发/C++/函数方法.md b/docs/开发/C++/函数方法.md index 5124e11e..af2f2efe 100644 --- a/docs/开发/C++/函数方法.md +++ b/docs/开发/C++/函数方法.md @@ -301,4 +301,3 @@ Lambda 表达式把函数看作对象。Lambda 表达式可以像对象一样使 // 实例 [](int x, int y){ return x < y ; } ``` - diff --git a/docs/开发/C++/基本语法.md b/docs/开发/C++/基本语法.md index 07cfb5e9..5c122907 100644 --- a/docs/开发/C++/基本语法.md +++ b/docs/开发/C++/基本语法.md @@ -91,7 +91,7 @@ C++ 允许在 **char、int 和 double** 数据类型前放置修饰符。修饰 | volatile | 修饰符 **volatile** 告诉编译器,变量的值可能以程序未明确指定的方式被改变。 | | restrict | 由 **restrict** 修饰的指针是唯一一种访问它所指向的对象的方式。只有 C99 增加了新的类型限定符 restrict。 | -### typedef +### typedef 可以使用 **typedef** 为一个已有的类型取一个新的名字。 @@ -128,8 +128,6 @@ C++ 不同于 Java,变量的大小会根据编译器和所使用的电脑而 | long double | 8 个字节 | +/- 1.7e +/- 308 (~15 个数字) | | wchar_t | 2 或 4 个字节 | 1 个宽字符 | -### 实例 - ```cpp // 输出电脑上各种数据类型的大小 #include @@ -137,15 +135,15 @@ using namespace std; int main(){ short int i; // 有符号短整数 - short unsigned int j; // 无符号短整数 + short unsigned int j; // 无符号短整数 - cout << "Size of char : " << sizeof(char) << endl; - cout << "Size of int : " << sizeof(int) << endl; - cout << "Size of short int : " << sizeof(short int) << endl; - cout << "Size of long int : " << sizeof(long int) << endl; - cout << "Size of float : " << sizeof(float) << endl; - cout << "Size of double : " << sizeof(double) << endl; - cout << "Size of wchar_t : " << sizeof(wchar_t) << endl; return 0; + cout << "Size of char : " << sizeof(char) << endl; + cout << "Size of int : " << sizeof(int) << endl; + cout << "Size of short int : " << sizeof(short int) << endl; + cout << "Size of long int : " << sizeof(long int) << endl; + cout << "Size of float : " << sizeof(float) << endl; + cout << "Size of double : " << sizeof(double) << endl; + cout << "Size of wchar_t : " << sizeof(wchar_t) << endl; return 0; } ``` diff --git a/docs/开发/C++/控制语句.md b/docs/开发/C++/控制语句.md index ff2fecf6..71672529 100644 --- a/docs/开发/C++/控制语句.md +++ b/docs/开发/C++/控制语句.md @@ -13,7 +13,7 @@ data: 2022年4月28日 C 语言把任何**非零**和**非空**的值假定为 **true**,把**零**或 **null** 假定为 **false**。 -```c++ +```cpp if (boolean_expression) { // 如果布尔表达式为真将执行的语句 @@ -48,7 +48,7 @@ a 的值是 10 如果布尔表达式为 **true**,则执行 **if** 块内的代码。如果布尔表达式为 **false**,则执行 **else** 块内的代码。 -```c++ +```cpp if (boolean_expression) { // 如果布尔表达式为真将执行的语句 @@ -98,7 +98,7 @@ a 的值是 100 - 一个 if 后可跟零个或多个 else if,else if 必须在 else 之前。 - 一旦某个 else if 匹配成功,其他的 else if 或 else 将不会被测试。 -```c++ +```cpp // 语法 if(boolean_expression 1) { @@ -163,7 +163,7 @@ a 的准确值是 100 #### 语法 -```c++ +```cpp switch(expression){ case constant-expression : statement(s); @@ -194,7 +194,7 @@ switch(expression){ #### 实例 -```C++ +```cpp // 实例 #include using namespace std; @@ -236,7 +236,7 @@ int main () ### while 循环语句 -```c++ +```cpp // 语法 while(condition) { @@ -279,7 +279,7 @@ a 的值: 19 **do...while** 循环与 while 循环类似,但是 do...while 循环会确保至少执行一次循环。 -```C++ +```cpp // 语法 do { @@ -323,23 +323,19 @@ a 的值: 19 **for** 循环允许您编写一个执行特定次数的循环的重复控制结构 -#### 语法 - 1. **init** 会首先被执行,且只会执行一次。这一步允许您声明并初始化任何循环控制变量。您也可以不在这里写任何语句,只要有一个分号出现即可。 2. 接下来,会判断 **condition**。如果为真,则执行循环主体。如果为假,则不执行循环主体,且控制流会跳转到紧接着 for 循环的下一条语句。 3. 在执行完 for 循环主体后,控制流会跳回上面的 **increment** 语句。该语句允许您更新循环控制变量。该语句可以留空,只要在条件后有一个分号出现即可。 4. 条件再次被判断。如果为真,则执行循环,这个过程会不断重复(循环主体,然后增加步值,再然后重新判断条件)。在条件变为假时,for 循环终止。 -```c++ +```cpp for ( init; condition; increment ) { statement(s); } ``` -#### 实例 - -```c++ +```cpp #include using namespace std; @@ -374,15 +370,11 @@ a 的值: 19 1. 当 **break** 语句出现在一个循环内时,循环会立即终止,且程序流将继续执行紧接着循环的下一条语句。 2. 它可用于终止 **switch** 语句中的一个 case。 -#### 语法 - -```c++ +```cpp break; ``` -#### 实例 - -```c++ +```cpp #include using namespace std; @@ -411,15 +403,11 @@ int main () C++ 中的 **continue** 语句有点像 **break** 语句。但它不是强迫终止,continue 会跳过当前循环中的代码,强迫开始下一次循环。 -#### 语法 - -```c++ +```cpp continue; ``` -#### 实例 - -```c++ +```cpp #include using namespace std; @@ -451,18 +439,14 @@ int main () **在任何编程语言中,都不建议使用 goto 语句。因为它使得程序的控制流难以跟踪,使程序难以理解和难以修改。** -#### 语法 - -``` +```cpp goto label; .. . label: statement; ``` -#### 实例 - -```c++ +```cpp #include using namespace std; @@ -491,4 +475,3 @@ int main () ### return 语句 返回语句 - diff --git a/docs/开发/C++/简介.md b/docs/开发/C++/简介.md index d7169a44..7746e367 100644 --- a/docs/开发/C++/简介.md +++ b/docs/开发/C++/简介.md @@ -51,11 +51,11 @@ C++ 是 C 的一个超集,事实上,任何合法的 C 程序都是合法的 - **2014 年**,C++ 14(也称为 C++ 1y)作为 C++11 的一个小扩展发布,主要功能是错误修复和小的改进,国际标准投票程序草案于 2014 年 8 月中完成,加强 lambda 函数,constexpr 和类型推导特性。 - **2017 年**,发布 C17 标准,C17 提供了很多东西。增强了核心语言和库。 - **2020 年**,发布 C++20 标准,推出了很多重量级功能,其中比较重要的有: - - Concepts:概念改变了我们思考和编程模板的方式。它们是模板参数的语义类别。它们使您可以直接在类型系统中表达您的意图。如果出了什么问题,您会收到清晰的错误消息。 - - Ranges library:新的 ranges 库使它可以直接在容器上执行算法,用管道符号组成算法,并将其应用于无限数据流。 - - Coroutines:由于协程,C++ 中的异步编程成为主流。协程是协作任务,事件循环,无限数据流或管道的基础。 - - Modules:模块克服了头文件的限制。头文件和源文件的分离变得和预处理器一样过时了。最后,我们有更快的构建时间和更轻松的构建软件包的方法。 - - Concurrency:Atomic Smart Pointers,Joining & Cancellable Threads,The C20 Synchronization Library,增强了 C++ 并发编程能力; + - Concepts:概念改变了我们思考和编程模板的方式。它们是模板参数的语义类别。它们使您可以直接在类型系统中表达您的意图。如果出了什么问题,您会收到清晰的错误消息。 + - Ranges library:新的 ranges 库使它可以直接在容器上执行算法,用管道符号组成算法,并将其应用于无限数据流。 + - Coroutines:由于协程,C++ 中的异步编程成为主流。协程是协作任务,事件循环,无限数据流或管道的基础。 + - Modules:模块克服了头文件的限制。头文件和源文件的分离变得和预处理器一样过时了。最后,我们有更快的构建时间和更轻松的构建软件包的方法。 + - Concurrency:Atomic Smart Pointers,Joining & Cancellable Threads,The C20 Synchronization Library,增强了 C++ 并发编程能力; ### 面向对象 @@ -83,13 +83,13 @@ using namespace std; // main() 是程序开始执行的地方 int main(){ - // 输出 Hello World - cout << "Hello World"; - return 0; + // 输出 Hello World + cout << "Hello World"; + return 0; } ``` -1. C++ 语言定义了一些头文件,这些头文件包含了程序中必需的或有用的信息。上面这段程序中,包含了头文件 +1. C++ 语言定义了一些头文件,这些头文件包含了程序中必需的或有用的信息。上面这段程序中,包含了头文件 2. 行 **using namespace std;** 告诉编译器使用 std 命名空间。命名空间是 C++ 中一个相对新的概念。 @@ -106,7 +106,7 @@ int main(){ 程序 g++ 是将 gcc 默认语言设为 C++ 的一个特殊的版本,链接时它自动使用 C++ 标准库而不用 C 标准库。通过遵循源码的命名规范并指定对应库的名字,用 gcc 来编译链接 C++ 程序是可行的,如下例所示: ```cpp -$ gcc main.cpp -lstdc++ -o main +gcc main.cpp -lstdc++ -o main ``` 下面是一个保存在文件 helloworld.cpp 中一个简单的 C++ 程序的代码: @@ -120,31 +120,31 @@ $ gcc main.cpp -lstdc++ -o main 最简单的编译方式: ```cpp -$ g++ helloworld.cpp +g++ helloworld.cpp ``` 由于命令行中未指定可执行程序的文件名,编译器采用默认的 a.out。程序可以这样来运行: ```cpp -$ ./a.outHello, world! +./a.outHello, world! ``` 通常我们使用 **-o** 选项指定可执行程序的文件名,以下实例生成一个 helloworld 的可执行文件: ```cpp -$ g++ helloworld.cpp -o helloworld +g++ helloworld.cpp -o helloworld ``` 执行 helloworld: ```cpp -$ ./helloworldHello, world! +./helloworldHello, world! ``` 如果是多个 C++ 代码文件,如 runoob1.cpp、runoob2.cpp,编译命令如下: ```cpp -$ g++ runoob1.cpp cpp、runoob2.cpp -o runoob +g++ runoob1.cpp cpp、runoob2.cpp -o runoob ``` 生成一个 runoob 可执行文件。 @@ -155,7 +155,7 @@ g++ 有些系统默认是使用 C++98,我们可以指定使用 C++11 来编译 g++ -g -Wall -std=c++11 main.cpp ``` -**常用命令选项** +常用命令选项 | 选项 | 解释 | | ------------ | ------------------------------------------------------------ | diff --git a/docs/开发/C++/面对对象.md b/docs/开发/C++/面对对象.md index 1bb0fa50..59c10603 100644 --- a/docs/开发/C++/面对对象.md +++ b/docs/开发/C++/面对对象.md @@ -80,7 +80,7 @@ int main( ) **输出:** -``` +```text Box1 的体积:210 Box2 的体积:1560 ``` @@ -152,7 +152,7 @@ C::C( double a, double b, double c): X(a), Y(b), Z(c) **等同于:** -``` +```cpp C::C( double a, double b, double c) { X = a; @@ -238,7 +238,7 @@ int main( ) **输出:** -``` +```text 调用构造函数 调用拷贝构造函数并为指针 ptr 分配内存 line 大小 : 10 @@ -252,8 +252,6 @@ line 大小 : 10 析构函数的名称与类的名称是完全相同的,只是在前面加了个波浪号(~)作为前缀,它不会返回任何值,也不能带有任何参数。析构函数有助于在跳出程序(比如关闭文件、释放内存等)前释放资源。 -#### 实例 - ```cpp #include @@ -305,7 +303,7 @@ int main( ) **输出:** -``` +```text Object is being created Length of line : 6 Object is being deleted @@ -337,7 +335,7 @@ class Base { - **私有(private)成员**:私有成员变量或函数在类的外部是**不可访问、查看的**。只有类和友元函数可以访问私有成员。**默认情况下,类的所有成员都是私有的。** - **保护(protected)成员**:保护成员变量或函数与私有成员十分相似,但有一点不同,保护成员在派生类(即子类)中是可访问的。 -- +- ### 成员函数 @@ -510,7 +508,11 @@ int main( ) } ``` -**输出:Width of box : 10** +**输出:** + +```text +Width of box : 10 +``` ### 内联函数 @@ -601,7 +603,7 @@ int main(void) **输出:** -``` +```text Constructor called. Constructor called. Total objects: 2 @@ -675,7 +677,7 @@ int main(void) **输出:** -``` +```text Inital Stage Count: 0 Constructor called. Constructor called. @@ -737,7 +739,7 @@ int main(void) **输出:** -``` +```text Constructor called. Constructor called. Box2 is equal to or larger than Box1 @@ -797,7 +799,7 @@ int main(void) **输出:** -``` +```text Constructor called. Constructor called. Volume of Box1: 5.94 @@ -856,7 +858,7 @@ int main(void) **输出:** -``` +```text Constructor called. Constructor called. Volume of Box1: 5.94 @@ -907,7 +909,11 @@ int main( ) } ``` -**输出:Total 60** +**输出:** + +```text +Total 60 +``` ## 继承 @@ -920,7 +926,7 @@ class <派生类名>: <继承方式> <基类名> // 多继承 class <派生类名>:<继承方式1><基类名1>,<继承方式2><基类名2>,… { - <派生类类体> + <派生类类体> }; ``` @@ -988,7 +994,7 @@ int main(void) **输出:** -``` +```text Total area: 35 Total paint cost: $2450 ``` @@ -1089,7 +1095,7 @@ int main( ) **输出:** -``` +```text Parent class area Parent class area ``` @@ -1129,7 +1135,7 @@ Triangle class area 我们想要的是在程序中任意点可以根据所调用的对象类型来选择调用的函数,这种操作被称为**动态链接**,或**后期绑定**。 -**纯虚函数** +### 纯虚函数 您可能想要在基类中定义虚函数,以便在派生类中重新定义该函数更好地适用于对象,但是您在基类中又不能对虚函数给出有意义的实现,这个时候就会用到纯虚函数。 @@ -1190,7 +1196,7 @@ int main(void) **输出:** -``` +```text 整数为: 5 浮点数为: 500.263 字符串为: Hello C++ @@ -1285,7 +1291,7 @@ int main( ) **输出:** -``` +```text Volume of Box1 : 210 Volume of Box2 : 1560 Volume of Box3 : 5400 diff --git a/docs/开发/C/Enum 类型.md b/docs/开发/C/Enum 类型.md index 0553e6e0..775ed0d1 100644 --- a/docs/开发/C/Enum 类型.md +++ b/docs/开发/C/Enum 类型.md @@ -116,4 +116,3 @@ enum { ``` Enum 的作用域与变量相同。如果是在顶层声明,那么在整个文件内都有效;如果是在代码块内部声明,则只对该代码块有效。如果与使用`int`声明的常量相比,Enum 的好处是更清晰地表示代码意图。 - diff --git a/docs/开发/C/IO 函数.md b/docs/开发/C/IO 函数.md index 972e422d..e6346c8e 100644 --- a/docs/开发/C/IO 函数.md +++ b/docs/开发/C/IO 函数.md @@ -246,4 +246,3 @@ gets(words); 上面示例使用`puts()`在屏幕上输出提示,然后使用`gets()`获取用户的输入。 由于`gets()`获取的字符串,可能超过字符数组变量的最大长度,有安全风险,建议不要使用,改为使用`fgets()`。 - diff --git a/docs/开发/C/Struct 结构.md b/docs/开发/C/Struct 结构.md index d31e3571..b59abd98 100644 --- a/docs/开发/C/Struct 结构.md +++ b/docs/开发/C/Struct 结构.md @@ -439,4 +439,3 @@ str->len = n; 这样就可以让数组`chars`有`n`个成员,不用事先确定,可以跟运行时的需要保持一致。 弹性数组成员有一些专门的规则。首先,弹性成员的数组,必须是 struct 结构的最后一个属性。另外,除了弹性数组成员,struct 结构必须至少还有一个其他属性。 - diff --git a/docs/开发/C/Typedef 命令.md b/docs/开发/C/Typedef 命令.md index 643b66b8..8d3df108 100644 --- a/docs/开发/C/Typedef 命令.md +++ b/docs/开发/C/Typedef 命令.md @@ -182,4 +182,3 @@ Arr* x(void); - `x`是一个函数,返回一个指向 Arr 类型的指针。 - `Arr`是一个数组,有5个成员,每个成员是`Func`类型。 - `Func`是一个函数指针,指向一个无参数、返回字符值的函数。 - diff --git a/docs/开发/C/Union 结构.md b/docs/开发/C/Union 结构.md index 4f511e4f..ae1a8ab9 100644 --- a/docs/开发/C/Union 结构.md +++ b/docs/开发/C/Union 结构.md @@ -106,4 +106,3 @@ typedef union { 上面示例中,`union`命令定义了一个包含三个属性的数据类型,`typedef`命令为它起别名为`quantity`。 Union 结构的好处,主要是节省空间。它将一段内存空间,重用于不同类型的数据。定义了三个属性,但同一时间只用到一个,使用 Union 结构就可以节省另外两个属性的空间。Union 结构占用的内存长度,等于它内部最长属性的长度。 - diff --git a/docs/开发/C/函数.md b/docs/开发/C/函数.md index 5cbe7658..a57062c0 100644 --- a/docs/开发/C/函数.md +++ b/docs/开发/C/函数.md @@ -518,4 +518,3 @@ double average(int i, ...) { ``` 上面示例中,`va_list ap`定义`ap`为可变参数对象,`va_start(ap, i)`将参数`i`后面的参数统一放入`ap`,`va_arg(ap, double)`用来从`ap`依次取出一个参数,并且指定该参数为 double 类型,`va_end(ap)`用来清理可变参数对象。 - diff --git a/docs/开发/C/变量.md b/docs/开发/C/变量.md index 5a6a00cd..0cb0593a 100644 --- a/docs/开发/C/变量.md +++ b/docs/开发/C/变量.md @@ -171,4 +171,3 @@ printf("%d\n", i); // 出错 ``` 上面示例中,`for`循环省略了大括号,但依然是一个块作用域,在外部读取循环变量`i`,编译器就会报错。 - diff --git a/docs/开发/C/变量说明符.md b/docs/开发/C/变量说明符.md index e0619ab5..5da902d1 100644 --- a/docs/开发/C/变量说明符.md +++ b/docs/开发/C/变量说明符.md @@ -242,4 +242,3 @@ void swap(int* restrict a, int* restrict b) { ``` 上面示例中,函数参数声明里的`restrict`表示,参数`a`和参数`b`的内存地址没有重叠。 - diff --git a/docs/开发/C/命令行环境.md b/docs/开发/C/命令行环境.md index 7d32f6ee..caa242d3 100644 --- a/docs/开发/C/命令行环境.md +++ b/docs/开发/C/命令行环境.md @@ -10,7 +10,7 @@ data: 2022年3月30日 C 语言程序可以从命令行接收参数。 ```bash -$ ./foo hello world +./foo hello world ``` 上面示例中,程序`foo`接收了两个命令行参数`hello`和`world`。 @@ -116,4 +116,3 @@ int main(void) { ``` 上面示例中,`getenv("HOME")`用来获取命令行的环境变量`$HOME`,如果这个变量为空(`NULL`),则程序报错返回。 - diff --git a/docs/开发/C/多文件项目.md b/docs/开发/C/多文件项目.md index ddd04922..be3bfc2d 100644 --- a/docs/开发/C/多文件项目.md +++ b/docs/开发/C/多文件项目.md @@ -94,7 +94,7 @@ int add(int a, int b) { 现在重新编译,就可以顺利得到二进制可执行文件。 ```bash -$ gcc -o foo foo.c bar.c +gcc -o foo foo.c bar.c ``` ## 重复加载 @@ -224,7 +224,7 @@ $ make foo 如果省略了编译目标,`make`命令会执行第一条编译规则,构建相应的产物。 ```bash -$ make +make ``` 上面示例中,`make`后面没有编译目标,所以会执行 makefile 的第一条编译规则,本例是`make foo`。由于用户期望执行`make`后得到最终的可执行文件,所以建议总是把最终可执行文件的编译规则,放在 makefile 文件的第一条。makefile 本身对编译规则没有顺序要求。 @@ -234,4 +234,3 @@ make 命令的强大之处在于,它不是每次执行命令,都会进行编 举例来说,上次编译之后,修改了`foo.c`,没有修改`bar.c`和`bar.h`。于是,重新运行`make foo`命令时,Make 就会发现`bar.c`和`bar.h`没有变动过,因此不用重新编译`bar.o`,只需要重新编译`foo.o`。有了新的`foo.o`以后,再跟`bar.o`一起,重新编译成新的可执行文件`foo`。 Make 这样设计的最大好处,就是自动处理编译过程,只重新编译变动过的文件,因此大大节省了时间。 - diff --git a/docs/开发/C/指针.md b/docs/开发/C/指针.md index 7f15d44f..acbb134a 100644 --- a/docs/开发/C/指针.md +++ b/docs/开发/C/指针.md @@ -183,4 +183,3 @@ printf("%d\n", dist); // 1 (4)指针与指针的比较运算 指针之间的比较运算,比较的是各自的内存地址哪一个更大,返回值是整数`1`(true)或`0`(false)。 - diff --git a/docs/开发/C/数组.md b/docs/开发/C/数组.md index cd251cb6..59b43fe7 100644 --- a/docs/开发/C/数组.md +++ b/docs/开发/C/数组.md @@ -546,4 +546,3 @@ int sum = sum_array((int []){2, 3, 4, 5}, 4); ``` 上面示例中,两种写法是等价的。第二种写法省掉了数组变量的声明,直接将数组字面量传入函数。`{2, 3, 4, 5}`是数组值的字面量,`(int [])`类似于强制的类型转换,告诉编译器怎么理解这组值。 - diff --git a/docs/开发/C/文件操作.md b/docs/开发/C/文件操作.md index 237c6869..1928d39a 100644 --- a/docs/开发/C/文件操作.md +++ b/docs/开发/C/文件操作.md @@ -123,7 +123,7 @@ Linux 允许改变这三个文件指针(文件流)指向的文件,这称 如果标准输入不绑定键盘,而是绑定其他文件,可以在文件名前面加上小于号`<`,跟在程序名后面。这叫做“输入重定向”(input redirection)。 ```bash -$ demo < in.dat +demo < in.dat ``` 上面示例中,`demo`程序代码里面的`stdin`,将指向文件`in.dat`,即从`in.dat`获取数据。 @@ -131,7 +131,7 @@ $ demo < in.dat 如果标准输出绑定其他文件,而不是显示器,可以在文件名前加上大于号`>`,跟在程序名后面。这叫做“输出重定向”(output redirection)。 ```bash -$ demo > out.dat +demo > out.dat ``` 上面示例中,`demo`程序代码里面的`stdout`,将指向文件`out.dat`,即向`out.dat`写入数据。 @@ -139,7 +139,7 @@ $ demo > out.dat 输出重定向`>`会先擦去`out.dat`的所有原有的内容,然后再写入。如果希望写入的信息追加在`out.dat`的结尾,可以使用`>>`符号。 ```bash -$ demo >> out.dat +demo >> out.dat ``` 上面示例中,`demo`程序代码里面的`stdout`,将向文件`out.dat`写入数据。与`>`不同的是,写入的开始位置是`out.dat`的文件结尾。 @@ -147,7 +147,7 @@ $ demo >> out.dat 标准错误的重定向符号是`2>`。其中的`2`代表文件指针的编号,即`2>`表示将2号文件指针的写入,重定向到`err.txt`。2号文件指针就是标准错误`stderr`。 ```bash -$ demo > out.dat 2> err.txt +demo > out.dat 2> err.txt ``` 上面示例中,`demo`程序代码里面的`stderr`,会向文件`err.txt`写入报错信息。而`stdout`向文件`out.dat`写入。 @@ -164,7 +164,7 @@ $ demo > out.dat < in.dat 重定向还有另一种情况,就是将一个程序的标准输出`stdout`,指向另一个程序的标准输入`stdin`,这时要使用`|`符号。 ```bash -$ random | sum +random | sum ``` 上面示例中,`random`程序代码里面的`stdout`的写入,会从`sum`程序代码里面的`stdin`被读取。 @@ -633,7 +633,7 @@ int fseek(FILE* stream, long int offset, int whence); - `stream`:文件指针。 - `offset`:距离基准(第三个参数)的字节数。类型为 long int,可以为正值(向文件末尾移动)、负值(向文件开始处移动)或 0(保持不动)。 -- `whence`:位置基准,用来确定计算起点。它的值是以下三个宏(定义在`stdio.h`):`SEEK_SET`(文件开始处)、`SEEK_CUR `(内部指针的当前位置)、`SEEK_END`(文件末尾) +- `whence`:位置基准,用来确定计算起点。它的值是以下三个宏(定义在`stdio.h`):`SEEK_SET`(文件开始处)、`SEEK_CUR`(内部指针的当前位置)、`SEEK_END`(文件末尾) 请看下面的例子。 diff --git a/docs/开发/C/流程控制.md b/docs/开发/C/流程控制.md index 66663fa0..0933ed4f 100644 --- a/docs/开发/C/流程控制.md +++ b/docs/开发/C/流程控制.md @@ -97,7 +97,7 @@ if (number > 6) { 上面示例中,使用了大括号,就可以清晰地看出`else`匹配外层的`if`。 -## 三元运算符 ?: +## 三元运算符 ? C 语言有一个三元表达式`?:`,可以用作`if...else`的简写形式。 @@ -438,4 +438,3 @@ if (do_something4() == ERR) 上面示例有四个判断,只要有一个发现错误,就使用 goto 跳过后面的判断。 注意,goto 只能在同一个函数之中跳转,并不能跳转到其他函数。 - diff --git a/docs/开发/C/简介.md b/docs/开发/C/简介.md index ce5b5eb2..e023e7c4 100644 --- a/docs/开发/C/简介.md +++ b/docs/开发/C/简介.md @@ -93,8 +93,8 @@ C 语言是一种编译型语言,源码都是文本文件,本身无法执行 目前,最常见的 C 语言编译器是自由软件基金会推出的 GCC 编译器,它可以免费使用。本书也使用这个编译器。Linux 和 Mac 系统可以直接安装 GCC,Windows 系统可以安装 MinGW。但是,也可以不用这么麻烦,网上有在线编译器,能够直接在网页上模拟运行 C 代码,查看结果,下面就是两个这样的工具。 -- CodingGround: https://tutorialspoint.com/compile_c_online.php -- OnlineGDB: https://onlinegdb.com/online_c_compiler +- CodingGround: +- OnlineGDB: 本书的例子都使用 GCC 在命令行进行编译。 @@ -116,7 +116,7 @@ int main(void) { 这里不讲解这些代码是什么意思,只是作为一个例子,让大家看看 C 代码应该怎么编译和运行。假设你已经安装好了 GCC 编译器,可以打开命令行,执行下面的命令。 ```Shell -$ gcc hello.cc +gcc hello.cc ``` 上面命令使用`gcc`编译器,将源文件`hello.c`编译成二进制代码。注意,`$`是命令行提示符,你真正需要输入的是`$`后面的部分。 @@ -130,8 +130,8 @@ Hello World GCC 的`-o`参数(output 的缩写)可以指定编译产物的文件名。 -``` -$ gcc -o hello hello.c +```shell +gcc -o hello hello.c ``` 上面命令的`-o hello`指定,编译产物的文件名为`hello`(取代默认的`a.out`)。编译后就会生成一个名叫`hello`的可执行文件,相当于为`a.out`指定了名称。执行该文件,也会得到同样的结果。 @@ -144,10 +144,9 @@ Hello World GCC 的`-std=`参数(standard 的缩写)还可以指定按照哪个 C 语言的标准进行编译。 ```shell -$ gcc -std=c99 hello.c +gcc -std=c99 hello.c ``` 上面命令指定按照 C99 标准进行编译。 注意,`-std`后面需要用`=`连接参数,而不是像上面的`-o`一样用空格,并且`=`前后也不能有多余的空格。 - diff --git a/docs/开发/C/语法.md b/docs/开发/C/语法.md index fb75cb4c..79e6768a 100644 --- a/docs/开发/C/语法.md +++ b/docs/开发/C/语法.md @@ -379,4 +379,3 @@ C 语言自带的所有这些功能,统称为“标准库”(standard librar ``` 注意,加载头文件的`#include`语句不需要分号结尾,详见《预处理器》一章。 - diff --git a/docs/开发/C/运算符.md b/docs/开发/C/运算符.md index 1430e9d3..414ef222 100644 --- a/docs/开发/C/运算符.md +++ b/docs/开发/C/运算符.md @@ -463,4 +463,3 @@ int x = (3 + 4) * 5; 上面示例中,由于添加了圆括号,加法会先于乘法进行运算。 完全记住所有运算符的优先级没有必要,解决方法是多用圆括号,防止出现意料之外的情况,也有利于提高代码的可读性。 - diff --git a/docs/开发/C/预处理器.md b/docs/开发/C/预处理器.md index af06ce80..8ea73cd5 100644 --- a/docs/开发/C/预处理器.md +++ b/docs/开发/C/预处理器.md @@ -262,7 +262,7 @@ printf("%s\n", X(1,2,3)); // Prints "1, 2, 3" GCC 的`-U`选项可以在命令行取消宏的定义,相当于`#undef`。 ```bash -$ gcc -ULIMIT foo.c +gcc -ULIMIT foo.c ``` 上面示例中的`-U`参数,取消了宏`LIMIT`,相当于源文件里面的`#undef LIMIT`。 @@ -290,7 +290,7 @@ $ gcc -ULIMIT foo.c GCC 编译器的`-I`参数,也可以用来指定`include`命令中用户文件的加载路径。 ```bash -$ gcc -Iinclude/ -o code code.c +gcc -Iinclude/ -o code code.c ``` 上面命令中,`-Iinclude/`指定从当前目录的`include`子目录里面,加载用户自己的文件。 @@ -357,7 +357,7 @@ printf("value of j : %d\n", j); GCC 的`-D`参数可以在编译时指定宏的值,因此可以很方便地打开调试开关。 ```bash -$ gcc -DDEBUG=1 foo.c +gcc -DDEBUG=1 foo.c ``` 上面示例中,`-D`参数指定宏`DEBUG`为`1`,相当于在代码中指定`#define DEBUG 1`。 @@ -588,4 +588,3 @@ newish.c:14:2: error: #error Not C11 ``` 上面示例让编译器以 C99 标准进行编译。 - diff --git a/docs/开发/Docker/Dockerfile 文件详解.md b/docs/开发/Docker/Dockerfile 文件详解.md index d8e3bcf0..cc52061f 100644 --- a/docs/开发/Docker/Dockerfile 文件详解.md +++ b/docs/开发/Docker/Dockerfile 文件详解.md @@ -16,8 +16,6 @@ Docker 可以通过读取 Dockerfile 中的指令自动构建镜像。 Dockerfil 变量前加 `\` 可以转义成普通字符串:``\$foo` or `\${foo}`,表示转换为`$foo`和`${foo}`文本字符串。 - - ## 二、FROM 初始化一个新的构建阶段,并设置基础映像: @@ -34,8 +32,6 @@ FROM [--platform=] [@] [AS ] - `tag`或`digest`值是可选的。如果您省略其中任何一个,构建器默认使用一个`latest`标签。如果找不到该`tag`值,构建器将返回错误。 - `--platform`标志可用于在`FROM`引用多平台镜像的情况下指定平台。例如:`linux/amd64`、`linux/arm64`、 或`windows/amd64` - - ## 三、RUN 将在当前镜像之上的新层中执行命令,在 docker build 时运行。 @@ -56,8 +52,6 @@ RUN 有两种形式: - `RUN`在下一次构建期间,指令缓存不会自动失效。可以使用`--no-cache`标志使指令缓存无效。 - Dockerfile 的指令每执行一次都会在 docker 上新建一层。所以过多无意义的层,会造成镜像膨胀过大,可以使用 **&&** 符号连接命令,这样执行后,只会创建 **1层** 镜像。 - - ## 四、CMD 运行程序,在 docker run 时运行,但是和 run 命令不同,RUN 是在 docker build 时运行。 @@ -77,8 +71,6 @@ CMD ["/usr/bin/wc","--help"] 如果用户启动容器时候指定了运行的命令,则会覆盖掉 `CMD` 指定的命令。 - - ## 五、LABEL 添加元数据: @@ -89,8 +81,6 @@ LABEL multi.label1="value1" \ other="value3" ``` - - ## 六、EXPOSE ```text @@ -107,8 +97,6 @@ Docker 容器在运行时侦听指定的网络端口。可以指定端口是监 EXPOSE 80/udp ``` - - ## 七、ENV 设置环境变量: @@ -132,8 +120,6 @@ ARG DEBIAN_FRONTEND=noninteractive RUN apt-get update && apt-get install -y ... ``` - - ## 八、ADD 复制新文件、目录或远程文件 URL `` ,并将它们添加到``中。 @@ -154,8 +140,6 @@ ADD hom?.txt /mydir/ ``是一个绝对路径,或相对`WORKDIR`的相对路径。 - - ## 九、COPY 语法同 ADD 一致,复制拷贝文件。 @@ -164,8 +148,6 @@ COPY 指令和 ADD 指令的唯一区别在于:是否支持从远程 URL 获 相同需求时,推荐使用 COPY 指令。ADD 指令更擅长读取本地 tar 文件并解压缩。 - - ## 十、ENTRYPOINT **ENTRYPOINT** 和 **CMD** 一样,都是在指定容器启动程序及参数,不过它不会被 docker run 的命令行参数指定的指令所覆盖。如果要覆盖的话,需要通过 docker run --entrypoint 来指定。 @@ -183,8 +165,6 @@ ENTRYPOINT command param1 param2 ``` - - ## 十一、VOLUME 创建一个具有指定名称的挂载数据卷。 @@ -224,8 +204,6 @@ Docker 有一组预定义的`ARG`变量,您可以在 Dockerfile 中没有相 docker build --build-arg HTTPS_PROXY=https://my-proxy.example.com . ``` - - ## 十三、ONBUILD 将一个触发指令添加到镜像中,以便稍后在该镜像用作另一个构建的基础时执行。也就是另外一个 dockerfile FROM 了这个镜像的时候执行。 @@ -235,8 +213,6 @@ ONBUILD ADD . /app/src ONBUILD RUN /usr/local/bin/python-build --dir /app/src ``` - - ## 十四、STOPSIGNAL 设置将发送到容器退出的系统调用信号。该信号可以是与内核系统调用表中的位置匹配的有效无符号数,例如 9,或格式为 SIGNAME 的信号名称,例如 SIGKILL。 @@ -247,8 +223,6 @@ STOPSIGNAL signal 默认的 stop-signal 是 **SIGTERM**,在 docker stop 的时候会给容器内 PID 为 1 的进程发送这个 signal,通过 --stop-signal 可以设置自己需要的 signal,主要目的是为了让容器内的应用程序在接收到 signal 之后可以先处理一些事物,实现容器的平滑退出,如果不做任何处理,容器将在一段时间之后强制退出,会造成业务的强制中断,默认时间是 10s。 - - ## 十五、HEALTHCHECK 用于指定某个程序或者指令来监控 docker 容器服务的运行状态。该`HEALTHCHECK`指令有两种形式: @@ -256,8 +230,6 @@ STOPSIGNAL signal - `HEALTHCHECK [OPTIONS] CMD command` (通过在容器内运行命令来检查容器健康状况) - `HEALTHCHECK NONE` (禁用从基础镜像继承的任何健康检查) - - ## 十六、SHELL 覆盖用于命令的 **shell** 形式的默认 shell。Linux 上的默认 shell 是`["/bin/sh", "-c"]`,Windows 上是`["cmd", "/S", "/C"]` @@ -268,8 +240,6 @@ SHELL ["executable", "parameters"] 该`SHELL`指令在 Windows 上特别有用,因为 Windows 有两种常用且截然不同的本机 shell:`cmd`和`powershell`,以及可用的备用 shell,包括`sh`。该 SHELL 指令可以出现多次。每条 SHELL 指令都会覆盖所有先前的 SHELL 指令,并影响所有后续指令。 - - ## 十七、WORKDIR 工作目录,如果`WORKDIR`不存在,即使它没有在后续`Dockerfile`指令中使用,它也会被创建。 @@ -297,8 +267,6 @@ RUN pwd 最终`pwd`命令的输出是`/path/$DIRNAME`。 - - ## 十八、USER 设置用户名(或 UID)和可选的用户组(或 GID) @@ -308,4 +276,4 @@ USER [:] USER [:] ``` -> Dockerfile文件全面详解 - 青火的文章 - 知乎 https://zhuanlan.zhihu.com/p/387855002 \ No newline at end of file +> Dockerfile文件全面详解 - 青火的文章 - 知乎 diff --git a/docs/开发/Git/分支.md b/docs/开发/Git/分支.md index 93c5a52d..da595a87 100644 --- a/docs/开发/Git/分支.md +++ b/docs/开发/Git/分支.md @@ -17,7 +17,7 @@ Git 的分支模型被称为它的「必杀技特性」,也正因为这一特 ### 创建分支 -``` +```shell // 创建分支 git branch ``` @@ -28,7 +28,7 @@ git branch 要切换到一个已存在的分支,你需要使用 git checkout 命令。 -``` +```shell // 切换到一个已存在的分支 git checkout @@ -38,21 +38,21 @@ git checkout -b ### 查看分支 -``` +```shell // 查看已创建的分支 git branch ``` ### 合并分支 -``` +```shell // 合并分支到当前分支。 git merge ``` ### 删除分支 -``` +```shell git branch -d ``` @@ -79,7 +79,7 @@ git branch -d 现在,你为实现某个新的需求,创建一个分支 iss53。 -``` +```shell git checkout -b iss53 ``` @@ -87,13 +87,13 @@ git checkout -b iss53 现在你接到那个电话,有个紧急问题等待你来解决,现在要做的就是切换回主分支。 -``` +```shell git checkout master ``` 接下来,你要修复这个紧急问题。新建一个 hotfix 分支,直至问题解决。 -``` +```shell git checkout -b hotfix ``` @@ -101,7 +101,7 @@ git checkout -b hotfix 然后将 hotfix 分支合并回你的 master 分支来部署线上。 -``` +```shell git checkout master git merge hotfix ``` @@ -110,7 +110,7 @@ git merge hotfix 此时,hotfix 分支已经不需要了,可以将它删除。 -``` +```shell git branch -d hotfix ``` @@ -118,7 +118,7 @@ git branch -d hotfix 假设这时你已经完成了 iss53 的需求,需要将 iss53 分支合并入 master 分支。 -``` +```shell git checkout master git merge iss53 ``` @@ -135,7 +135,7 @@ git merge iss53 出现冲突的文件会包含一些特殊区段像下面这个样子: -``` +```shell <<<<<<< HEAD:index.html ======= @@ -151,7 +151,7 @@ git merge iss53 如,你可以通过把这段内容换成下面的样子来解决冲突: -``` +```shell @@ -167,7 +167,7 @@ please contact us at email.support@github.com 当你想要公开分享一个分支时,需要将其推送到有写入权限的远程仓库上。 **本地的分支并不会自动与远程仓库同步——你必须显式地推送想要分享的分支。** -``` +```shell // 推送本地分支到正在跟踪远程分支 git push @@ -179,7 +179,7 @@ git push : 从一个远程跟踪分支检出一个本地分支会自动创建所谓的“跟踪分支”(它跟踪的分支叫做“上游分支”)。跟踪分支是与远程分支有直接关系的本地分支。 -``` +```shell // 从远程分支新建本地跟踪分支 git checkout --track / @@ -197,7 +197,7 @@ git branch -vv 当从服务器上抓取本地没有的数据时,可以运行 git fetch 或 git pull。推荐单独显式地使用 fetch 与 merge 命令。 -``` +```shell // 仅拉取默认远程分支数据,不进行自动合并。 git fetch @@ -207,7 +207,7 @@ git pull ### 删除远程分支 -``` +```shell git push --delete ``` @@ -215,14 +215,13 @@ git push --delete 你可以使用 rebase 命令将提交到某一分支上的所有修改都移至另一分支上,就好像“重新播放”一样。在 Git 中,这种操作就叫做 变基(rebase)。 -``` +```shell git rebase ``` 它的原理是首先找到这两个分支(假设当前分支 experiment、变基操作的目标基底分支 master) 的最近共同祖先,然后对比当前分支相对于该祖先的历次提交,提取相应的修改并存为临时文件, 然后将当前分支指向目标基底, 最后以此将之前另存为临时文件的修改依序应用。 - -``` +```shell // 1.切换 experiment 分支。 git checkout experiment @@ -245,7 +244,7 @@ git merge experiment 这时,你就可以使用 git rebase 命令的 --onto 选项, 选中在 client 分支里但不在 server 分支里的修改,将它们在 master 分支上重放。 -``` +```shell // 1. 取出 client 分支,找出它从 server 分支分歧之后的补丁。然后把这些补丁在master 分支上重放一遍,让 client 看起来像直接基于 master 修改一样。 git rebase --onto master server client @@ -258,7 +257,7 @@ git merge client 接下来你决定将 server 分支中的修改也整合进来。 -``` +```shell // 1.变基至 master分支 git rebase master server @@ -287,4 +286,4 @@ git merge server 现在,让我们回到之前的问题上来,到底合并还是变基好?希望你能明白,这并没有一个简单的答案。 Git 是一个非常强大的工具,它允许你对提交历史做许多事情,但每个团队、每个项目对此的需求并不相同。 既然你已经分别学习了两者的用法,相信你能够根据实际情况作出明智的选择。 -总的原则是,只对尚未推送或分享给别人的本地修改执行变基操作清理历史, 从不对已推送至别处的提交执行变基操作,这样,你才能享受到两种方式带来的便利。 \ No newline at end of file +总的原则是,只对尚未推送或分享给别人的本地修改执行变基操作清理历史, 从不对已推送至别处的提交执行变基操作,这样,你才能享受到两种方式带来的便利。 diff --git a/docs/开发/Git/基础.md b/docs/开发/Git/基础.md index 81b00995..e1ce3a2a 100644 --- a/docs/开发/Git/基础.md +++ b/docs/开发/Git/基础.md @@ -16,7 +16,7 @@ data: 2022年1月13日 ### 在目录中初始化仓库 -``` +```shell // 在当前目录初始化仓库 git init ``` @@ -27,14 +27,14 @@ git init 如果你想获得一份已经存在了的 Git 仓库的拷贝,比如说,你想为某个开源项目贡献自己的一份力,这时就要用到 git clone 命令。 -``` +```shell // 克隆远程仓库 git clone ``` 如果你想在克隆远程仓库的时候,自定义本地仓库的名字,你可以通过额外的参数指定新的目录名: -``` +```shell // 指定仓库本地命名 git clone ``` @@ -66,11 +66,11 @@ git clone - 匹配模式可以以(/)结尾指定目录。 - 要忽略指定模式以外的文件或目录,可以在模式前加上叹号(!)取反。 -> GitHub 有一个十分详细的针对数十种项目及语言的 .gitignore 文件列表, 你可以在 https://github.com/github/gitignore 找到它。 +> GitHub 有一个十分详细的针对数十种项目及语言的 .gitignore 文件列表, 你可以在 找到它。 ### 检查当前仓库状态 -``` +```shell // 查看当前仓库状态总览 git status @@ -88,7 +88,7 @@ git diff --cached ### 踪新文件或暂存已修改的文件 -``` +```shell // 添加文件到暂存区 git add @@ -98,7 +98,7 @@ git add ### 提交更新 -``` +```shell // 提交更新,同时会启动文本编辑器来输入提交说明。 git commit @@ -111,9 +111,9 @@ git commit -a ## 查看提交历史 -### git log 的常用选项 +### git log 的常用选项 -``` +```shell // 格式化输出一行显示提交历史 git log --oneline ``` @@ -133,7 +133,7 @@ git log --oneline ### git log --pretty=format 常用的选项 -``` +```shell // format 可以定制记录的显示格式 git log --pretty=format:"%h - %an, %ar : %s" ``` @@ -168,13 +168,12 @@ git log --pretty=format:"%h - %an, %ar : %s" | --grep | 仅显示提交说明中包含指定字符串的提交。 | | -S | 仅显示添加或删除内容匹配指定字符串的提交。 | - ## 撤消操作 有时候我们提交完了才发现漏掉了几个文件没有添加,或者提交信息写错了。 此时,可以运行带有 --amend 选 项的提交命令来重新提交: -``` +```shell // 撤销上次提交 git commit --amend ``` @@ -183,7 +182,7 @@ git commit --amend ### 撤销已暂存的文件 -``` +```shell // 取消暂存区文件 git reset HEAD ``` @@ -192,7 +191,7 @@ git reset 确实是个危险的命令,如果加上了 --hard 选项则更是 ### 撤消对文件的修改 -``` +```shell // 撤销工作区的文件修改 git checkout -- ``` @@ -202,7 +201,7 @@ git checkout -- ## 远程仓库 为了能在任意 Git 项目上协作,你需要知道如何管理自己的远程仓库。远程仓库是指托管在因特网或其他网络中 -的你的项目的版本库。 +的你的项目的版本库。 你可以有好几个远程仓库,通常有些仓库对你只读,有些则可以读写。 与他人协作涉及管理远程仓库以及根据需要推送或拉取数据。 管理远程仓库包括了解如何添加远程仓库、移除无效的远程仓库、管理不同的远程分支并定义它们是否被跟踪等等。 @@ -210,14 +209,14 @@ git checkout -- 可以运行 git remote 命令,查看你已经配置的远程仓库服务器。 -``` +```shell // 查看远程仓库 git remote ``` 你也可以指定选项 -v,会显示需要读写远程仓库使用的 Git 保存的简写与其对应的 URL -``` +```shell // 显示远程仓库简写及其 URL git remote -v ``` @@ -226,7 +225,7 @@ git remote -v 你可以运行 `git remote add ` 添加一个新的远程 Git 仓库,同时指定一个方便使用的简写: -``` +```shell // 添加一个新的远程 Git 仓库 git remote add ``` @@ -235,7 +234,7 @@ git remote add 当你添加远程仓库后,可以从远程仓库拉取数据。 -``` +```shell // 从远程仓库拉取数据,不自动合并。 git fetch @@ -247,7 +246,7 @@ git pull 当你想分享你的项目时,必须将其推送到上游。 -``` +```shell // 推送分支到远程仓库 git push ``` @@ -256,7 +255,7 @@ git push 你可以使用以下命令,对远程仓库进行查看、重命名与移除操作。 -``` +```shell // 查看远程仓库 git remote show @@ -281,7 +280,7 @@ Git 支持两种标签:**轻量标签(lightweight)**与**附注标签(an ### 创建标签 -``` +```shell // 创建轻量标签 git tag @@ -291,14 +290,14 @@ git tag -a 你也可以对过去的提交打标签。,只需要输入提交的 SHA-1 数。 -``` +```shell // 后期打标签 git tag ``` ### 查看标签 -``` +```shell // 列出已有的标签 git tag @@ -310,7 +309,7 @@ git show 默认情况下,git push 命令并不会传送标签到远程仓库服务器上。 在创建完标签后你必须显式地推送标签到共享服务器上。 -``` +```shell // 推送标签到远程仓库 git push origin @@ -320,7 +319,7 @@ git push origin --tags ### 删除标签 -``` +```shell // 删除标签 git tag -d @@ -333,11 +332,11 @@ git push origin --delete Git 并不会在你输入部分命令时自动推断出你想要的命令。 如果不想每次都输入完整的 Git 命令,可以通过 git config 文件来轻松地为每一个命令设置一个别名。如下: -``` +```shell git config --global alias.co checkout git config --global alias.br branch git config --global alias.ci commit git config --global alias.st status ``` -接下来我们就可以使用 git co 等价代替 git checkout,其他同理。 \ No newline at end of file +接下来我们就可以使用 git co 等价代替 git checkout,其他同理。 diff --git a/docs/开发/Git/工作流.md b/docs/开发/Git/工作流.md index 71ba1b02..41bf508d 100644 --- a/docs/开发/Git/工作流.md +++ b/docs/开发/Git/工作流.md @@ -49,7 +49,7 @@ Git 允许多个远程仓库存在,使得这样一种工作流成为可能: ### 提交准则 -``` +```shell 首字母大写的摘要(不多于 50 个字符) 如果必要的话,加入更详细的解释文字。在大概 72 个字符的时候换行。 @@ -96,16 +96,16 @@ Git 允许多个远程仓库存在,使得这样一种工作流成为可能: 型私有团队中贡献者基于特性进行协作,而这些团队的贡献将会由其他人整合。 -1. John 与 Jessica 在一个特性分支(featureA)上工作。 +1. John 与 Jessica 在一个特性分支(featureA)上工作。 2. Jessica 同时与第三个开发者 Josie 在第二个特性分支(featureB)上工作。 3. 公司使用了一种整合-管理者工作流程,独立小组的工作只能被特定的工程师整合, 主仓库的 master 分支只能被那些工程师更新。 -4. 在这种情况下,所有的工作都是在基于团队的分支上完成的,并且稍后会被整合者拉到一起。 +4. 在这种情况下,所有的工作都是在基于团队的分支上完成的,并且稍后会被整合者拉到一起。 ………… ### 派生的公开项目 -第一个例子描述在支持简单派生的 Git 托管上使用派生来做贡献。 许多托管站点支持这个功能(包括 GitHub、BitBucket、repo.or.cz 等等),许多项目维护者期望这种风格的贡献。 +第一个例子描述在支持简单派生的 Git 托管上使用派生来做贡献。 许多托管站点支持这个功能(包括 GitHub、BitBucket、repo.or.cz 等等),许多项目维护者期望这种风格的贡献。 第二个例子会讨论偏好通过邮件接受贡献补丁的项目。 @@ -113,7 +113,7 @@ Git 允许多个远程仓库存在,使得这样一种工作流成为可能: 首先,你可能想要克隆主仓库,为计划贡献的补丁或补丁序列创建一个主题分支,然后在那儿做工作。 -``` +```shell // 克隆远程仓库 git clone @@ -132,7 +132,7 @@ git commit 当你的分支工作完成后准备将其贡献回维护者,去原始项目中然后点击 Fork 按钮,创建一份自己的可写的项目派生仓库。 然后需要在本地仓库中将该仓库添加为一个新的远程仓库,在本例中称作 myfork: -``` +```shell // 添加 fork 仓库 git remote add myfork @@ -142,7 +142,7 @@ git push -u myfork featureA 当工作已经被推送到你的派生仓库后,你需要通知原项目的维护者你有想要他们合并的工作。 这通常被称作一个 拉取请求(Pull Request),**你通常可以通过网站生成它**。也可以运行 git request-pull 命令然后将随后的输出通过电子邮件手动发送给项目维护者。 -在一个你不是维护者的项目上,通常有一个总是跟踪 origin/master 的 master 分支会很方便,在主题分支上做工作是因为如果它们被拒绝时你可以轻松地丢弃。 如果同一时间主仓库移动了然后你的提交不再能干净地应用,那么使工作主题独立于主题分支也会使你变基(rebase)工作时更容易。 +在一个你不是维护者的项目上,通常有一个总是跟踪 origin/master 的 master 分支会很方便,在主题分支上做工作是因为如果它们被拒绝时你可以轻松地丢弃。 如果同一时间主仓库移动了然后你的提交不再能干净地应用,那么使工作主题独立于主题分支也会使你变基(rebase)工作时更容易。 例如,你想要提供第二个特性工作到项目,不要继续在刚刚推送的主题分支上工作——从主仓库的 master 分支重新开始: @@ -150,7 +150,7 @@ git push -u myfork featureA 首先,你要克隆主仓库,然后在那儿做工作。 -``` +```shell // 克隆远程仓库 git clone @@ -169,7 +169,7 @@ git commit 现在有两个提交要发送到邮件列表。 使用 git format-patch 来生成可以邮寄到列表的 mbox 格式的文件——它将每一个提交转换为一封电子邮件,提交信息的第一行作为主题,剩余信息与提交引入的补丁作为正文。 -``` +```shell git format-patch -M origin/master // 补丁文件 @@ -179,7 +179,7 @@ git format-patch -M origin/master 为了将其邮寄到邮件列表,你既可以将文件粘贴进电子邮件客户端,也可以通过命令行程序发送它。 -``` +```shell // 本地邮件服务器设置正确的前提下,使用此命令。 git send-email .patch ``` @@ -198,7 +198,7 @@ git send-email .patch 如果你收到了一个使用 git diff 或 Unix diff 命令的变体(不推荐使用这种方式,具体见下一小节) 创建的补丁,可以使用 git apply 命令来应用。 假设你将补丁保存在了 /tmp/patch-ruby-client.patch 中,可以这样应用补丁: -``` +```shell git apply /tmp/patch-ruby-client.patch ``` @@ -208,7 +208,7 @@ git apply /tmp/patch-ruby-client.patch 要应用一个由 format-patch 命令生成的补丁,你应该使用 git am 命令。 -``` +```shell git am .patch ``` @@ -228,7 +228,7 @@ Git 项目包含四个长期分支:master、next,用于新工作的 pu(pro #### 变基与拣选工作流 -为了保持线性的提交历史,有些维护者更喜欢在 master 分支上对贡献过来的工作进行变基和拣选,而不是直接将其合并。 当你完成了某个主题分支中的工作,并且决定要将其整合的时候,你可以在该分支中运行变基命令, 在当前 master 分支(或者是 develop 等分支)的基础上重新构造修改。 +为了保持线性的提交历史,有些维护者更喜欢在 master 分支上对贡献过来的工作进行变基和拣选,而不是直接将其合并。 当你完成了某个主题分支中的工作,并且决定要将其整合的时候,你可以在该分支中运行变基命令, 在当前 master 分支(或者是 develop 等分支)的基础上重新构造修改。 #### 为发布打标签 @@ -238,7 +238,7 @@ Git 项目包含四个长期分支:master、next,用于新工作的 pu(pro Git 中不存在随每次提交递增的 v123 之类的数字序列,如果你想要为提交附上一个可读的名称, 可以对其运行 git describe 命令。作为回应,Git 将会生成一个字符串, 它由最近的标签名、自该标签之后的提交数目和你所描述的提交的部分 SHA-1 值(前缀的 g 表示 Git)构成: -``` +```shell git describe master v1.6.2-rc1-20-g8c5b85c ``` @@ -248,7 +248,7 @@ v1.6.2-rc1-20-g8c5b85c 现在你可以发布一个构建了。 其中一件事情就是为那些不使用 Git 的可怜包们创建一个最新的快照归档。 使用 git archive 命令完成此工作: -``` +```shell git archive master > archive.zip ``` @@ -256,7 +256,7 @@ git archive master > archive.zip 现在是时候通知邮件列表里那些好奇你的项目发生了什么的人了。 使用 git shortlog 命令可以快速生成一份包含从上次发布之后项目新增内容的修改日志(changelog)类文档。 -``` +```shell // 包括了自 v1.0.1 以来的所有提交 git shortlog --no-merges master --not v1.0.1 -``` \ No newline at end of file +``` diff --git a/docs/开发/Git/服务.md b/docs/开发/Git/服务.md index d904051f..5f3e6154 100644 --- a/docs/开发/Git/服务.md +++ b/docs/开发/Git/服务.md @@ -29,11 +29,11 @@ Git 可以使用四种不同的协议来传输资料: 最基本的就是 本地协议(Local protocol),其中的远程版本库就是同一主机上的另一个目录。 这常见于团队每一个成员都对一个共享的文件系统(例如一个挂载的 NFS)拥有访问权,或者比较少见的多人共用同一台电脑的情况。 后者并不理想,因为你的所有代码版本库如果长存于同一台电脑,更可能发生灾难性的损失。 -**优点** +- 优点 基于文件系统的版本库的优点是简单,并且直接使用了现有的文件权限和网络访问权限。 如果你的团队已经有共享文件系统,建立版本库会十分容易。 只需要像设置其他共享目录一样,把一个裸版本库的副本放到大家都可以访问的路径,并设置好读/写的权限,就可以了, 我们会在在服务器上搭建 Git 讨论如何导出一个裸版本库。这也是快速从别人的工作目录中拉取更新的方法。 如果你和别人一起合作一个项目,他想让你从版本库中拉取更新时,运行类似 git pull /home/john/project 的命令比推送到服务器再抓取回来简单多了。 -**缺点** +- 缺点 这种方法的缺点是,通常共享文件系统比较难配置,并且比起基本的网络连接访问,这不方便从多个位置访问。如果你想从家里推送内容,必须先挂载一个远程磁盘,相比网络连接的访问方式,配置不方便,速度也慢。值得一提的是,如果你使用的是类似于共享挂载的文件系统时,这个方法不一定是最快的。 访问本地版本库的速度与你访问数据的速度是一样的。 在同一个服务器上,如果允许 Git 访问本地硬盘,一般的通过 NFS 访问版本库要比通过 SSH 访问慢。最终,这个协议并不保护仓库避免意外的损坏。 每一个用户都有“远程”目录的完整 shell 权限,没有方法可以阻止他们修改或删除 Git 内部文件和损坏仓库。 @@ -47,13 +47,13 @@ Git 通过 HTTP 通信有两种模式:**智能 HTTP 协议、哑(Dumb) HTT #### 哑(Dumb) HTTP 协议 -如果服务器没有提供智能 HTTP 协议的服务,Git 客户端会尝试使用更简单的“哑” HTTP 协议。 哑 HTTP 协议里 web 服务器仅把裸版本库当作普通文件来对待,提供文件服务。 哑 HTTP 协议的优美之处在于设置起来简单。 +如果服务器没有提供智能 HTTP 协议的服务,Git 客户端会尝试使用更简单的“哑” HTTP 协议。 哑 HTTP 协议里 web 服务器仅把裸版本库当作普通文件来对待,提供文件服务。 哑 HTTP 协议的优美之处在于设置起来简单。 -**优点** +- 优点 我们将只关注智能 HTTP 协议的优点。不同的访问方式只需要一个 URL 以及服务器只在需要授权时提示输入授权信息,这两个简便性让终端用户使用 Git 变得非常简单。 相比 SSH 协议,可以使用用户名/密码授权是一个很大的优势,这样用户就不必须在使用 Git 之前先在本地生成 SSH 密钥对再把公钥上传到服务器。 对非资深的使用者,或者系统上缺少 SSH 相关程序的使用者,HTTP 协议的可用性是主要的优势。 与 SSH 协议类似,HTTP 协议也非常快和高效。你也可以在 HTTPS 协议上提供只读版本库的服务,如此你在传输数据的时候就可以加密数据;或者,你甚至可以让客户端使用指定的 SSL 证书。另一个好处是 HTTPS 协议被广泛使用,一般的企业防火墙都会允许这些端口的数据通过。 -**缺点** +- 缺点 在一些服务器上,架设 HTTPS 协议的服务端会比 SSH 协议的棘手一些。 除了这一点,用其他协议提供 Git 服务与智能 HTTP 协议相比就几乎没有优势了。如果你在 HTTP 上使用需授权的推送,管理凭证会比使用 SSH 密钥认证麻烦一些。 然而,你可以选择使用凭证存储工具,比如 macOS 的 Keychain 或者 Windows 的凭证管理器。 参考 凭证存储 如何安全地保存 HTTP 密码。 @@ -61,12 +61,12 @@ Git 通过 HTTP 通信有两种模式:**智能 HTTP 协议、哑(Dumb) HTT 架设 Git 服务器时常用 SSH 协议作为传输协议。 因为大多数环境下服务器已经支持通过 SSH 访问 —— 即使没有也很容易架设。 SSH 协议也是一个验证授权的网络协议;并且,因为其普遍性,架设和使用都很容易。 -**优势** +- 优点 用 SSH 协议的优势有很多。 首先,SSH 架设相对简单 —— SSH 守护进程很常见,多数管理员都有使用经验,并 且多数操作系统都包含了它及相关的管理工具。 其次,通过 SSH 访问是安全的 —— 所有传输数据都要经过授权和加密。 最后,与 HTTPS 协议、Git 协议及本地协议一样,SSH 协议很高效,在传输前也会尽量压缩数据。 -**缺点** +- 缺点 SSH 协议的缺点在于它不支持匿名访问 Git 仓库。 如果你使用 SSH,那么即便只是读取数据,使用者也 必须 通 过 SSH 访问你的主机, 这使得 SSH 协议不利于开源的项目,毕竟人们可能只想把你的仓库克隆下来查看。 如果你只在公司网络使用,SSH 协议可能是你唯一要用到的协议。 如果你要同时提供匿名只读访问和 SSH 协议,那么你除了为自己推送架设 SSH 服务以外, 还得架设一个可以让其他人访问的服务。 @@ -74,14 +74,14 @@ SSH 协议的缺点在于它不支持匿名访问 Git 仓库。 如果你使用 这是包含在 Git 里的一个特殊的守护进程;它监听在一个特定的端口(9418),类似于 SSH 服务,但是访问无需任何授权。 要让版本库支持 Git 协议,需要先创建一个 git-daemon-export-ok 文件 —— 它是 Git 协议守护进程为这个版本库提供服务的必要条件 —— 但是除此之外没有任何安全措施。 要么谁都可以克隆这个版本库,要么谁也不能。 这意味着,通常不能通过 Git 协议推送。 由于没有授权机制,一旦你开放推送操作,意味着网络上知道这个项目 URL 的人都可以向项目推送数据。 不用说,极少会有人这么做。 -**优点** +- 优点 目前,Git 协议是 Git 使用的网络传输协议里最快的。 如果你的项目有很大的访问量,或者你的项目很庞大并且不需要为写进行用户授权,架设 Git 守护进程来提供服务是不错的选择。 它使用与 SSH 相同的数据传输机制,但是省去了加密和授权的开销。 -**缺点** +- 缺点 Git 协议缺点是缺乏授权机制。 把 Git 协议作为访问项目版本库的唯一手段是不可取的。 一般的做法里,会同时提供 SSH 或者 HTTPS 协议的访问服务,只让少数几个开发者有推送(写)权限,其他人通过 git:// 访问只有读权限。 Git 协议也许也是最难架设的。 它要求有自己的守护进程,这就要配置 xinetd、systemd 或者其他的程序,这些工作并不简单。 它还要求防火墙开放 9418 端口,但是企业防火墙一般不会开放这个非标准端口。而大型的企业防火墙通常会封锁这个端口。 ## 第三方托管 -现在已经拥有了很多更现代,功能更全的 Git 服务器,GitLab 便是其中最出名的一个,同时 GitHub、Gitte 都是很棒的开源社区。 \ No newline at end of file +现在已经拥有了很多更现代,功能更全的 Git 服务器,GitLab 便是其中最出名的一个,同时 GitHub、Gitte 都是很棒的开源社区。 diff --git a/docs/开发/Git/起步.md b/docs/开发/Git/起步.md index d9e5c0d7..ac3a7141 100644 --- a/docs/开发/Git/起步.md +++ b/docs/开发/Git/起步.md @@ -8,6 +8,7 @@ data: 2022年1月13日 本章介绍开始使用 Git 前的相关知识。我们会先了解一些版本控制工具的历史背景,然后试着让 Git 在你的系统上跑起来,直到最后配置好,可以正常开始开发工作。读完本章,你就会明白为什么 Git 会如此流行,为什么你应该立即开始使用它。 ## 版本控制系统 + 版本控制系统(Version Control Systems,简称 VCS)是一种记录一个或若干文件内容变化,以便将来查阅特定版本修订情况的系统。 ### 本地版本控制系统 @@ -31,6 +32,7 @@ data: 2022年1月13日 更进一步,许多这类系统都可以指定和若干不同的远端代码仓库进行交互。籍此,你就可以在同一个项目中,分别和不同工作小组的人相互协作。 你可以根据需要设定不同的协作流程,比如层次模型式的工作流,而这在以前的集中式系统中是无法实现的。 ## Git 简史 + 同生活中的许多伟大事物一样,Git 诞生于一个极富纷争大举创新的年代。 Linux 内核开源项目有着为数众多的参与者。 绝大多数的 Linux 内核维护工作都花在了提交补丁和保存归档的繁琐事务上(1991-2002年间)。到 2002 年,整个项目组开始启用一个专有的分布式版本控制系统 BitKeeper 来管理和维护代码。 @@ -44,7 +46,9 @@ Linux 内核开源项目有着为数众多的参与者。 绝大多数的 Linux - **有能力高效管理类似 Linux 内核一样的超大规模项目(速度和数据量)** 自诞生于 2005 年以来,Git 日臻成熟完善,在高度易用的同时,仍然保留着初期设定的目标。 它的速度飞快,极其适合管理大项目,有着令人难以置信的非线性分支管理系统。 + ## Git 特性 + 那么,简单地说,Git 究竟是怎样的一个系统呢?它的主要特性是什么? ### 直接记录快照,而非差异比较 @@ -57,16 +61,16 @@ Git 与其他版本控制系统主要差别在于对待数据的方法;**Git ### Git 保证数据完整性 -Git 中所有的数据在存储前都用 SHA-1 散列(hash,哈希)计算校验和并以哈希值来索引,而不是文件名。这意味着不可能在 Git 不知情时更改任何文件内容或目录内容。 +Git 中所有的数据在存储前都用 SHA-1 散列(hash,哈希)计算校验和并以哈希值来索引,而不是文件名。这意味着不可能在 Git 不知情时更改任何文件内容或目录内容。 -``` +```shell // SHA-1 哈希 24b9da6552252987aa493b52f8696cd6d3b00373 ``` ### Git 一般只添加数据 -因为 Git 一般只添加数据,所以你很难让 Git 执行任何不可逆操作,或者让它以任何方式清除数据。 +因为 Git 一般只添加数据,所以你很难让 Git 执行任何不可逆操作,或者让它以任何方式清除数据。 ### Git 的三种状态 @@ -91,6 +95,7 @@ Git 有三种状态,你的文件可能处于其中之一: **已提交(comm ## 首次运行 Git 安装 Git 后要先定制你的 Git 环境,仅需配置一次,升级时保留配置信息。 + ### Git 配置 1. 系统配置:包含系统上每一个用户及其仓库的通用配置。 @@ -99,7 +104,7 @@ Git 有三种状态,你的文件可能处于其中之一: **已提交(comm 配置文件作用域采用就近原则,每一个级别会覆盖上一级别的配置。修改不同的配置文件,需要在执行 git config 时传递不同参数。 -``` +```shell git config --system git config --global git config --local @@ -109,14 +114,14 @@ git config --local 务必设置用户名和邮件地址,这一点至关重要,因为每一个 Git 提交都会使用这些信息,并且写入到每一次提交中,不可更改。 -``` +```shell git config --global user.name -git config --global user.email ``` ### 查看配置 -``` +```shell // 所有 Git 配置 git config --list @@ -126,11 +131,11 @@ git config ### 获取帮助 -``` +```shell git help git --help man git- // 简明的帮助文件 git -h -``` \ No newline at end of file +``` diff --git a/docs/开发/Java/基本语法.md b/docs/开发/Java/基本语法.md index b76de979..68f06883 100644 --- a/docs/开发/Java/基本语法.md +++ b/docs/开发/Java/基本语法.md @@ -115,4 +115,3 @@ public class HelloWorld { } } ``` - diff --git a/docs/开发/Java/控制语句.md b/docs/开发/Java/控制语句.md index 3db5e23c..70e98a8a 100644 --- a/docs/开发/Java/控制语句.md +++ b/docs/开发/Java/控制语句.md @@ -15,7 +15,7 @@ Java 中的控制语句其实和 C 一样,会涉及刀包括 **if-else、while int a = 10; if(a > 10){ - return true; + return true; } return false; @@ -28,9 +28,9 @@ int a = 10; int b = 11; if(a >= b){ - System.out.println("a >= b"); + System.out.println("a >= b"); }else{ - System.out.println("a < b"); + System.out.println("a < b"); } ``` @@ -40,13 +40,13 @@ if(a >= b){ int x = 40; if(x > 60) { - System.out.println("x的值大于60"); + System.out.println("x的值大于60"); } else if (x > 30) { - System.out.println("x的值大于30但小于60"); + System.out.println("x的值大于30但小于60"); } else if (x > 0) { - System.out.println("x的值大于0但小于30"); + System.out.println("x的值大于0但小于30"); } else { - System.out.println("x的值小于等于0"); + System.out.println("x的值小于等于0"); } ``` @@ -54,28 +54,28 @@ if(x > 60) { ```java switch (week) { - case 1: - System.out.println("Monday"); - break; - case 2: + case 1: + System.out.println("Monday"); + break; + case 2: System.out.println("Tuesday"); break; - case 3: + case 3: System.out.println("Wednesday"); break; - case 4: + case 4: System.out.println("Thursday"); break; - case 5: + case 5: System.out.println("Friday"); break; - case 6: + case 6: System.out.println("Saturday"); break; - case 7: + case 7: System.out.println("Sunday"); break; - default: + default: System.out.println("No Else"); break; } @@ -87,7 +87,7 @@ switch (week) { ```java while(布尔值){ - 表达式 + 表达式 } ``` @@ -98,8 +98,8 @@ while 与 do...while 循环的唯一区别是 do...while 语句最少执行一 ```java int b = 10; do { - System.out.println("b== " + b); - b--; + System.out.println("b== " + b); + b--; } while(b == 1); ``` @@ -115,7 +115,7 @@ for(初始化; 布尔表达式; 步进){} 在 for 语句表达式初始化部分,可以使用一系列的逗号分隔的语句;通过逗号操作符,可以在 for 语句内定义多个变量。 -``` +```java for(int i = 1; j = i + 10;i < 5;i++, j = j * 2){} ``` @@ -127,7 +127,7 @@ for-each 语句是一种更加简介的、方便对数组和集合进行遍历 int array[] = {7, 8, 9}; for (int arr : array) { - System.out.println(arr); + System.out.println(arr); } ``` @@ -143,4 +143,4 @@ for (int arr : array) { ### return 语句 -返回语句 \ No newline at end of file +返回语句 diff --git a/docs/开发/Java/简介.md b/docs/开发/Java/简介.md index b643aee9..b0cbd438 100644 --- a/docs/开发/Java/简介.md +++ b/docs/开发/Java/简介.md @@ -5,7 +5,7 @@ sidebar_position: 1 data: 2022年4月25日 --- -## Java 是什么 +## Java 是什么 Java 是世界上使用最广泛的编程语言之一。 diff --git a/docs/开发/Java/面对对象.md b/docs/开发/Java/面对对象.md index 6d93afe5..8e928920 100644 --- a/docs/开发/Java/面对对象.md +++ b/docs/开发/Java/面对对象.md @@ -20,7 +20,7 @@ data: 2022年4月27日 ```java class ClassName{ - // body + // body } ``` @@ -36,24 +36,24 @@ ClassName classname = new ClassName(); ```java class Apple { - int sum; - String color; + int sum; + String color; - public Apple(){} - public Apple(int sum){} - public Apple(String color){} - public Apple(int sum,String color){} + public Apple(){} + public Apple(int sum){} + public Apple(String color){} + public Apple(int sum,String color){} } // 创建对象 class createApple { - public static void main(String[] args) { - Apple apple1 = new Apple(); - Apple apple2 = new Apple(1); - Apple apple3 = new Apple("red"); - Apple apple4 = new Apple(2,"color"); - } + public static void main(String[] args) { + Apple apple1 = new Apple(); + Apple apple2 = new Apple(1); + Apple apple3 = new Apple("red"); + Apple apple4 = new Apple(2,"color"); + } } ``` @@ -71,8 +71,8 @@ class createApple { ```java Class A{ - int a; - Apple apple; + int a; + Apple apple; } ``` @@ -163,8 +163,6 @@ Java 不支持多继承,但支持多重继承。 - **this:**指向自己的引用。 - **final:**类定义为不能继承的,即最终类;或者用于修饰方法,该方法不能被子类重写。 -#### 实例 - ```java class 父类 { } @@ -206,30 +204,30 @@ public class C implements A,B { // super 与 this 关键字 class Animal { - void eat() { - System.out.println("animal : eat"); - } + void eat() { + System.out.println("animal : eat"); + } } class Dog extends Animal { - void eat() { - System.out.println("dog : eat"); - } + void eat() { + System.out.println("dog : eat"); + } - void eatTest() { - this.eat(); // this 调用自己的方法 - super.eat(); // super 调用父类方法 - } + void eatTest() { + this.eat(); // this 调用自己的方法 + super.eat(); // super 调用父类方法 + } } public class Test { - public static void main(String[] args) { - Animal a = new Animal(); - a.eat(); - Dog d = new Dog(); - d.eatTest(); - } + public static void main(String[] args) { + Animal a = new Animal(); + a.eat(); + Dog d = new Dog(); + d.eatTest(); + } } // final 关键字 @@ -283,17 +281,17 @@ final class 类名 { /*方法体*/ } ```java class Fruit { - public void eat(){ - System.out.printl('eat fruit'); - } + public void eat(){ + System.out.printl('eat fruit'); + } } class Apple extends Fruit{ - @Override - public void eat(){ - System.out.printl('eat apple'); - } + @Override + public void eat(){ + System.out.printl('eat apple'); + } } ``` @@ -310,19 +308,19 @@ class Apple extends Fruit{ ```java public class Apple { - int sum; - String color; + int sum; + String color; - public Apple(){} - public Apple(int sum){} + public Apple(){} + public Apple(int sum){} - public int getApple(int num){ - return 1; - } + public int getApple(int num){ + return 1; + } - public String getApple(String color){ - return "color"; - } + public String getApple(String color){ + return "color"; + } } ``` @@ -344,7 +342,7 @@ public class Apple { ![区别图例](https://static.7wate.com/img/2022/04/27/4fdd076693397.png) -- +- ## 抽象 @@ -360,39 +358,39 @@ public class Apple { - 构造方法,类方法(用 static 修饰的方法)不能声明为抽象方法。 - 抽象类的子类必须给出抽象类中的抽象方法的具体实现,除非该子类也是抽象类。 -### 类 +### 抽象类 ```java // 抽象类 public abstract class Employee { - private String name; - private String address; - private int number; + private String name; + private String address; + private int number; - public Employee(String name, String address, int number) { - System.out.println("Constructing an Employee"); - this.name = name; - this.address = address; - this.number = number; - } + public Employee(String name, String address, int number) { + System.out.println("Constructing an Employee"); + this.name = name; + this.address = address; + this.number = number; + } - public double computePay() { - System.out.println("Inside Employee computePay"); - return 0.0; - } + public double computePay() { + System.out.println("Inside Employee computePay"); + return 0.0; + } - public void mailCheck() { - System.out.println("Mailing a check to " + this.name - + " " + this.address); - } + public void mailCheck() { + System.out.println("Mailing a check to " + this.name + + " " + this.address); + } - public String toString() { - return name + " " + address + " " + number; - } + public String toString() { + return name + " " + address + " " + number; + } - public String getName() { - return name; - } + public String getName() { + return name; + } public String getAddress() { return address; @@ -455,7 +453,7 @@ public class AbstractDemo { } ``` -### 方法 +### 抽象方法 如果你想设计这样一个类,该类包含一个特别的成员方法,该方法的具体实现由它的子类确定,那么你可以在父类中声明该方法为抽象方法。同时抽象方法必须遵守如下约定: @@ -487,7 +485,7 @@ public abstract class Employee { 接口无法被实例化,但是可以被实现。一个实现接口的类,必须实现接口内所描述的所有方法,否则就必须声明为抽象类。 -### 特性 +### 特点 - 接口中每一个方法也是隐式抽象的,接口中的方法会被隐式的指定为 **public abstract**(只能是 public abstract,其他修饰符都会报错)。 - 接口中可以含有变量,但是接口中的变量会被隐式的指定为 **public static final** 变量(并且只能是 public,用 private 修饰会报编译错误)。 @@ -509,8 +507,6 @@ public abstract class Employee { - 接口不是被类继承了,而是要被类实现。 - 接口支持多继承。 -### 实例 - ```java // 接口声明 [可见度] interface 接口名称 [extends 其他的接口名] { @@ -615,8 +611,6 @@ import payroll.Employee ``` - - ### 作用 1. 把功能相似或相关的类或接口组织在同一个包中,方便类的查找和使用。 @@ -627,8 +621,6 @@ import payroll.Employee Java 使用包(package)这种机制是为了防止命名冲突,访问控制,提供搜索和定位类(class)、接口、枚举(enumerations)和注释(annotation)等。 -### 实例 - ```java // 在 animals 包中加入一个接口(interface) @@ -664,4 +656,3 @@ public class MammalInt implements Animal{ } } ``` - diff --git a/docs/开发/Python/Python 缺失 API 原因分析和解决方法.md b/docs/开发/Python/Python 缺失 API 原因分析和解决方法.md deleted file mode 100644 index 4e9a9dc5..00000000 --- a/docs/开发/Python/Python 缺失 API 原因分析和解决方法.md +++ /dev/null @@ -1,124 +0,0 @@ ---- -id: Python 缺失 API 原因分析和解决方法 -title: Python 缺失 API 原因分析和解决方法 -data: 2022年1月26日 ---- -在电脑使用过程中,有的朋友可能会遇到 api-ms-win-crt**.dll 缺失的问题,导致一些软件或游戏无法正常运行。这一问题的解决方法网上有些介绍,但到底是何原因,似乎没这方面的分析文章。对此,本人通过多次系统安装、比较和分析,找到其具体原因和解决方法。 - -## 方法/步骤 - -Windows 通用 C 运行库(Universal C Runtime)是通过 Windows Update 更新安装到系统的,更新的编号为KB2999226(10.0.10240.16390)或 KB3118401(10.0.10586.9),组件如下: - -   - -``` -api-ms-win-core-file-l1-2-0.dll -api-ms-win-core-file-l2-1-0.dll -api-ms-win-core-localization-l1-2-0.dll -api-ms-win-core-processthreads-l1-1-1.dll -api-ms-win-core-synch-l1-2-0.dll -api-ms-win-core-timezone-l1-1-0.dll -api-ms-win-core-xstate-l2-1-0.dll -api-ms-win-crt-conio-l1-1-0.dll -api-ms-win-crt-convert-l1-1-0.dll -api-ms-win-crt-environment-l1-1-0.dll -api-ms-win-crt-filesystem-l1-1-0.dll -api-ms-win-crt-heap-l1-1-0.dll -api-ms-win-crt-locale-l1-1-0.dll -api-ms-win-crt-math-l1-1-0.dll -api-ms-win-crt-multibyte-l1-1-0.dll -api-ms-win-crt-private-l1-1-0.dll -api-ms-win-crt-process-l1-1-0.dll -api-ms-win-crt-runtime-l1-1-0.dll -api-ms-win-crt-stdio-l1-1-0.dll -api-ms-win-crt-string-l1-1-0.dll -api-ms-win-crt-time-l1-1-0.dll -api-ms-win-crt-utility-l1-1-0.dll -api-ms-win-eventing-provider-l1-1-0.dll(KB3118401不含此文件) -ucrtbase.dll -``` - -系统是否安装了此类更新,可以通过查看“系统信息”来判断,操作:Win键+R,输入 cmd /k systeminfo.exe 确定。当然,也可以通过打开控制面板或使用第三方工具来查看。 - -如果系统中未安装 KB2999226、KB3118401 更新,则利用系统 Windows Update 扫描更新安装,或者单独下载更新进行手动安装。KB2999226、KB3118401 更新适用于下列操作系统,请注意 SP1、SP2 的系统环境要求,如果不满足条件,将无法正常安装。 - -``` -Windows Server 2012 R2 -Windows 8.1 -Windows RT 8.1 -Windows Server 2012 -Windows Server 2008 R2 Service Pack 1 (SP1) -Windows 7 Service Pack 1 (SP1) -Windows Server 2008 Service Pack 2 (SP2) -Windows Vista Service Pack 2 (SP2) - -注:Windows RT 8.1只能从Windows Update下载安装。 -``` - -## KB2999226、KB3118401更新下载: - -- KB2999226 微软下载链接 - - https://support.microsoft.com/en-us/help/2999226/update-for-universal-c-runtime-in-windows - -- KB3118401 微软下载链接 - - https://support.microsoft.com/en-us/help/3118401/update-for-universal-c-runtime-in-windows - - -下载链接为英文页面,可转换到简体页面下载。方法如下: - -1. 打开页面上,根据系统版本选择对应的下载按钮; - -2. 新打开页面上,“Select Language“ 处选择 “Chinese(Simplified)” 进入中文页面,然后下载更新。 - -另外,可以通过其它方式安装解决: - -Visual C++ 2015 Redistributable(x86/x64),根据系统版本下载,安装成功即可。 - -微软连接 https://www.microsoft.com/zh-cn/download/details.aspx?id=48145 - -## 其他方式 - -如果系统中已经安装了 KB2999226 或 KB3118401 更新,则 DLL 异常、缺失,大多是磁盘错误引起,按如下步骤修复: - -1. 系统分区磁盘查错。Ctrl+Shift+Esc-- 文件 --Ctrl+ 鼠标单击“新(建)任务”;黑窗中键入 chkdsk /r %systemdrive% 回车,如提示:强制卸除此卷?选择 “N” ,计划重启检查?选择 “Y”,重启电脑进行检查,时间较长。 - -  检查结束后,观察是否正常,如果还有问题,继续。 - -2. 卸载更新,重新安装。如果 KB2999226、KB3118401 都安装过,则选择 KB3118401 卸载,然后重新安装。 - -以 Win7 系统为例:开始--控制面板--程序和功能--查看已安装的更新:根据编号找到更新右键选择“卸载”,重启电脑后,利用 Windows Update 扫描更新安装,或者利用其它方法进行安装。 - -如果系统是使用集成了 VB/VC 运行库的映像安装的,或者是使用过“磁盘清理”清除过 “Windows 更新”,在卸载 KB2999226 或 KB3118401 更新时,可能会遇到无“卸载”选项的问题,修复方法上面已作了介绍。在修复无效的情况下,可以尝试提取 KB2999226 或 KB3118401 中的 DLL 文件进行替换解决。具体方法: - -1. 新建一文件夹,如 d:\KB; - -2. 按照前面介绍,下载 KB2999226 或 KB3118401 更新,存放到KB中; - -3. 利用批处理来提取DLL文件。打开系统“记事本”,复制粘贴批处理内容,然后选择“另存为”,选择路径到D:\KB,“文件名 ”输入GetDll.bat,“ 保存类型”选择“所有文件(*.*)”,保存。复制内容如下: - - - -``` -@echo off - -set pn=%~dp0 - -if "%pn:~-1%"=="\" set pn=%pn:~0,-1% - -for /f "delims=" %%i in ('dir %pn%\*.msu /a-d /b 2^>nul') do ( - -if not exist %pn%\%%~ni md %pn%\%%~ni - -start /wait %%i /extract:%pn%\%%~ni - -expand %pn%\%%~ni\%%~ni.cab /f:*.dll %pn%\%%~ni - -) - -echo.&pause -``` - -4. 双击批处理提取DLL文件,然后找到对应的DLL文件复制到系统目录(或复制到所需软件的安装目录)。文件替换可能会因权限问题无法进行,则先在原文件上右键选择“管理员取得所有权”,然后再进行处理。如果右键没有管理员权限菜单,可利用360方案处理:打开360人工服务,输入“管理员权限右键增加管理员权限”查找方案修复。 - diff --git a/docs/开发/Python/函数方法.md b/docs/开发/Python/函数方法.md index 4202ed21..bb559ae4 100644 --- a/docs/开发/Python/函数方法.md +++ b/docs/开发/Python/函数方法.md @@ -137,4 +137,4 @@ lambda 关键字用于创建小巧的匿名函数。lambda a, b: a+b 函数返 42 >>> f(1) 43 -``` \ No newline at end of file +``` diff --git a/docs/开发/Python/基本语法.md b/docs/开发/Python/基本语法.md index ddcb02f9..05dbfd58 100644 --- a/docs/开发/Python/基本语法.md +++ b/docs/开发/Python/基本语法.md @@ -31,7 +31,7 @@ data: 2022年4月27日 - 受保护的实例属性用单个下划线开头(后面会讲到)。 - 私有的实例属性用两个下划线开头(后面会讲到)。 -*使用 type() 检查变量的类型* +使用 type() 检查变量的类型 **Python中内置的函数对变量类型进行转换。** @@ -58,7 +58,7 @@ data: 2022年4月27日 | `is` `is not` | 身份运算符 | | `in` `not in` | 成员运算符 | | `not` `or` `and` | 逻辑运算符 | -| `=` `+=` `-=` `*=` `/=` `%=` `//=` `**=` `&=` ` | =` `^=` `>>=` `<<=` | | +| `=` `+=` `-=` `*=` `/=` `%=` `//=` `**=` `&=` `| =` `^=` `>>=` `<<=` | | *在实际开发中,如果搞不清楚运算符的优先级,可以使用括号来确保运算的执行顺序。* diff --git a/docs/开发/Python/控制语句.md b/docs/开发/Python/控制语句.md index e65c7727..17d36c4c 100644 --- a/docs/开发/Python/控制语句.md +++ b/docs/开发/Python/控制语句.md @@ -56,8 +56,6 @@ case 401 | 403 | 404: return "Not allowed" ``` - - ## 循环 ### for diff --git a/docs/开发/Python/数据结构.md b/docs/开发/Python/数据结构.md index e268a16c..df7bf0ec 100644 --- a/docs/开发/Python/数据结构.md +++ b/docs/开发/Python/数据结构.md @@ -185,7 +185,7 @@ print(len(list1)) # 9 # 先通过成员运算判断元素是否在列表中,如果存在就删除该元素 if 3 in list1: - list1.remove(3) + list1.remove(3) if 1234 in list1: list1.remove(1234) print(list1) # [1, 400, 5, 7, 100, 200, 1000, 2000] @@ -476,4 +476,4 @@ def main(): if __name__ == '__main__': main() -``` \ No newline at end of file +``` diff --git a/docs/开发/Python/简介.md b/docs/开发/Python/简介.md index a16fdd45..8eba3b9b 100644 --- a/docs/开发/Python/简介.md +++ b/docs/开发/Python/简介.md @@ -6,6 +6,7 @@ data: 2022年2月9日 --- ## 简介 + Python 是一种解释型语言,不需要编译和链接,可以节省大量开发时间。 Python 程序简洁、易读,通常比实现同种功能的 C、C++、Java 代码短很多,原因如下: @@ -18,7 +19,7 @@ Python 程序简洁、易读,通常比实现同种功能的 C、C++、Java 代 ### 安装 -Python 官网:https://www.python.org/,选择合适版本安装。 +Python 官网:,选择合适版本安装。 ### 使用 @@ -28,6 +29,6 @@ Python 官网:https://www.python.org/,选择合适版本安装。 Python 源码文件的编码是 UTF-8,如果不使用默认编码,则要声明文件的编码,文件的**第一行**要写成特殊注释。句法如下: -``` +```python # -*- coding: encoding -*- ``` diff --git a/docs/开发/Python/面对对象.md b/docs/开发/Python/面对对象.md index 88319503..127d261d 100644 --- a/docs/开发/Python/面对对象.md +++ b/docs/开发/Python/面对对象.md @@ -423,4 +423,3 @@ def main(): if __name__ == '__main__': main() ``` - diff --git a/docs/开发/Regex/什么是正则表达式.md b/docs/开发/Regex/什么是正则表达式.md index 530ab4c2..913b2c31 100644 --- a/docs/开发/Regex/什么是正则表达式.md +++ b/docs/开发/Regex/什么是正则表达式.md @@ -24,7 +24,7 @@ data: 2022年1月22日 正则表达式其实就是在执行搜索时的格式, 它由一些字母和数字组合而成. 例如: 一个正则表达式 `the`, 它表示一个规则: 由字母`t`开始,接着是`h`,再接着是`e`. -"the" => The fat cat sat on **the** mat. +"the" => The fat cat sat on **the** mat. [在线练习](https://regex101.com/r/dmRygT/1) @@ -58,7 +58,7 @@ data: 2022年1月22日 ## 2.1 点运算符 `.` -`.`是元字符中最简单的例子. +`.`是元字符中最简单的例子. `.`匹配任意单个字符, 但不匹配换行符. 例如, 表达式`.ar`匹配一个任意字符后面跟着是`a`和`r`的字符串. @@ -96,7 +96,7 @@ data: 2022年1月22日 ## 2.3 重复次数 -后面跟着元字符 `+`, `*` or `?` 的, 用来指定匹配子模式的次数. +后面跟着元字符 `+`, `*` or `?` 的, 用来指定匹配子模式的次数. 这些元字符在不同的情况下有着不同的意思. ### 2.3.1 `*` 号 @@ -111,7 +111,7 @@ data: 2022年1月22日 `*`字符和`.`字符搭配可以匹配所有的字符`.*`. `*`和表示匹配空格的符号`\s`连起来用, 如表达式`\s*cat\s*`匹配0或更多个空格开头和0或更多个空格结尾的cat字符串. -"\s*cat\s*" => The fat** cat **sat on the con**cat**enation. +"\s*cat\s*" => The fat**cat**sat on the con**cat**enation. [在线练习](https://regex101.com/r/gGrwuz/1) @@ -149,7 +149,7 @@ data: 2022年1月22日 我们可以省略第二个参数. 例如, `[0-9]{2,}` 匹配至少两位 0~9 的数字. -如果逗号也省略掉则表示重复固定的次数. +如果逗号也省略掉则表示重复固定的次数. 例如, `[0-9]{3}` 匹配3位数字 "[0-9]{2,}" => The number was 9.**9997** but we rounded it off to **10**.0. @@ -224,7 +224,7 @@ data: 2022年1月22日 [在线练习](https://regex101.com/r/t0AkOd/1) -## 3. 简写字符集 +## 3. 简写字符集 正则表达式提供一些常用的字符集简写. 如下: @@ -260,7 +260,7 @@ data: 2022年1月22日 `?=...` 前置约束(存在), 表示第一部分表达式必须跟在 `?=...`定义的表达式之后. 返回结果只瞒住第一部分表达式. -定义一个前置约束(存在)要使用 `()`. 在括号内部使用一个问号和等号: `(?=...)`. +定义一个前置约束(存在)要使用 `()`. 在括号内部使用一个问号和等号: `(?=...)`. 前置约束的内容写在括号中的等号后面. 例如, 表达式 `[T|t]he(?=\sfat)` 匹配 `The` 和 `the`, 在括号中我们又定义了前置约束(存在) `(?=\sfat)` ,即 `The` 和 `the` 后面紧跟着 `(空格)fat`. @@ -272,7 +272,7 @@ data: 2022年1月22日 ### 4.2 `?!...` 前置约束-排除 前置约束-排除 `?!` 用于筛选所有匹配结果, 筛选条件为 其后不跟随着定义的格式 -`前置约束-排除` 定义和 `前置约束(存在)` 一样, 区别就是 `=` 替换成 `!` 也就是 `(?!...)`. +`前置约束-排除` 定义和 `前置约束(存在)` 一样, 区别就是 `=` 替换成 `!` 也就是 `(?!...)`. 表达式 `[T|t]he(?!\sfat)` 匹配 `The` 和 `the`, 且其后不跟着 `(空格)fat`. @@ -324,7 +324,7 @@ data: 2022年1月22日 ### 5.2 全局搜索 (Global search) -修饰符 `g` 常用于执行一个全局搜索匹配, 即(不仅仅返回第一个匹配的, 而是返回全部). +修饰符 `g` 常用于执行一个全局搜索匹配, 即(不仅仅返回第一个匹配的, 而是返回全部). 例如, 表达式 `/.(at)/g` 表示搜索 任意字符(除了换行) + `at`, 并返回全部结果. "/.(at)/" => The **fat** cat sat on the mat. @@ -355,11 +355,10 @@ data: 2022年1月22日 [在线练习](https://regex101.com/r/E88WE2/1) - ## 贡献 感谢 [Learn-regex]( https://github.com/ziishaned/learn-regex) 项目 ## 许可证 -MIT © [Zeeshan Ahmad](https://twitter.com/ziishaned) \ No newline at end of file +MIT © [Zeeshan Ahmad](https://twitter.com/ziishaned) diff --git a/docs/开发/Regex/常用正则大全.md b/docs/开发/Regex/常用正则大全.md index 6cd95d4f..3368c974 100644 --- a/docs/开发/Regex/常用正则大全.md +++ b/docs/开发/Regex/常用正则大全.md @@ -4,9 +4,9 @@ title: 常用正则大全 data: 2022年1月22日 --- - - [regex101(正则表达式测试工具)](https://regex101.com/) - - [REGEXP(正则表达式测试工具)](https://regexr.com/) - - [Regulex(正则表达式可视化工具)](https://jex.im/regulex) +- [regex101(正则表达式测试工具)](https://regex101.com/) +- [REGEXP(正则表达式测试工具)](https://regexr.com/) +- [Regulex(正则表达式可视化工具)](https://jex.im/regulex) 感谢 [any-rule](https://github.com/any86/any-rule) 项目 @@ -15,386 +15,463 @@ data: 2022年1月22日 ## 🍔正则 ### 火车车次 + ```javascript /^[GCDZTSPKXLY1-9]\d{1,4}$/ ``` ### 手机机身码(IMEI) + ```javascript /^\d{15,17}$/ ``` ### 必须带端口号的网址(或ip) + ```javascript /^((ht|f)tps?:\/\/)?[\w-]+(\.[\w-]+)+:\d{1,5}\/?$/ ``` ### 网址(URL) + ```javascript /^(((ht|f)tps?):\/\/)?([^!@#$%^&*?.\s-]([^!@#$%^&*?.\s]{0,63}[^!@#$%^&*?.\s])?\.)+[a-z]{2,6}\/?/ ``` ### 统一社会信用代码 + ```javascript /^[0-9A-HJ-NPQRTUWXY]{2}\d{6}[0-9A-HJ-NPQRTUWXY]{10}$/ ``` ### 统一社会信用代码(宽松匹配)(15位/18位/20位数字/字母) + ```javascript /^(([0-9A-Za-z]{15})|([0-9A-Za-z]{18})|([0-9A-Za-z]{20}))$/ ``` ### 迅雷链接 + ```javascript /^thunderx?:\/\/[a-zA-Z\d]+=$/ ``` ### ed2k链接(宽松匹配) + ```javascript /^ed2k:\/\/\|file\|.+\|\/$/ ``` ### 磁力链接(宽松匹配) + ```javascript /^magnet:\?xt=urn:btih:[0-9a-fA-F]{40,}.*$/ ``` ### 子网掩码(不包含 0.0.0.0) + ```javascript /^(254|252|248|240|224|192|128)\.0\.0\.0|255\.(254|252|248|240|224|192|128|0)\.0\.0|255\.255\.(254|252|248|240|224|192|128|0)\.0|255\.255\.255\.(255|254|252|248|240|224|192|128|0)$/ ``` ### linux"隐藏文件"路径 + ```javascript /^\/(?:[^/]+\/)*\.[^/]*/ ``` ### linux文件夹路径 + ```javascript /^\/(?:[^/]+\/)*$/ ``` ### linux文件路径 + ```javascript /^\/(?:[^/]+\/)*[^/]+$/ ``` ### window"文件夹"路径 + ```javascript /^[a-zA-Z]:\\(?:\w+\\?)*$/ ``` ### window下"文件"路径 + ```javascript /^[a-zA-Z]:\\(?:\w+\\)*\w+\.\w+$/ ``` ### 股票代码(A股) + ```javascript /^(s[hz]|S[HZ])(000[\d]{3}|002[\d]{3}|300[\d]{3}|600[\d]{3}|60[\d]{4})$/ ``` ### 大于等于0, 小于等于150, 支持小数位出现5, 如145.5, 用于判断考卷分数 + ```javascript /^150$|^(?:\d|[1-9]\d|1[0-4]\d)(?:\.5)?$/ ``` ### html注释 + ```javascript //g ``` ### md5格式(32位) + ```javascript /^([a-f\d]{32}|[A-F\d]{32})$/ ``` ### GUID/UUID + ```javascript /^[a-f\d]{4}(?:[a-f\d]{4}-){4}[a-f\d]{12}$/i ``` ### 版本号(version)格式必须为X.Y.Z + ```javascript /^\d+(?:\.\d+){2}$/ ``` ### 视频(video)链接地址(视频格式可按需增删) + ```javascript /^https?:\/\/(.+\/)+.+(\.(swf|avi|flv|mpg|rm|mov|wav|asf|3gp|mkv|rmvb|mp4))$/i ``` ### 图片(image)链接地址(图片格式可按需增删) + ```javascript /^https?:\/\/(.+\/)+.+(\.(gif|png|jpg|jpeg|webp|svg|psd|bmp|tif))$/i ``` ### 24小时制时间(HH:mm:ss) + ```javascript /^(?:[01]\d|2[0-3]):[0-5]\d:[0-5]\d$/ ``` ### 12小时制时间(hh:mm:ss) + ```javascript /^(?:1[0-2]|0?[1-9]):[0-5]\d:[0-5]\d$/ ``` ### base64格式 + ```javascript /^\s*data:(?:[a-z]+\/[a-z0-9-+.]+(?:;[a-z-]+=[a-z0-9-]+)?)?(?:;base64)?,([a-z0-9!$&',()*+;=\-._~:@/?%\s]*?)\s*$/i ``` ### 数字/货币金额(支持负数、千分位分隔符) + ```javascript /^-?\d+(,\d{3})*(\.\d{1,2})?$/ ``` ### 数字/货币金额 (只支持正数、不支持校验千分位分隔符) + ```javascript /(?:^[1-9]([0-9]+)?(?:\.[0-9]{1,2})?$)|(?:^(?:0)$)|(?:^[0-9]\.[0-9](?:[0-9])?$)/ ``` ### 银行卡号(10到30位, 覆盖对公/私账户, 参考[微信支付](https://pay.weixin.qq.com/wiki/doc/api/xiaowei.php?chapter=22_1)) + ```javascript /^[1-9]\d{9,29}$/ ``` ### 中文姓名 + ```javascript /^(?:[\u4e00-\u9fa5·]{2,16})$/ ``` ### 英文姓名 + ```javascript /(^[a-zA-Z][a-zA-Z\s]{0,20}[a-zA-Z]$)/ ``` ### 车牌号(新能源) + ```javascript /^[京津沪渝冀豫云辽黑湘皖鲁新苏浙赣鄂桂甘晋蒙陕吉闽贵粤青藏川宁琼使领][A-HJ-NP-Z](?:((\d{5}[A-HJK])|([A-HJK][A-HJ-NP-Z0-9][0-9]{4}))|[A-HJ-NP-Z0-9]{4}[A-HJ-NP-Z0-9挂学警港澳])$/ ``` ### 车牌号(非新能源) + ```javascript /^[京津沪渝冀豫云辽黑湘皖鲁新苏浙赣鄂桂甘晋蒙陕吉闽贵粤青藏川宁琼使领][A-HJ-NP-Z][A-HJ-NP-Z0-9]{4}[A-HJ-NP-Z0-9挂学警港澳]$/ ``` ### 车牌号(新能源+非新能源) + ```javascript /^[京津沪渝冀豫云辽黑湘皖鲁新苏浙赣鄂桂甘晋蒙陕吉闽贵粤青藏川宁琼使领][A-HJ-NP-Z][A-HJ-NP-Z0-9]{4,5}[A-HJ-NP-Z0-9挂学警港澳]$/ ``` ### 手机号(mobile phone)中国(严谨), 根据工信部2019年最新公布的手机号段 + ```javascript /^(?:(?:\+|00)86)?1(?:(?:3[\d])|(?:4[5-79])|(?:5[0-35-9])|(?:6[5-7])|(?:7[0-8])|(?:8[\d])|(?:9[189]))\d{8}$/ ``` ### 手机号(mobile phone)中国(宽松), 只要是13,14,15,16,17,18,19开头即可 + ```javascript /^(?:(?:\+|00)86)?1[3-9]\d{9}$/ ``` ### 手机号(mobile phone)中国(最宽松), 只要是1开头即可, 如果你的手机号是用来接收短信, 优先建议选择这一条 + ```javascript /^(?:(?:\+|00)86)?1\d{10}$/ ``` ### date(日期) + ```javascript /^\d{1,4}(-)(1[0-2]|0?[1-9])\1(0?[1-9]|[1-2]\d|30|31)$/ ``` ### 可以被moment转化成功的时间 YYYYMMDD HH:mm:ss + ```javascript /^\d{4}([/:-\S])(1[0-2]|0?[1-9])\1(0?[1-9]|[1-2]\d|30|31) (?:[01]\d|2[0-3]):[0-5]\d:[0-5]\d$/ ``` ### email(邮箱) + ```javascript /^(([^<>()[\]\\.,;:\s@"]+(\.[^<>()[\]\\.,;:\s@"]+)*)|(".+"))@((\[[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}\])|(([a-zA-Z\-0-9]+\.)+[a-zA-Z]{2,}))$/ ``` ### 座机(tel phone)电话(国内),如: 0341-86091234 + ```javascript /^(?:(?:\d{3}-)?\d{8}|^(?:\d{4}-)?\d{7,8})(?:-\d+)?$/ ``` ### 身份证号(1代,15位数字) + ```javascript /^[1-9]\d{7}(?:0\d|10|11|12)(?:0[1-9]|[1-2][\d]|30|31)\d{3}$/ ``` ### 身份证号(2代,18位数字),最后一位是校验位,可能为数字或字符X + ```javascript /^[1-9]\d{5}(?:18|19|20)\d{2}(?:0[1-9]|10|11|12)(?:0[1-9]|[1-2]\d|30|31)\d{3}[\dXx]$/ ``` ### 身份证号, 支持1/2代(15位/18位数字) + ```javascript /^\d{6}((((((19|20)\d{2})(0[13-9]|1[012])(0[1-9]|[12]\d|30))|(((19|20)\d{2})(0[13578]|1[02])31)|((19|20)\d{2})02(0[1-9]|1\d|2[0-8])|((((19|20)([13579][26]|[2468][048]|0[48]))|(2000))0229))\d{3})|((((\d{2})(0[13-9]|1[012])(0[1-9]|[12]\d|30))|((\d{2})(0[13578]|1[02])31)|((\d{2})02(0[1-9]|1\d|2[0-8]))|(([13579][26]|[2468][048]|0[048])0229))\d{2}))(\d|X|x)$/ ``` ### 护照(包含香港、澳门) + ```javascript /(^[EeKkGgDdSsPpHh]\d{8}$)|(^(([Ee][a-fA-F])|([DdSsPp][Ee])|([Kk][Jj])|([Mm][Aa])|(1[45]))\d{7}$)/ ``` ### 帐号是否合法(字母开头,允许5-16字节,允许字母数字下划线组合 + ```javascript /^[a-zA-Z]\w{4,15}$/ ``` ### 中文/汉字 + ```javascript /^(?:[\u3400-\u4DB5\u4E00-\u9FEA\uFA0E\uFA0F\uFA11\uFA13\uFA14\uFA1F\uFA21\uFA23\uFA24\uFA27-\uFA29]|[\uD840-\uD868\uD86A-\uD86C\uD86F-\uD872\uD874-\uD879][\uDC00-\uDFFF]|\uD869[\uDC00-\uDED6\uDF00-\uDFFF]|\uD86D[\uDC00-\uDF34\uDF40-\uDFFF]|\uD86E[\uDC00-\uDC1D\uDC20-\uDFFF]|\uD873[\uDC00-\uDEA1\uDEB0-\uDFFF]|\uD87A[\uDC00-\uDFE0])+$/ ``` ### 小数 + ```javascript /^\d+\.\d+$/ ``` ### 数字 + ```javascript /^\d{1,}$/ ``` ### html标签(宽松匹配) + ```javascript /<(\w+)[^>]*>(.*?<\/\1>)?/ ``` ### qq号格式正确 + ```javascript /^[1-9][0-9]{4,10}$/ ``` ### 数字和字母组成 + ```javascript /^[A-Za-z0-9]+$/ ``` ### 英文字母 + ```javascript /^[a-zA-Z]+$/ ``` ### 小写英文字母组成 + ```javascript /^[a-z]+$/ ``` ### 大写英文字母 + ```javascript /^[A-Z]+$/ ``` ### 密码强度校验,最少6位,包括至少1个大写字母,1个小写字母,1个数字,1个特殊字符 + ```javascript /^\S*(?=\S{6,})(?=\S*\d)(?=\S*[A-Z])(?=\S*[a-z])(?=\S*[!@#$%^&*? ])\S*$/ ``` ### 用户名校验,4到16位(字母,数字,下划线,减号) + ```javascript /^[a-zA-Z0-9_-]{4,16}$/ ``` ### ip-v4[:端口] + ```javascript /^((\d|[1-9]\d|1\d\d|2[0-4]\d|25[0-5])\.){3}(\d|[1-9]\d|1\d\d|2[0-4]\d|25[0-5])(?::(?:[0-9]|[1-9][0-9]{1,3}|[1-5][0-9]{4}|6[0-4][0-9]{3}|65[0-4][0-9]{2}|655[0-2][0-9]|6553[0-5]))?$/ ``` ### ip-v6[:端口] + ```javascript /(^(?:(?:(?:[0-9A-Fa-f]{1,4}:){7}[0-9A-Fa-f]{1,4})|(([0-9A-Fa-f]{1,4}:){6}:[0-9A-Fa-f]{1,4})|(([0-9A-Fa-f]{1,4}:){5}:([0-9A-Fa-f]{1,4}:)?[0-9A-Fa-f]{1,4})|(([0-9A-Fa-f]{1,4}:){4}:([0-9A-Fa-f]{1,4}:){0,2}[0-9A-Fa-f]{1,4})|(([0-9A-Fa-f]{1,4}:){3}:([0-9A-Fa-f]{1,4}:){0,3}[0-9A-Fa-f]{1,4})|(([0-9A-Fa-f]{1,4}:){2}:([0-9A-Fa-f]{1,4}:){0,4}[0-9A-Fa-f]{1,4})|(([0-9A-Fa-f]{1,4}:){6}((\b((25[0-5])|(1\d{2})|(2[0-4]\d)|(\d{1,2}))\b)\.){3}(\b((25[0-5])|(1\d{2})|(2[0-4]\d)|(\d{1,2}))\b))|(([0-9A-Fa-f]{1,4}:){0,5}:((\b((25[0-5])|(1\d{2})|(2[0-4]\d)|(\d{1,2}))\b)\.){3}(\b((25[0-5])|(1\d{2})|(2[0-4]\d)|(\d{1,2}))\b))|(::([0-9A-Fa-f]{1,4}:){0,5}((\b((25[0-5])|(1\d{2})|(2[0-4]\d)|(\d{1,2}))\b)\.){3}(\b((25[0-5])|(1\d{2})|(2[0-4]\d)|(\d{1,2}))\b))|([0-9A-Fa-f]{1,4}::([0-9A-Fa-f]{1,4}:){0,5}[0-9A-Fa-f]{1,4})|(::([0-9A-Fa-f]{1,4}:){0,6}[0-9A-Fa-f]{1,4})|(([0-9A-Fa-f]{1,4}:){1,7}:))$)|(^\[(?:(?:(?:[0-9A-Fa-f]{1,4}:){7}[0-9A-Fa-f]{1,4})|(([0-9A-Fa-f]{1,4}:){6}:[0-9A-Fa-f]{1,4})|(([0-9A-Fa-f]{1,4}:){5}:([0-9A-Fa-f]{1,4}:)?[0-9A-Fa-f]{1,4})|(([0-9A-Fa-f]{1,4}:){4}:([0-9A-Fa-f]{1,4}:){0,2}[0-9A-Fa-f]{1,4})|(([0-9A-Fa-f]{1,4}:){3}:([0-9A-Fa-f]{1,4}:){0,3}[0-9A-Fa-f]{1,4})|(([0-9A-Fa-f]{1,4}:){2}:([0-9A-Fa-f]{1,4}:){0,4}[0-9A-Fa-f]{1,4})|(([0-9A-Fa-f]{1,4}:){6}((\b((25[0-5])|(1\d{2})|(2[0-4]\d)|(\d{1,2}))\b)\.){3}(\b((25[0-5])|(1\d{2})|(2[0-4]\d)|(\d{1,2}))\b))|(([0-9A-Fa-f]{1,4}:){0,5}:((\b((25[0-5])|(1\d{2})|(2[0-4]\d)|(\d{1,2}))\b)\.){3}(\b((25[0-5])|(1\d{2})|(2[0-4]\d)|(\d{1,2}))\b))|(::([0-9A-Fa-f]{1,4}:){0,5}((\b((25[0-5])|(1\d{2})|(2[0-4]\d)|(\d{1,2}))\b)\.){3}(\b((25[0-5])|(1\d{2})|(2[0-4]\d)|(\d{1,2}))\b))|([0-9A-Fa-f]{1,4}::([0-9A-Fa-f]{1,4}:){0,5}[0-9A-Fa-f]{1,4})|(::([0-9A-Fa-f]{1,4}:){0,6}[0-9A-Fa-f]{1,4})|(([0-9A-Fa-f]{1,4}:){1,7}:))\](?::(?:[0-9]|[1-9][0-9]{1,3}|[1-5][0-9]{4}|6[0-4][0-9]{3}|65[0-4][0-9]{2}|655[0-2][0-9]|6553[0-5]))?$)/i ``` ### 16进制颜色 + ```javascript /^#?([a-fA-F0-9]{6}|[a-fA-F0-9]{3})$/ ``` ### 微信号(wx),6至20位,以字母开头,字母,数字,减号,下划线 + ```javascript /^[a-zA-Z][-_a-zA-Z0-9]{5,19}$/ ``` ### 邮政编码(中国) + ```javascript /^(0[1-7]|1[0-356]|2[0-7]|3[0-6]|4[0-7]|5[1-7]|6[1-7]|7[0-5]|8[013-6])\d{4}$/ ``` ### 中文和数字 + ```javascript /^((?:[\u3400-\u4DB5\u4E00-\u9FEA\uFA0E\uFA0F\uFA11\uFA13\uFA14\uFA1F\uFA21\uFA23\uFA24\uFA27-\uFA29]|[\uD840-\uD868\uD86A-\uD86C\uD86F-\uD872\uD874-\uD879][\uDC00-\uDFFF]|\uD869[\uDC00-\uDED6\uDF00-\uDFFF]|\uD86D[\uDC00-\uDF34\uDF40-\uDFFF]|\uD86E[\uDC00-\uDC1D\uDC20-\uDFFF]|\uD873[\uDC00-\uDEA1\uDEB0-\uDFFF]|\uD87A[\uDC00-\uDFE0])|(\d))+$/ ``` ### 不能包含字母 + ```javascript /^[^A-Za-z]*$/ ``` ### java包名 + ```javascript /^([a-zA-Z_]\w*)+([.][a-zA-Z_]\w*)+$/ ``` ### mac地址 + ```javascript /^((([a-f0-9]{2}:){5})|(([a-f0-9]{2}-){5}))[a-f0-9]{2}$/i ``` ### 匹配连续重复的字符 + ```javascript /(.)\1+/ ``` ### 数字和英文字母组成,并且同时含有数字和英文字母 + ```javascript /^(?=.*[a-zA-Z])(?=.*\d).+$/ ``` -### 香港身份证 +### 香港身份证 + ```javascript /^[a-zA-Z]\d{6}\([\dA]\)$/ ``` -### 澳门身份证 +### 澳门身份证 + ```javascript /^[1|5|7]\d{6}\(\d\)$/ ``` -### 台湾身份证 +### 台湾身份证 + ```javascript /^[a-zA-Z][0-9]{9}$/ ``` ### 大写字母,小写字母,数字,特殊符号 `@#$%^&*`~()-+=` 中任意3项密码 + ```javascript /^(?![a-zA-Z]+$)(?![A-Z0-9]+$)(?![A-Z\W_!@#$%^&*`~()-+=]+$)(?![a-z0-9]+$)(?![a-z\W_!@#$%^&*`~()-+=]+$)(?![0-9\W_!@#$%^&*`~()-+=]+$)[a-zA-Z0-9\W_!@#$%^&*`~()-+=]/ ``` ### 正整数,不包含0 + ```javascript /^\+?[1-9]\d*$/ ``` ### 负整数,不包含0 + ```javascript /^-[1-9]\d*$/ ``` ### 整数 + ```javascript /^-?[0-9]\d*$/ ``` ### 浮点数 + ```javascript /^(-?\d+)(\.\d+)?$/ ``` ### email(支持中文邮箱) + ```javascript /^[A-Za-z0-9\u4e00-\u9fa5]+@[a-zA-Z0-9_-]+(\.[a-zA-Z0-9_-]+)+$/ ``` diff --git a/docs/开发/SQL/基础.md b/docs/开发/SQL/基础.md index 65b3b576..933bad48 100644 --- a/docs/开发/SQL/基础.md +++ b/docs/开发/SQL/基础.md @@ -23,12 +23,8 @@ data: 2022年5月11日 1. 使用表存储数据,格式统一,便于维护。 2. 使用 SQL 语言操作,标准统一,使用方便。 - - ![img](https://static.7wate.com/img/2022/05/11/6bbfdea71bff2.png) - - 常见的 MySQL、Oracle、DB2、SQLServer 这些都是属于关系型数据库,里面都是基于二维表存储数据的。 无论我们使用哪一个关系型数据库,最终在操作时都是使用 SQL 语言来进行统一操作, @@ -40,8 +36,6 @@ data: 2022年5月11日 全称 Structured Query Language,结构化查询语言。操作关系型数据库的编程语言,定义了一套操作关系型数据库统一标准。 - - ![img](https://static.7wate.com/img/2022/05/11/9459b0983c451.png) 1. SQL 语句可以单行或多行书写,以分号结尾。 @@ -442,12 +436,8 @@ DQL 执行顺序: FROM -> WHERE -> GROUP BY -> HAVING -> SELECT -> ORDER BY -> LIMIT ``` - - ![img](https://static.7wate.com/img/2022/05/11/e526304cef38f.png) - - 按照需求完成如下 DQL 语句编写 ```sql @@ -644,8 +634,6 @@ from employee; ## 常用约束 - - ![img](https://static.7wate.com/img/2022/05/11/58a6b68ad6471.png) ```sql @@ -662,12 +650,8 @@ create table user( 外键约束是用来让两个表的数据之间建立连接,从而保证数据的一致性和完整性。 - - ![img](https://static.7wate.com/img/2022/05/11/110dd22cdc2cf.png) - - ```sql -- 在创建表时添加外键 CREATE TABLE 表名( @@ -718,12 +702,8 @@ alter table emp add constraint fk_emp_dept_id foreign key dept_id references dep 实现:在多的一方建立外键,指向一的一方的主键 - - ![img](https://static.7wate.com/img/2022/05/11/0f32732cb6a00.png) - - ### 多对多 案例:学生与课程 @@ -732,12 +712,8 @@ alter table emp add constraint fk_emp_dept_id foreign key dept_id references dep 实现:建立第三张中间表,中间表至少包含两个外键,分别关联两方主键 - - ![img](https://static.7wate.com/img/2022/05/11/c029ca35af10d.png) - - ### 一对一 案例:用户与用户详情 @@ -746,12 +722,8 @@ alter table emp add constraint fk_emp_dept_id foreign key dept_id references dep 实现:在任意一方加入外键,关联另外一方的主键,并且设置外键为唯一的(UNIQUE) - - ![img](https://static.7wate.com/img/2022/05/11/ae2c3633fde99.png) - - ## 多表查询 指的是从多表中查询出想要的数据。 @@ -763,12 +735,8 @@ alter table emp add constraint fk_emp_dept_id foreign key dept_id references dep **消除笛卡尔积**:`select * from employee, dept where employee.dept = dept.id;` - - ![img](https://static.7wate.com/img/2022/05/11/eaa68daf10655.png) - - 在进行多表查询测试之前,我们先准备好数据表。 ```sql @@ -821,19 +789,15 @@ INSERT INTO emp (id, name, age, job, salary, entrydate, managerid, dept_id) VALU 内连接查询的是两张表交集的部分。 - - ![img](https://static.7wate.com/img/2022/05/11/8d8fa0226c444.png) - - 隐式内连接: `SELECT 字段列表 FROM 表1, 表2 WHERE 条件 ...;` 显式内连接: `SELECT 字段列表 FROM 表1 [ INNER ] JOIN 表2 ON 连接条件 ...;` -**显式性能比隐式高** +SQL**显式性能比隐式高** ```sql -- 查询每一个员工的姓名,及关联的部门的名称(隐式内连接查询) @@ -888,7 +852,7 @@ SQL 语句中嵌套 SELECT 语句,称谓嵌套查询,又称子查询。 SELECT * FROM t1 WHERE column1 = ( SELECT column1 FROM t2); ``` -**子查询外部的语句可以是 INSERT / UPDATE / DELETE / SELECT 的任何一个** +子查询外部的语句可以是 **INSERT / UPDATE / DELETE / SELECT 的任何一个** 根据子查询结果可以分为: @@ -1063,8 +1027,6 @@ select * from emp e2 where e2.salary < (select avg(e1.salary) from emp e1 where select d.*, (select count(*) from emp e where e.dept_id = d.id) '人数' from dept d; ``` - - ![img](https://static.7wate.com/img/2022/05/11/7ee27cf278dd9.png) 事务是一组操作的集合,它是一个不可分割的工作单位,事务会把所有的操作作为一个整体一起向系统提交或撤销操作请求 @@ -1143,32 +1105,20 @@ commit; 如下图,事务 A 更新 1,但还未提交,此时被事务 B 查去了,这就导致可能事务 A 最终决定不提交,但是事务 B 拿出来后当真了,所以这种现象叫做脏读。 - - ![img](https://static.7wate.com/img/2022/05/11/85c311e17a51d.png) - - ### 不可重复读 如下图,事务 A 查询第一次后,事务 B 更新了这条数据,事务 A 查询第二次时发现跟第一次查询的结果不一样,这种现象叫做不可重复读。 - - ![img](https://static.7wate.com/img/2022/05/11/0d298382a22d4.png) - - ### 幻读 幻读是在解决 [不可重复读] 的基础上产生的新问题,如下图,事务 A 读取 id 为 1 的数据为空,事务 B 插入 id 为 1 的数据,之后事务 A 想要插入这条数据发现插入不了(比如被主键约束了),然后事务 A 重新查询还是找不到 id 为 1 的数据(因为我们解决了[不可重复读],所以查询出来的结果跟第一次查是一致的)。 - - ![img](https://static.7wate.com/img/2022/05/11/b5bdbc0d6b4e0.png) - - ## 事务隔离级别 MySQL 默认的事务隔离级别是 Repeatable Read @@ -1195,8 +1145,6 @@ SET [ SESSION | GLOBAL ] TRANSACTION ISOLATION LEVEL {READ UNCOMMITTED | READ CO -- GLOBAL 表示对所有会话有效 ``` - - >版权属于:乐心湖's Blog > ->本文链接:https://www.xn2001.com/archives/677.html \ No newline at end of file +>本文链接: diff --git a/docs/标准/Git/Git 规范.md b/docs/标准/Git 规范.md similarity index 98% rename from docs/标准/Git/Git 规范.md rename to docs/标准/Git 规范.md index 52ce4fad..29ef16ec 100644 --- a/docs/标准/Git/Git 规范.md +++ b/docs/标准/Git 规范.md @@ -6,7 +6,6 @@ data: 2022年1月25日 统一团队的 Git 工作流,包括分支工作流、Git commit 日志、tag 规范、README 模板、issue 模板,便于后续代码 review,版本发布以及日志自动化生成等等。 - ## 分支工作流 ![Git 分支工作流.png](https://static.7wate.com/img/2021/08/24/c5a50e99dde5f.png) @@ -21,7 +20,7 @@ commit 包括三个部分:**Header**、**Body**、**Footer**。 commit 格式如下: -``` +```text ([scope]): [body] @@ -31,7 +30,7 @@ commit 格式如下: 示例: -``` +```text feature(auth): increase length of new API key the length is increased from 24 to 32 for new API keys @@ -59,7 +58,7 @@ close #12 示例 -``` +```text feature!(api): limit array length to 256 elements BREAKING: Array length limit is added to further limit request size. A diff --git a/docs/求职/互联网行业-郑州.md b/docs/求职/互联网行业-郑州.md index 7351a1ca..407ba443 100644 --- a/docs/求职/互联网行业-郑州.md +++ b/docs/求职/互联网行业-郑州.md @@ -160,6 +160,4 @@ UU 跑腿的工作环境以及各种福利都还算不错! 读者补充:海康威视、APUS、云鸟、亚信科技、牧原食品、小鱼易联、神州信息、云智慧都在郑州招开发工程师。 - - -> 转载自 CS 指南 :https://zhuanlan.zhihu.com/p/412688735 \ No newline at end of file +> 转载自 CS 指南 : diff --git a/docs/求职/写给软件工程师的建议.md b/docs/求职/写给软件工程师的建议.md index 49b81047..9e51ecd7 100644 --- a/docs/求职/写给软件工程师的建议.md +++ b/docs/求职/写给软件工程师的建议.md @@ -4,11 +4,11 @@ title: 写给软件工程师的建议 data: 2022 年 3 月 21 日 --- -# 前言 +## 前言 最近一段时间,通过和不同的人对话,脑海中涌现出了一些想法。另一方面也意识到自己正处在职业生涯的某个节点上,回顾从业的这几年,有得有失,所以想借这篇文章聊一下工程师成长这个话题,旨在能给大家带来一点点思考。受自身经验所限,这些观点不一定对,希望朋友们可以辩证的去思考。因为自己的职业属性,这里讨论的仅限于软件工程师这个群体。当然如果下面这些经验之谈能帮助到更多其他领域的同学,那我也荣幸之至。下面是正文,会分享几个个人认为工程师成长之路上很重要的点。 -# 基础很重要 +## 基础很重要 我之前作为一个求职者在面试的时候,喜欢问面试官一个问题:“你觉得优秀的工程师有哪些特质?”不同的面试官给出的答案不尽相同,但是他们几乎全都肯定了基础的重要性。 @@ -20,7 +20,7 @@ data: 2022 年 3 月 21 日 说了这么多,那么怎么样培养建立基础呢?我的答案是:**刻意练习**。明确自己的弱项,然后不停地反复地去刻意练习它。我刚上大学那会儿,每次上台讲话都会超级紧张,紧张到发抖冒汗。后来我做了个尝试,去学校的电信营业厅卖手机。这样每天都要被迫和许多人讲话,慢慢地学会了比较从容地面对人群讲话。有一个著名的一万小时定律,它说的是要成为某个领域的专家,需要 10000 小时。其实如果能在某一项上,坚持练习 1000 小时,就已经非常非常厉害了。 -# 培养技术品味 +## 培养技术品味 品味这个东西很难讲清楚。对设计师来说,审美品味是必备的,对于软件工程师来说,同样也要有对于技术的审美,需要知道什么是好的,是优雅的。而且我发现技术品味跟工作年限并没有太大的关系,更多跟个人的眼界有关系。当你看到的优秀的东西足够多,慢慢地也会具备识别能力。 @@ -28,7 +28,7 @@ data: 2022 年 3 月 21 日 另外想推荐一本书《重构,改善既有代码的设计》。很庆幸我在学校图书馆某个角落翻到了这本书,让我知道了什么是好的代码。 -# 从错误中成长 +## 从错误中成长 人非圣贤,是人都会犯错,尤其是对软件开发者来说,犯错更是一件再正常不过的事。之前听公司里一位前辈分享,他说现在的年轻人越来越谨慎,不敢犯错,怕承担责任,但其实犯错有它的积极意义。 @@ -39,7 +39,7 @@ data: 2022 年 3 月 21 日 这种可以让人铭记终身的case,对个人的成长是很有帮助的。所以我想说,不要害怕犯错,犯错后积极总结经验,避免同样的错误发生第二次,才是最重要的。顺便还想说一下,找工作时,团队对于新人的宽容度或者说容错率,我觉得也是求职者需要考虑的一个因素,**好的团队氛围会给予新人充足的试错空间**,这对于新人成长是很重要的。 -# 不要设限 +## 不要设限 不要给自己设限,这一点可以决定自己的成长天花板。比如对于前端工程师,如果限定自己只在这一个范畴,那么你可能会错过很多精彩的东西。三年前是切图仔,三年后还是一个切图仔,只是可能切图更快了,这样可以做的事情会非常局限。而如果把自己放到一个更大的领域,做一个软件工程师,或者去接触产品运营,去了解金融知识,会发现世界又变大了一些。 @@ -47,7 +47,7 @@ data: 2022 年 3 月 21 日 多了解不同领域,跳出固有思维模式,换一个角度来思考,有些问题或许会有不一样的答案。促使我们去了解学习这些的动力,可以是对未知的好奇心,可以是兴趣,可以就是单纯为了赚更多的钱。 -# 以终为始 +## 以终为始 “以终为始”(Begin With The End In Mind),是《高效能人士的七个习惯》里提到的一个习惯。这个习惯讲的是先在脑海里酝酿,然后进行实质创造,换句话说,就是想清楚了目标,然后努力实现之。一位美团工程师在一篇叫《写给工程师的十条精进原则》的文章里也将这一条作为原则之一。 @@ -55,16 +55,14 @@ data: 2022 年 3 月 21 日 最近几年,国内互联网公司盛行 OKR 文化,OKR 算是以终为始这个原则的有力实践。这个制度本身是好的,只不过在实践过程中,慢慢流于形式,变成了披着 OKR 外壳的 KPI,这也招致很多人的吐槽。这个话题可以另写一篇文章来聊了。 -# 保持身体健康 +## 保持身体健康 这一点,也是我认为最重要的一点,所以放在了最后。身体是革命的本钱,没健康的身体,其他任何事情都无从谈起。健康这个东西,只有在失去了它之后才会真正意识到它有多么重要。一些俗套的祝福语,“身体健康”、“幸福快乐”等等,我发现确实是人最需要也最重要的东西。所以,加强体育锻炼,多出去走走吧。人生路还很漫长,有强健的身体,才能正常走完这漫漫长路。 -# 总结 +## 总结 以上是我认为工程师成长路上很重要的几点。有些想法可能会随着年龄的增长、阅历的提升而改变,也希望最好会变化,毕竟如果一成不变,意味着也就没有成长了。 - - > 转载《写给软件工程师的几条成长建议》 > -> 作者:FrankXiong 地址:[点击打开](https://blog.skrskrskrskr.com/article/%E5%86%99%E7%BB%99%E8%BD%AF%E4%BB%B6%E5%B7%A5%E7%A8%8B%E5%B8%88%E7%9A%84%E5%87%A0%E6%9D%A1%E6%88%90%E9%95%BF%E5%BB%BA%E8%AE%AE/) \ No newline at end of file +> 作者:FrankXiong 地址:[点击打开](https://blog.skrskrskrskr.com/article/%E5%86%99%E7%BB%99%E8%BD%AF%E4%BB%B6%E5%B7%A5%E7%A8%8B%E5%B8%88%E7%9A%84%E5%87%A0%E6%9D%A1%E6%88%90%E9%95%BF%E5%BB%BA%E8%AE%AE/) diff --git a/docs/求职/反向面试.md b/docs/求职/反向面试.md index 77267f12..985fecb6 100644 --- a/docs/求职/反向面试.md +++ b/docs/求职/反向面试.md @@ -4,8 +4,8 @@ title: 反向面试 data: 2022年1月22日 --- -> 大部分翻译自:https://github.com/viraptor/reverse-interview ,亦有其他网友补充。 -> 译者总结的一份适合突击记忆的简洁版 LeetCode 题解和面试问题,也欢迎 Star。https://github.com/yifeikong/interview +> 大部分翻译自: ,亦有其他网友补充。 +> 译者总结的一份适合突击记忆的简洁版 LeetCode 题解和面试问题,也欢迎 Star。 下面列表里的问题对于参加技术面试的人来说可能有些用。 列表里的问题并不一定适用于某个特定的职位或者工作类型,也没有排序 最开始的时候这只是我自己的问题列表,但是慢慢地添加了一些我觉得可能让我对这家公司亮红牌的问题。 @@ -31,7 +31,6 @@ data: 2022年1月22日 请记住事情总是灵活的,组织的结构调整也会经常发生。拥有一个 bug 追踪系统并不会保证高效处理 bug。 CI/CD (持续集成系统) 也不一定保证交付时间会很短。 - ### 职责 - On-call (电话值班)的计划或者规定是什么?值班或者遇到问题加班时候有加班费吗? @@ -213,11 +212,11 @@ CI/CD (持续集成系统) 也不一定保证交付时间会很短。 Find more inspiration for questions in: - - [The Joel Test: 12 Steps to Better Code](https://www.joelonsoftware.com/2000/08/09/the-joel-test-12-steps-to-better-code/) by Joel Spolsky - - [Questions I'm asking in interviews](https://jvns.ca/blog/2013/12/30/questions-im-asking-in-interviews/) by Julia Evans +- [The Joel Test: 12 Steps to Better Code](https://www.joelonsoftware.com/2000/08/09/the-joel-test-12-steps-to-better-code/) by Joel Spolsky +- [Questions I'm asking in interviews](https://jvns.ca/blog/2013/12/30/questions-im-asking-in-interviews/) by Julia Evans ### License [![Creative Commons License](https://i.creativecommons.org/l/by-sa/4.0/88x31.png)](https://creativecommons.org/licenses/by-sa/4.0/) -This work is licensed under a [Creative Commons Attribution-ShareAlike 4.0 International License](https://creativecommons.org/licenses/by-sa/4.0/). \ No newline at end of file +This work is licensed under a [Creative Commons Attribution-ShareAlike 4.0 International License](https://creativecommons.org/licenses/by-sa/4.0/). diff --git a/docs/求职/职业发展路线图.md b/docs/求职/职业发展路线图.md index 02be6b4b..a0f6c913 100644 --- a/docs/求职/职业发展路线图.md +++ b/docs/求职/职业发展路线图.md @@ -25,7 +25,6 @@ data: 2022 年 2 月 17 日 - 专家线路主要和机器打交道,需要不断地迭代项目,优化数据和性能; - 管理线路主要和人打交道,需要控制资源和进度,随时要和下属谈心,向上级汇报。 - 如果觉得自己情商不高,搞不定领导和女人,或者觉得和人打交道非常内耗,需要很多时间恢复精力,那可能不太适合走管理路线。 注意,能不能当领导不仅仅看技术实力,有时候也看公司发展、机遇、情商、站队等,这都是不确定的事情。 @@ -54,7 +53,6 @@ SOHO 的原因有很多,比如: - 觉得工资不够,想得到更多的回报; - 喜欢折腾,不管成功失败,经历也是人生重要的一部分。 - SOHO 的风险和收益都很高,如果你的产品和服务卖不出去,那你就赚不到钱,生活会变得艰辛,如果你的切入点正确,而且具备相应的能力,那么年入百万也不多。 不太推荐的 SOHO 模式就是外包接单,吃了上顿没下顿,也不能持续积累资源;说白了,干就有,不干就没有。 @@ -74,7 +72,6 @@ SOHO 是比较自由的,没有人可以约束你,你可以十点起床,也 - SOHO 是过日子,一般规模不大,收入也不多,团队中往往只有创始人生活得比较潇洒,员工还在温饱线上挣扎。 - 创业是干大事,要追求规模,不断拿投资,直到上市或者被收购,它的营收规模是 N 个亿,足够让团队中的很多人实现人生目标。 - 如果你只是想多挣点钱,改善生活水平,那我劝你不要去创业,SOHO 就挺好的,压力不大,精神舒适。 创业是一个非常艰辛的过程,你首要追求的不是利润,而是规模,所以你要快速地扩张,一年翻 10 倍。从 0 到 1 是一座山,从 1 到 10,再到 100、1000…… 也都是一座山,要想创业成功,你需要跨越很多障碍。 @@ -88,7 +85,6 @@ SOHO 是比较自由的,没有人可以约束你,你可以十点起床,也 - 如果创业公司能够快速成长起来,那你就是人生赢家,登上了人生顶峰; - 如果创业公司经营不善而倒闭,那也主要是 CEO 的责任,不是 CTO 的责任,你换一家创业公司继续做 CTO 就行。 - 如果你有大厂工作经验,而且能独当一面,那么很容易进入初始创业公司担任 CTO。大厂工作经验是一生的光环,它和学历一样,熠熠发光。 另外,如果你 SOHO 做出的产品非常 NB,被投资人看上,那么也可以进入创业模式。 diff --git a/docs/求职/职业规划建议.md b/docs/求职/职业规划建议.md index 9247da52..18be87d1 100644 --- a/docs/求职/职业规划建议.md +++ b/docs/求职/职业规划建议.md @@ -17,10 +17,10 @@ data: 2022年1月21日 ## 总结 -**反推即可知当下可为不可为** +反推即可知**当下可为不可为** 祝愿看到这篇文章的每一位好友 早日暴富富富富富富富 -💰💰💰 \ No newline at end of file +💰💰💰 diff --git a/docs/社区/如何向开源社区提问.md b/docs/社区/如何向开源社区提问.md index 1b9cd72c..ef4b232c 100644 --- a/docs/社区/如何向开源社区提问.md +++ b/docs/社区/如何向开源社区提问.md @@ -79,7 +79,7 @@ 如果社区提供了问题模板,一定要仔细看下。比如 Google Code 社区,当你创建一个问题时,会自动提供以下模板: -``` +```text What steps will reproduce the problem? 该问题的重现步骤是什么? 1. @@ -108,13 +108,13 @@ Please provide any additional information below. 对于很多需要代码来描述的问题,要尤其注意格式,比如 -``` +```text seajs.use('jquery',function($){$(document).ready(function() { /* ... */ })}); ``` 可读性不如 -``` +```text seajs.use('jquery', function($) { $(document).ready(function() { // ... @@ -192,4 +192,4 @@ GitHub 的 Markdown 语法可以很好地支持代码排版、语法高亮等, ### 不要忘记感谢 -最后,记得感谢。很多开源软件的作者,都是利用业余时间在创作代码。你的感谢,汇集许许多多大家的感谢,会让开源社区充满爱与力量。 \ No newline at end of file +最后,记得感谢。很多开源软件的作者,都是利用业余时间在创作代码。你的感谢,汇集许许多多大家的感谢,会让开源社区充满爱与力量。 diff --git a/docs/社区/如何有效报告 BUG.md b/docs/社区/如何有效报告 BUG.md index 668e92bc..29ba1f2c 100644 --- a/docs/社区/如何有效报告 BUG.md +++ b/docs/社区/如何有效报告 BUG.md @@ -120,7 +120,7 @@ - *慎用代词*。诸如“它”,“窗体”这些词,当它们指代不清晰的时候不要用。来看看这句话:“我运行了FooApp,它弹出一个警告窗口,我试着关掉它,它就崩溃了。”这种表述并不清晰,用户究竟关掉了哪个窗口?是警告窗口还是整个FooApp程序?您可以这样说,“我运行FooApp程序时弹出一个警告窗口,我试着关闭警告窗口,FooApp崩溃了。”这样虽然罗嗦点,但是很清晰不容易产生误解。 - *检查*。重新读一遍您写的bug报告,*您*觉得它是否清晰?如果您列出了一系列能导致程序出错的操作,那么照着做一遍,看看您是不是漏写了一步。 -### 小结: +### 小结 - bug报告的首要目的是让程序员亲眼看到错误。如果您不能亲自做给他们看,给他们能使程序出错的详细的操作步骤。 - 如果首要目的不能达成,程序员*不能*看到程序出错。这就需要bug报告的第二个目的来描述程序的什么地方出毛病了。详细的描述每一件事情:您看到了什么,您想看到什么,把错误消息记下来,*尤其*是“错误消息号”。 @@ -142,4 +142,4 @@ 英文版:[anakin@pobox.com](mailto:anakin@pobox.com) -中文版:[dasn@users.sf.net](https://www.chiark.greenend.org.uk/~sgtatham/dasn@users.sf.net) \ No newline at end of file +中文版:[dasn@users.sf.net](https://www.chiark.greenend.org.uk/~sgtatham/dasn@users.sf.net) diff --git a/docs/社区/提问的智慧.md b/docs/社区/提问的智慧.md index 35d9d53e..c2ab1faa 100644 --- a/docs/社区/提问的智慧.md +++ b/docs/社区/提问的智慧.md @@ -1,13 +1,10 @@ - -[![PRs Welcome](https://camo.githubusercontent.com/0ff11ed110cfa69f703ef0dcca3cee6141c0a8ef465e8237221ae245de3deb3d/68747470733a2f2f696d672e736869656c64732e696f2f62616467652f5052732d77656c636f6d652d627269676874677265656e2e7376673f7374796c653d666c61742d737175617265)](https://github.com/ryanhanwu/How-To-Ask-Questions-The-Smart-Way/pulls?q=is%3Apr+is%3Aopen+sort%3Aupdated-desc) - -**How To Ask Questions The Smart Way** +## How To Ask Questions The Smart Way Copyright © 2001,2006,2014 Eric S. Raymond, Rick Moen 本指南英文版版权为 Eric S. Raymond, Rick Moen 所有。 -原文网址:http://www.catb.org/~esr/faqs/smart-questions.html +原文网址: Copyleft 2001 by D.H.Grand(nOBODY/Ginux), 2010 by Gasolin, 2015 by Ryan Wu @@ -150,9 +147,7 @@ Stack Exchange 已经成长到[超过一百个网站](https://stackexchange.com/ 一个好标题范例是`目标 —— 差异`式的描述,许多技术支持组织就是这样做的。在`目标`部分指出是哪一个或哪一组东西有问题,在`差异`部分则描述与期望的行为不一致的地方。 > 蠢问题:救命啊!我的笔记本电脑不能正常显示了! - > 聪明问题:X.org 6.8.1 的鼠标光标会变形,某牌显卡 MV1005 芯片组。 - > 更聪明问题:X.org 6.8.1 的鼠标光标,在某牌显卡 MV1005 芯片组环境下 - 会变形。 编写`目标 —— 差异` 式描述的过程有助于你组织对问题的细致思考。是什么被影响了? 仅仅是鼠标光标或者还有其它图形?只在 X.org 的 X 版中出现?或只是出现在 6.8.1 版中? 是针对某牌显卡芯片组?或者只是其中的 MV1005 型号? 一个黑客只需瞄一眼就能够立即明白你的环境**和**你遇到的问题。 @@ -263,11 +258,11 @@ Stack Exchange 已经成长到[超过一百个网站](https://stackexchange.com/ 告诉黑客们你认为问题是怎样造成的并没什么帮助。(如果你的推断如此有效,还用向别人求助吗?),因此要确信你原原本本告诉了他们问题的症状,而不是你的解释和理论;让黑客们来推测和诊断。如果你认为陈述自己的猜测很重要,清楚地说明这只是你的猜测,并描述为什么它们不起作用。 -**蠢问题** +- 蠢问题 > 我在编译内核时接连遇到 SIG11 错误, 我怀疑某条飞线搭在主板的走线上了,这种情况应该怎样检查最好? -**聪明问题** +- 聪明问题 > 我的组装电脑是 FIC-PA2007 主机板搭载 AMD K6/233 CPU(威盛 Apollo VP2 芯片组), 256MB Corsair PC133 SDRAM 内存,在编译内核时,从开机 20 分钟以后就频频产生 SIG11 错误, 但是在头 20 分钟内从没发生过相同的问题。重新启动也没有用,但是关机一晚上就又能工作 20 分钟。 所有内存都换过了,没有效果。相关部分的标准编译记录如下…。 @@ -287,11 +282,11 @@ Stack Exchange 已经成长到[超过一百个网站](https://stackexchange.com/ 经常寻求技术帮助的人在心中有个更高层次的目标,而他们在自以为能达到目标的特定道路上被卡住了,然后跑来问该怎么走,但没有意识到这条路本身就有问题。结果要费很大的劲才能搞定。 -**蠢问题** +- 蠢问题 > 我怎样才能从某绘图程序的颜色选择器中取得十六进制的 RGB 值? -**聪明问题** +- 聪明问题 > 我正试着用替换一幅图片的色码(color table)成自己选定的色码,我现在知道的唯一方法是编辑每个色码区块(table slot), 但却无法从某绘图程序的颜色选择器取得十六进制的 RGB 值。 @@ -381,8 +376,6 @@ Stack Exchange 已经成长到[超过一百个网站](https://stackexchange.com/ ## 如何解读答案 - - ### RTFM 和 STFW:如何知道你已完全搞砸了 有一个古老而神圣的传统:如果你收到`RTFM(Read The Fucking Manual)`的回应,回答者认为你**应该去读他妈的手册**。当然,基本上他是对的,你应该去读一读。 @@ -464,32 +457,22 @@ Jeff Bigler 的观察总结和这个相关也值得一读 (**[tact filters](http ------ - - > 问题:我能在哪找到 X 程序或 X 资源? 回答:就在我找到它的地方啊,白痴 —— 搜索引擎的那一头。天哪!难道还有人不会用 [Google](https://www.google.com/) 吗? - - > 问题:我怎样用 X 做 Y? 回答:如果你想解决的是 Y ,提问时别给出可能并不恰当的方法。这种问题说明提问者不但对 X 完全无知,也对 Y 要解决的问题糊涂,还被特定形势禁锢了思维。最好忽略这种人,等他们把问题搞清楚了再说。 - - > 问题:如何设定我的 shell 提示?? 回答:如果你有足够的智慧提这个问题,你也该有足够的智慧去 [RTFM](https://github.com/ryanhanwu/How-To-Ask-Questions-The-Smart-Way/blob/main/README-zh_CN.md#RTFM),然后自己去找出来。 - - > 问题:我可以用 Bass-o-matic 文件转换工具将 AcmeCorp 文件转换为 TeX 格式吗? 回答:试试看就知道了。如果你试过,你就知道了答案,就不用浪费我的时间了。 - - > 问题:我的{程序/设定/SQL 语句}没有用 回答:这不算是问题吧,我对要我问你二十个问题才找得出你真正问题的问题没兴趣 —— 我有更有意思的事要做呢。在看到这类问题的时候,我的反应通常不外如下三种 @@ -498,30 +481,22 @@ Jeff Bigler 的观察总结和这个相关也值得一读 (**[tact filters](http - 真糟糕,希望你能搞定。 - 这关我屁事? - - > 问题:我的 Windows 电脑有问题,你能帮我吗? 回答:能啊,扔掉微软的垃圾,换个像 Linux 或 BSD 的开源操作系统吧。 注意:如果程序有官方版 Windows 或者与 Windows 有互动(如 Samba),你**可以**问与 Windows 相关的问题,只是别对问题是由 Windows 操作系统而不是程序本身造成的回复感到惊讶, 因为 Windows 一般来说实在太烂,这种说法通常都是对的。 - - > 问题:我的程序不会动了,我认为系统工具 X 有问题 回答:你完全有可能是第一个注意到被成千上万用户反复使用的系统调用与函数库文件有明显缺陷的人,更有可能的是你完全没有根据。不同凡响的说法需要不同凡响的证据,当你这样声称时,你必须有清楚而详尽的缺陷说明文件作后盾。 - - > 问题:我在安装 Linux(或者 X )时有问题,你能帮我吗? 回答:不能,我只有亲自在你的电脑上动手才能找到毛病。还是去找你当地的 Linux 使用群组者寻求实际的指导吧(你能在[这儿](http://www.linux.org/groups/index.html)找到用户群组的清单)。 注意:如果安装问题与某 Linux 的发行版有关,在它的邮件列表、论坛或本地用户群组中提问也许是恰当的。此时,应描述问题的准确细节。在此之前,先用 `Linux` 和**所有**被怀疑的硬件作关键词仔细搜索。 - - > 问题:我怎么才能破解 root 帐号/窃取 OP 特权/读别人的邮件呢? 回答:想要这样做,说明了你是个卑鄙小人;想找个黑客帮你,说明你是个白痴! @@ -620,4 +595,4 @@ Jeff Bigler 的观察总结和这个相关也值得一读 (**[tact filters](http ## 鸣谢 -Evelyn Mitchel 贡献了一些愚蠢问题例子并启发了编写`如何更好地回答问题`这一节, Mikhail Ramendik 贡献了一些特别有价值的建议和改进。 \ No newline at end of file +Evelyn Mitchel 贡献了一些愚蠢问题例子并启发了编写`如何更好地回答问题`这一节, Mikhail Ramendik 贡献了一些特别有价值的建议和改进。 diff --git a/docs/算法/常见算法.md b/docs/算法/常见算法.md index a915b1ea..5b0036ea 100644 --- a/docs/算法/常见算法.md +++ b/docs/算法/常见算法.md @@ -200,4 +200,3 @@ while money > 0: needs_go_on = True print('你破产了, 游戏结束!') ``` - diff --git a/docs/运维/Linux/常用命令.md b/docs/运维/Linux/常用命令.md index 846af08f..c9554027 100644 --- a/docs/运维/Linux/常用命令.md +++ b/docs/运维/Linux/常用命令.md @@ -6,17 +6,18 @@ data: 2022年3月4日 --- ## 简介 + 一台完整的计算机是由运算器、控制器、存储器、输入/输出等多种硬件设备共同组成的,而能让各种硬件设备各司其职且又能协同运行的东西就是系统内核。Linux 系统的内核负责完成对硬件资源的分配、调度等管理任务,对系统的正常运行起着十分重要的作用。 Shell就是终端程序的统称,它充当了人与内核(硬件)之间的翻译官,用户把一些命令“告诉”终端程序,它就会调用相应的程序服务去完成某些工作。现在包括红帽系统在内的许多主流Linux系统默认使用的终端是 Bash(Bourne-Again SHell)解释器,这个 Bash 解释器主要有以下4项优势: - - 通过上下方向键来调取执行过的 Linux 命令; - - 命令或参数仅需输入前几位就可以用 Tab 键补全; - - 具有强大的批处理脚本; - - 具有实用的环境变量功能。 +- 通过上下方向键来调取执行过的 Linux 命令; +- 命令或参数仅需输入前几位就可以用 Tab 键补全; +- 具有强大的批处理脚本; +- 具有实用的环境变量功能。 ### 执行命令 -``` +```shell 命令名称 [命令参数] [命令对象] ``` @@ -34,7 +35,7 @@ Linux命令参数的长格式与短格式示例 - **命令对象**:一般指要处理的文件、目录、用户等资源名称,也就是命令执行后的“承受方”。例如创建一位叫小明的用户、查看一个叫工资表的文件、重启一个IP为192.168.10.10的系统等。 -**Linux系统中的命令、参数、对象都是严格区分大小写的** +Linux系统中的**命令、参数、对象都是严格区分大小写**的 ## 帮助文档 @@ -160,7 +161,7 @@ date "+%j" 用于设置系统的时间,英文全称为“time date control”,语法格式: -``` +```shell timedatectl [参数] ``` @@ -208,7 +209,7 @@ timedatectl set-time 9:30 wget 命令用于在终端命令行中下载网络文件,英文全称为“web get”,语法格式: -``` +```shell wget [参数] 网址 ``` @@ -225,7 +226,7 @@ wget [参数] 网址 示例: -``` +```shell wget www.7wate.com # Resolving www.7wate.com (www.7wate.com)... 182.118.11.21 @@ -237,7 +238,7 @@ wget www.7wate.com ps 命令用于查看系统中的进程状态,英文全称为“processes”,语法格式: -``` +```shell ps [参数] ``` @@ -293,7 +294,7 @@ nice -n -20 bash pidof 命令用于查询某个指定服务进程的 PID 号码值,语法格式: -``` +```shell pidof [参数] 服务名称 ``` @@ -786,7 +787,7 @@ cut 令用于按“列”提取文本内容,语法格式: cut [参数] 文件名称 ``` -常用参数: +常用参数: | -b | 以字节为单位进行分割 ,仅显示行中指定直接范围的内容 | | --------------- | -------------------------------------------------- | @@ -841,7 +842,7 @@ sort命令用于对文本内容进行再排序,语法格式: sort [参数] 文件名称 ``` -常用参数: +常用参数: | -b | 忽略每行前面开始出的空格字符 | | ------------- | ------------------------------------------------------ | @@ -867,7 +868,7 @@ touch 命令用于创建空白文件或设置文件的时间,语法格式: touch [参数] 文件名称 ``` -常用参数: +常用参数: | -a | 改变档案的读取时间记录 | | ----------- | ------------------------------------------ | @@ -947,7 +948,7 @@ rm [参数] 文件 名称 dd命令用于按照指定大小和个数的数据块来复制文件或转换文件,语法格式: -``` +```shell dd if=参数值of=参数值count=参数值bs=参数值 ``` @@ -997,4 +998,4 @@ tar 参数 文件名称 | -v | 显示压缩或解压的过程 | | -f | 目标文件名 | | -p | 保留原始的权限与属性 | -| -P | 使用绝对路径来压缩 | \ No newline at end of file +| -P | 使用绝对路径来压缩 | diff --git a/docs/运维/Linux/管道符、重定向与环境变量.md b/docs/运维/Linux/管道符、重定向与环境变量.md index dde31a2a..c438694a 100644 --- a/docs/运维/Linux/管道符、重定向与环境变量.md +++ b/docs/运维/Linux/管道符、重定向与环境变量.md @@ -16,7 +16,7 @@ data: 2022年3月4日 *对于重定向中的标准输出模式,可以省略文件描述符 1 不写,而错误输出模式的文件描述符 2 是必须要写的。* -### 输入重定向 +### 输入重定向 符号及其作用 @@ -40,8 +40,6 @@ data: 2022年3月4日 按下键盘上的Shift+反斜杠(\)键即可输入管道符,其执行格式为“命令A | 命令B”。**管道命令符把前一个命令原本要输出到屏幕的信息当作后一个命令的标准输入** -**示例** - ```shell # 输出禁止登录用户行数 grep /sbin/nologin /etc/passwd | wc -l @@ -50,7 +48,7 @@ grep /sbin/nologin /etc/passwd | wc -l ps aux | grep bash ``` -*命令符可以无限组合,例如:命令A | 命令B | 命令C |……* +命令符可以**无限组合**,例如:命令A | 命令B | 命令C |…… > 曾经有位东北的同学做了一个特别贴切的类比:把管道符当做流水线作业,这跟吃顿烧烤是同一个道理,即第一个人负责切肉,第二个人负责串肉,第三个人负责烧烤,最后的处理结果交付给用户。 @@ -107,4 +105,4 @@ Linux系统中最重要的 10 个环境变量 | RANDOM | 生成一个随机数字 | | PS1 | Bash解释器的提示符 | | PATH | 定义解释器搜索用户执行命令的路径 | -| EDITOR | 用户默认的文本编辑器 | \ No newline at end of file +| EDITOR | 用户默认的文本编辑器 | diff --git a/life/食谱/凉菜/凉菜食材处理.md b/life/食谱/凉菜/凉菜食材处理.md index d64c0e08..dd61b6fd 100644 --- a/life/食谱/凉菜/凉菜食材处理.md +++ b/life/食谱/凉菜/凉菜食材处理.md @@ -22,4 +22,4 @@ data: 2022年04月21日 ## 苦菊 -凉水**浸泡十分钟**清洗干净,切段放盘。 \ No newline at end of file +凉水**浸泡十分钟**清洗干净,切段放盘。 diff --git a/life/食谱/早餐/花样蒸蛋.md b/life/食谱/早餐/花样蒸蛋.md index da785350..c6ff9502 100644 --- a/life/食谱/早餐/花样蒸蛋.md +++ b/life/食谱/早餐/花样蒸蛋.md @@ -31,4 +31,4 @@ data: 2022年05月27日 ## 佐料 -喜欢吃酸甜味就加番茄酱,总之喜欢吃什么加什么!!! \ No newline at end of file +喜欢吃酸甜味就加番茄酱,总之喜欢吃什么加什么!!! diff --git a/life/食谱/早餐/蒸蛋.md b/life/食谱/早餐/蒸蛋.md index a8cda384..4a94d764 100644 --- a/life/食谱/早餐/蒸蛋.md +++ b/life/食谱/早餐/蒸蛋.md @@ -22,4 +22,4 @@ data: 2022年05月27日 ## 佐料 -喜欢吃酸甜味就加番茄酱,总之喜欢吃什么加什么!!! \ No newline at end of file +喜欢吃酸甜味就加番茄酱,总之喜欢吃什么加什么!!!