<?xml version="1.0" encoding="utf-8" standalone="yes"?><rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom"><channel><title>白菜</title><link>https://blog.baicai.me/</link><description>Recent content on 白菜</description><generator>Hugo -- gohugo.io</generator><language>zh-CN</language><managingEditor>admin@baicai.me (白菜)</managingEditor><webMaster>admin@baicai.me (白菜)</webMaster><copyright>baicai.me</copyright><lastBuildDate>Wed, 31 Dec 2025 14:57:20 +0800</lastBuildDate><atom:link href="https://blog.baicai.me/index.xml" rel="self" type="application/rss+xml"/><item><title>卸载腾讯云的云监控组件 sgagent、barad_agent、YDService</title><link>https://blog.baicai.me/article/2025/qcloud_uninstall/</link><pubDate>Wed, 31 Dec 2025 14:57:20 +0800</pubDate><author>admin@baicai.me (白菜)</author><guid>https://blog.baicai.me/article/2025/qcloud_uninstall/</guid><description>&lt;p>相关云监控的进程分别是&lt;code>sgagent&lt;/code>,&lt;code>barad_agent&lt;/code>和&lt;code>YDService&lt;/code>&lt;/p>
&lt;h3 id="删除云监控插件">删除云监控插件&lt;/h3>
&lt;div class="highlight">&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;">&lt;code class="language-bash" data-lang="bash">&lt;span style="display:flex;">&lt;span>/usr/local/qcloud/stargate/admin/uninstall.sh
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>/usr/local/qcloud/YunJing/uninst.sh
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>/usr/local/qcloud/monitor/barad/admin/uninstall.sh
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>&lt;h3 id="删除自动化助手">删除自动化助手&lt;/h3>
&lt;div class="highlight">&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;">&lt;code class="language-bash" data-lang="bash">&lt;span style="display:flex;">&lt;span>sudo wget -qO - https://tat-1258344699.cos.accelerate.myqcloud.com/tat_agent/uninstall.sh | sudo sh
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>&lt;p>或&lt;/p>
&lt;div class="highlight">&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;">&lt;code class="language-bash" data-lang="bash">&lt;span style="display:flex;">&lt;span>systemctl stop tat_agent
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>systemctl disable tat_agent
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>rm -f /etc/systemd/system/tat_agent.service
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>rm -rf /usr/local/qcloud
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>&lt;h3 id="检查-agent-进程是否还在">检查 agent 进程是否还在&lt;/h3>
&lt;div class="highlight">&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;">&lt;code class="language-bash" data-lang="bash">&lt;span style="display:flex;">&lt;span>ps -A | grep agent
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>&lt;p>如果执行后没有任何显示，说明已经清理干净&lt;/p>
&lt;h3 id="删除自启">删除自启&lt;/h3>
&lt;p>进入服务器 &lt;code>/etc/rc.d/rc.local&lt;/code> 目录，删除所有&lt;code>/usr/local/qcloud/&lt;/code>路径的信息。&lt;/p>
&lt;h3 id="官方文档">官方文档&lt;/h3>
&lt;pre tabindex="0">&lt;code>云监控：https://cloud.tencent.com/document/product/248/53584
YDService ：https://cloud.tencent.com/document/product/296/9928
自主化助手：https://cloud.tencent.com/document/product/1340/50822
&lt;/code>&lt;/pre></description></item><item><title>当 PostgreSQL 查询占用 CPU 很高时，找出是谁在吃 CPU</title><link>https://blog.baicai.me/article/2025/analyze/</link><pubDate>Sat, 20 Dec 2025 15:09:26 +0800</pubDate><author>admin@baicai.me (白菜)</author><guid>https://blog.baicai.me/article/2025/analyze/</guid><description>&lt;h3 id="找出是谁在吃-cpu">找出「是谁」在吃 CPU&lt;/h3>
&lt;h4 id="查看当前正在跑的高-cpu-查询">查看当前正在跑的高 CPU 查询&lt;/h4>
&lt;pre tabindex="0">&lt;code>SELECT
pid,
usename,
datname,
state,
now() - query_start AS running_time,
wait_event_type,
wait_event,
query
FROM pg_stat_activity
WHERE state = &amp;#39;active&amp;#39;
ORDER BY running_time DESC;
&lt;/code>&lt;/pre>&lt;p>重点关注：
running_time 很长的
query 是否是复杂 SELECT
是否反复出现同一条 SQL&lt;/p>
&lt;h4 id="看耗-cpu-的-sql">看耗 CPU 的 SQL&lt;/h4>
&lt;p>如果开启了 pg_stat_statements&lt;/p>
&lt;p>查总 CPU 消耗最高：&lt;/p>
&lt;pre tabindex="0">&lt;code>SELECT
query,
calls,
total_exec_time,
mean_exec_time,
rows
FROM pg_stat_statements
ORDER BY total_exec_time DESC
LIMIT 10;
&lt;/code>&lt;/pre>&lt;p>查单次最慢：&lt;/p>
&lt;pre tabindex="0">&lt;code>SELECT
query,
max_exec_time,
calls
FROM pg_stat_statements
ORDER BY max_exec_time DESC
LIMIT 10;
&lt;/code>&lt;/pre>&lt;p>查调用次数最多&lt;/p>
&lt;pre tabindex="0">&lt;code>SELECT
query,
calls
FROM pg_stat_statements
ORDER BY calls DESC
LIMIT 10;
&lt;/code>&lt;/pre>&lt;h4 id="检查连接数">检查连接数&lt;/h4>
&lt;p>&lt;code>SELECT count(*) FROM pg_stat_activity;&lt;/code>&lt;/p>
&lt;h4 id="看当前正在跑的-sql">看当前正在跑的 SQL&lt;/h4>
&lt;pre tabindex="0">&lt;code>SELECT
pid,
now() - query_start AS runtime,
state,
query
FROM pg_stat_activity
WHERE state = &amp;#39;active&amp;#39;
ORDER BY runtime DESC;
&lt;/code>&lt;/pre>&lt;h4 id="系统确认-cpu-高--io-高">系统确认 CPU 高 ≠ I/O 高&lt;/h4>
&lt;pre tabindex="0">&lt;code>SELECT
datname,
blks_read,
blks_hit
FROM pg_stat_database;
&lt;/code>&lt;/pre>&lt;p>&lt;code>blks_hit&lt;/code> 高 → CPU 计算型
&lt;code>blks_read&lt;/code> 高 → I/O 型问题&lt;/p>
&lt;h4 id="是否有-autovacuum-问题">是否有 autovacuum 问题&lt;/h4>
&lt;pre tabindex="0">&lt;code>SELECT relname, n_dead_tup
FROM pg_stat_user_tables
ORDER BY n_dead_tup DESC;
&lt;/code>&lt;/pre>&lt;p>死元组多：
查询变慢
CPU 增高&lt;/p>
&lt;h3 id="启用-pg_stat_statements-扩展">启用 pg_stat_statements 扩展&lt;/h3>
&lt;p>docker-compose&lt;/p>
&lt;pre tabindex="0">&lt;code>services:
db_postgres:
image: postgres:18
command:
- &amp;#34;postgres&amp;#34;
- &amp;#34;-c&amp;#34;
- &amp;#34;shared_preload_libraries=pg_stat_statements&amp;#34;
- &amp;#34;-c&amp;#34;
- &amp;#34;pg_stat_statements.max=10000&amp;#34;
- &amp;#34;-c&amp;#34;
- &amp;#34;pg_stat_statements.track=all&amp;#34;
&lt;/code>&lt;/pre>&lt;p>或者修改 &lt;code>/var/lib/postgresql/data/postgresql.conf&lt;/code> 加入：&lt;/p>
&lt;pre tabindex="0">&lt;code>shared_preload_libraries = &amp;#39;pg_stat_statements&amp;#39;
pg_stat_statements.max = 10000
pg_stat_statements.track = all
&lt;/code>&lt;/pre>&lt;h4 id="在数据库里创建扩展">在数据库里创建扩展&lt;/h4>
&lt;pre tabindex="0">&lt;code>CREATE EXTENSION IF NOT EXISTS pg_stat_statements;
&lt;/code>&lt;/pre>&lt;p>验证是否成功:&lt;/p>
&lt;pre tabindex="0">&lt;code>SELECT count(*) FROM pg_stat_statements;
&lt;/code>&lt;/pre>&lt;p>如果有数字结果 → 成功&lt;/p>
&lt;pre tabindex="0">&lt;code>-- =====================================
-- 📊 PostgreSQL Top 10 SQL 分析模板
-- 时间单位：秒 (s)
-- =====================================
SELECT
query,
calls AS execution_count,
total_exec_time / 1000.0 AS total_time_sec, -- 总耗时（秒）
mean_exec_time / 1000.0 AS avg_time_sec, -- 平均耗时（秒）
max_exec_time / 1000.0 AS max_time_sec, -- 单次最大耗时（秒）
rows AS total_rows_returned
FROM pg_stat_statements
ORDER BY total_exec_time DESC
LIMIT 10;
&lt;/code>&lt;/pre>&lt;pre>&lt;code>字段解释
字段 含义
query SQL 文本
execution_count SQL 被调用次数
total_time_sec SQL 总耗时，秒为单位
avg_time_sec SQL 平均执行时间，秒为单位
max_time_sec SQL 单次最大耗时，秒为单位
total_rows_returned SQL 总返回行数
&lt;/code>&lt;/pre>
&lt;h3 id="优化建议">优化建议&lt;/h3>
&lt;h4 id="建立索引可有效应对大部分的耗时查询">建立索引可有效应对大部分的耗时查询&lt;/h4>
&lt;p>通过 PostgreSQL 内置的系统视图或 &lt;code>\d&lt;/code> 命令查看已经创建的索引&lt;/p>
&lt;p>&lt;code>\d 表名&lt;/code>&lt;/p>
&lt;h4 id="检查-work_mem">检查 work_mem&lt;/h4>
&lt;p>如果聚合 + 排序占用 CPU 高，可以调大：
&lt;code>SET work_mem = '64MB';&lt;/code>&lt;/p>
&lt;h4 id="定期-analyze">定期 ANALYZE&lt;/h4>
&lt;p>&lt;code>ANALYZE 表名;&lt;/code>&lt;/p></description></item><item><title>从 Debian 12 升级到 Debian 13</title><link>https://blog.baicai.me/article/2025/debian_apt_full-upgrade_12to13/</link><pubDate>Tue, 16 Sep 2025 13:56:17 +0800</pubDate><author>admin@baicai.me (白菜)</author><guid>https://blog.baicai.me/article/2025/debian_apt_full-upgrade_12to13/</guid><description>&lt;p>在进行重大版本升级之前，务必备份所有重要数据。尽管升级过程通常很稳定，但硬件故障或配置错误等意外情况可能会导致数据丢失。&lt;/p>
&lt;p>以下是将Debian 12 (Bookworm) 升级到Debian 13 (Trixie) 的详细步骤。&lt;/p>
&lt;h3 id="备份">备份&lt;/h3>
&lt;p>在开始升级之前，请务必创建一个完整的系统备份，包括：&lt;/p>
&lt;p>所有重要数据和个人文件 (/home 目录)。&lt;/p>
&lt;p>系统配置文件 (/etc 目录)。&lt;/p>
&lt;p>已安装软件包的列表。您可以使用以下命令生成一个列表：&lt;/p>
&lt;pre tabindex="0">&lt;code>Bashsudo dpkg --get-selections &amp;#39;*&amp;#39; &amp;gt; ~/installed-packages.list
&lt;/code>&lt;/pre>&lt;h3 id="第一步-升级现有系统">第一步 升级现有系统&lt;/h3>
&lt;div class="highlight">&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;">&lt;code class="language-bash" data-lang="bash">&lt;span style="display:flex;">&lt;span>apt update
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>apt upgrade
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>apt autoremove
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>apt clean
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>&lt;h3 id="第二步-修改软件源列表">第二步 修改软件源列表&lt;/h3>
&lt;div class="highlight">&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;">&lt;code class="language-bash" data-lang="bash">&lt;span style="display:flex;">&lt;span>sed -i &lt;span style="color:#e6db74">&amp;#39;s/bookworm/trixie/g&amp;#39;&lt;/span> /etc/apt/sources.list
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>&lt;h3 id="第三步-升级">第三步 升级&lt;/h3>
&lt;div class="highlight">&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;">&lt;code class="language-bash" data-lang="bash">&lt;span style="display:flex;">&lt;span>&lt;span style="color:#75715e">#更新软件包索引&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>apt update
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#75715e">#最小系统升级&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>apt upgrade --without-new-pkgs
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#75715e">#完整系统升级&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>apt full-upgrade
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#75715e">#清理和重启&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>apt --purge autoremove
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>reboot
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#75715e">#新的系统对于source.list的内容做了结构上的更新，使得格式更加易读了。可用如下的命令更新 source.list&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#75715e">#此命令可以将原有的source.list做个备份--source.list.bak, 可以放心更新&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>sudo apt modernize-sources
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>&lt;h3 id="确认系统版本">确认系统版本&lt;/h3>
&lt;div class="highlight">&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;">&lt;code class="language-bash" data-lang="bash">&lt;span style="display:flex;">&lt;span>root@debian ~ &lt;span style="color:#75715e"># cat /etc/debian_version &lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>13.0
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>&lt;div class="highlight">&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;">&lt;code class="language-bash" data-lang="bash">&lt;span style="display:flex;">&lt;span>root@debian ~ &lt;span style="color:#75715e"># lsb_release -a&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>No LSB modules are available.
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>Distributor ID: Debian
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>Description: Debian GNU/Linux &lt;span style="color:#ae81ff">13&lt;/span> &lt;span style="color:#f92672">(&lt;/span>trixie&lt;span style="color:#f92672">)&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>Release: &lt;span style="color:#ae81ff">13&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>Codename: trixie
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>&lt;div class="highlight">&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;">&lt;code class="language-bash" data-lang="bash">&lt;span style="display:flex;">&lt;span>root@debian ~ &lt;span style="color:#75715e"># uname -a&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>Linux debian 6.12.35+deb13-amd64 &lt;span style="color:#75715e">#1 SMP PREEMPT_DYNAMIC Debian 6.12.35-1 (2025-07-03) x86_64 GNU/Linu&lt;/span>
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>&lt;p>如果您在升级过程中遇到任何问题，可以查阅Debian官方的升级指南获取更详细的信息和故障排除帮助
&lt;a href="https://www.debian.org/releases/stable/release-notes/upgrading.html#upgrading-the-system">官方文档&lt;/a>&lt;/p></description></item><item><title>在命令行 ssh 时按 &lt;kbd>TAB&lt;/kbd> 自动补全主机名</title><link>https://blog.baicai.me/article/2025/zsh_tab/</link><pubDate>Tue, 09 Sep 2025 20:19:17 +0800</pubDate><author>admin@baicai.me (白菜)</author><guid>https://blog.baicai.me/article/2025/zsh_tab/</guid><description>&lt;p>Zsh + Oh My Zsh&lt;/p>
&lt;p>必须是 zsh 或者 bash，并且补全脚本已经生效&lt;/p>
&lt;div class="highlight">&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;">&lt;code class="language-bash" data-lang="bash">&lt;span style="display:flex;">&lt;span>echo $SHELL
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>echo $0
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>&lt;ul>
&lt;li>输出 /bin/zsh 或 zsh → 正确&lt;/li>
&lt;li>输出 bash → 需要用 bash 的补全方法（和 zsh 不同）&lt;/li>
&lt;/ul>
&lt;p>确认 oh-my-zsh 已安装。&lt;/p>
&lt;h3 id="在-zshrc-里启用插件">在 &lt;code>~/.zshrc&lt;/code> 里启用插件：&lt;/h3>
&lt;pre tabindex="0">&lt;code class="language-conf" data-lang="conf">plugins=(git ssh)
&lt;/code>&lt;/pre>&lt;h3 id="确认-zsh-补全系统已经启用">确认 zsh 补全系统已经启用&lt;/h3>
&lt;p>zsh 的补全系统必须加载：&lt;/p>
&lt;div class="highlight">&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;">&lt;code class="language-bash" data-lang="bash">&lt;span style="display:flex;">&lt;span>autoload -Uz compinit
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>compinit
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>&lt;p>在 ~/.zshrc 中通常 Oh My Zsh 已经自动加载，但如果手动配置过可能没生效。&lt;/p>
&lt;h3 id="重新加载-zshrc-">重新加载 &lt;code>~/.zshrc&lt;/code> ：&lt;/h3>
&lt;p>source ~/.zshrc&lt;/p>
&lt;h3 id="然后输入测试">然后输入测试：&lt;/h3>
&lt;div class="highlight">&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;">&lt;code class="language-bash" data-lang="bash">&lt;span style="display:flex;">&lt;span>ssh db&amp;lt;TAB&amp;gt;
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>&lt;p>就会自动补全到 &lt;code>.ssh/config&lt;/code> 里的 db1、db2。&lt;/p></description></item><item><title>访问世界上每一个经纬度为整数的交叉点</title><link>https://blog.baicai.me/article/2025/the_degree_confluence_project/</link><pubDate>Fri, 28 Mar 2025 17:12:15 +0800</pubDate><author>admin@baicai.me (白菜)</author><guid>https://blog.baicai.me/article/2025/the_degree_confluence_project/</guid><description>&lt;p>该项目的目标是访问世界上每一个经纬度为整数的交叉点，并在每个地点拍照记录。
目前&lt;a href="https://confluence.org/country.php?id=28">中国的进度&lt;/a>是 429/978，平原地区的交叉点基本上被记录完毕了，剩下的都是难啃的骨头。&lt;/p>
&lt;p>the Degree Confluence Project: &lt;a href="https://confluence.org">https://confluence.org&lt;/a>&lt;/p></description></item><item><title>测试服务器能否正常收发邮件</title><link>https://blog.baicai.me/article/2025/test_25/</link><pubDate>Mon, 24 Feb 2025 00:40:55 +0800</pubDate><author>admin@baicai.me (白菜)</author><guid>https://blog.baicai.me/article/2025/test_25/</guid><description>&lt;p>需要收发邮件的话，要注意商家是否开放25端口&lt;/p>
&lt;h3 id="发邮件">发邮件&lt;/h3>
&lt;p>使用&lt;/p>
&lt;pre tabindex="0">&lt;code>telnet smtp.qq.com 25
&lt;/code>&lt;/pre>&lt;p>显示：&lt;/p>
&lt;pre tabindex="0">&lt;code>telnet smtp.qq.com 25
Trying 43.129.255.54...
&lt;/code>&lt;/pre>&lt;p>则无法使用。&lt;/p>
&lt;p>显示：&lt;/p>
&lt;pre tabindex="0">&lt;code>telnet smtp.qq.com 25
Trying 43.129.255.54...
Connected to smtp.qq.com.
Escape character is &amp;#39;^]&amp;#39;.
220 newxmesmtplogicsvrszc5-0.qq.com XMail Esmtp QQ Mail Server.
&lt;/code>&lt;/pre>&lt;p>则可以正常使用。&lt;/p>
&lt;h3 id="使用gmail进行测试也是类似的">使用gmail进行测试也是类似的：&lt;/h3>
&lt;pre tabindex="0">&lt;code>telnet smtp.gmail.com 25
Trying 172.253.117.109...
Connected to smtp.gmail.com.
Escape character is &amp;#39;^]&amp;#39;.
220 smtp.gmail.com ESMTP ca40-20020a056a0206a800b005897bfc2ed3sm7618602pgb.93 - gsmtp
&lt;/code>&lt;/pre>&lt;p>当然，现在Gmail 推荐使用 TLS/SSL 连接，所以也要测试465：&lt;/p>
&lt;pre tabindex="0">&lt;code>telnet smtp.gmail.com 465
&lt;/code>&lt;/pre>&lt;p>显示：&lt;/p>
&lt;pre tabindex="0">&lt;code>telnet smtp.gmail.com 465
Trying 173.194.174.108...
Connected to smtp.gmail.com.
Escape character is &amp;#39;^]&amp;#39;.
&lt;/code>&lt;/pre>&lt;p>正常，超时则无法发送。&lt;/p>
&lt;h3 id="收邮件">收邮件&lt;/h3>
&lt;pre tabindex="0">&lt;code>telnet pop.gmail.com 995
&lt;/code>&lt;/pre>&lt;p>显示：&lt;/p>
&lt;pre tabindex="0">&lt;code>telnet pop.gmail.com 995
Trying 64.233.188.108...
Connected to pop.gmail.com.
Escape character is &amp;#39;^]&amp;#39;.
&lt;/code>&lt;/pre>&lt;p>测试：&lt;/p>
&lt;pre tabindex="0">&lt;code>telnet imap.gmail.com 993
&lt;/code>&lt;/pre>&lt;p>显示：&lt;/p>
&lt;pre tabindex="0">&lt;code>Trying 142.251.8.108...
Connected to imap.gmail.com.
Escape character is &amp;#39;^]&amp;#39;.
&lt;/code>&lt;/pre>&lt;p>这两个都要测试，超时则无法收到邮件。&lt;/p></description></item><item><title>Nginx 出现 Too many open files 错误与修复</title><link>https://blog.baicai.me/article/2025/nginx_too_many_open_files/</link><pubDate>Sun, 23 Feb 2025 22:22:39 +0800</pubDate><author>admin@baicai.me (白菜)</author><guid>https://blog.baicai.me/article/2025/nginx_too_many_open_files/</guid><description>&lt;p>最近服务器遭遇间歇性流量攻击，服务器负载不高，却出现无法打开的情况，查看nginx错误日志，出现大量的“Too many open files”错误，大致意思就是说nginx无法打开更多的文件。&lt;/p>
&lt;p>出现这个错误可能是由于系统的ulimit限制和nginx自身的配置有关系。&lt;/p>
&lt;h3 id="什么是ulimit">什么是ulimit?&lt;/h3>
&lt;p>ulimit命令用来限制系统用户对shell资源的访问。&lt;/p>
&lt;p>假设有这样一种情况，当一台 Linux 主机上同时登陆了 10 个人，在系统资源无限制的情况下，这 10 个用户同时打开了 500 个文档，而假设每个文档的大小有 10M，这时系统的内存资源就会受到巨大的挑战。&lt;/p>
&lt;p>ulimit 用于限制 shell 启动进程所占用的资源，支持以下各种类型的限制：所创建的内核文件的大小、进程数据块的大小、Shell 进程创建文件的大小、内存锁住的大小、常驻内存集的大小、打开文件描述符的数量、分配堆栈的最大大小、CPU 时间、单个用户的最大线程数、Shell 进程所能使用的最大虚拟内存。同时，它支持硬资源和软资源的限制。&lt;/p>
&lt;p>简单来说，ulimit描述符可以对用户打开的文件数量进行限制（不止限制打开文件数量），让单个用户不至于打开较多的文件，导致系统奔溃或者资源不足的情况。
查看ulimit&lt;/p>
&lt;p>既然知道了ulimit是做什么的，首先要先知道系统底层限制到底是多少，ulimit的参数如下：&lt;/p>
&lt;pre tabindex="0">&lt;code>-a：显示目前资源限制的设定；
-c &amp;lt;core文件上限&amp;gt;：设定core文件的最大值，单位为区块；
-d &amp;lt;数据节区大小&amp;gt;：程序数据节区的最大值，单位为KB；
-f &amp;lt;文件大小&amp;gt;：shell所能建立的最大文件，单位为区块；
-H：设定资源的硬性限制，也就是管理员所设下的限制；
-m &amp;lt;内存大小&amp;gt;：指定可使用内存的上限，单位为KB；
-n &amp;lt;文件数目&amp;gt;：指定同一时间最多可开启的文件数；
-p &amp;lt;缓冲区大小&amp;gt;：指定管道缓冲区的大小，单位512字节；
-s &amp;lt;堆叠大小&amp;gt;：指定堆叠的上限，单位为KB；
-S：设定资源的弹性限制；
-t &amp;lt;CPU时间&amp;gt;：指定CPU使用时间的上限，单位为秒；
-u &amp;lt;程序数目&amp;gt;：用户最多可开启的程序数目；
-v &amp;lt;虚拟内存大小&amp;gt;：指定可使用的虚拟内存上限，单位为KB。
&lt;/code>&lt;/pre>&lt;p>由于上述nginx错误是无法打开过多的文件，那么我们直接使用ulimit -n查看同一时间最多可开启的文件数。&lt;/p>
&lt;p>&lt;code>ulimit -n&lt;/code>&lt;/p>
&lt;p>可以看出限制的1024个文件，这就导致nginx尝试打开更多的文件（超出1024个）的时候出现错误“Too many open files”&lt;/p>
&lt;h3 id="修复问题">修复问题&lt;/h3>
&lt;h4 id="修改ulimit限制">修改ulimit限制&lt;/h4>
&lt;p>直接执行命令ulimit -n 65535修改打开文件数，65535指的是需要同一时间最多打开多少个文件，请根据自身情况适当修改。&lt;/p>
&lt;p>ulimit命令修改只对当前的shell有效，退出后失效，如果需要永久生效，需要修改&lt;code>/etc/security/limits.conf&lt;/code>这个文件，在底部加入下面的配置：&lt;/p>
&lt;pre tabindex="0">&lt;code>* soft nproc 65535
* hard nproc 65535
* soft nofile 65535
* hard nofile 65535
&lt;/code>&lt;/pre>&lt;pre tabindex="0">&lt;code> *：代表全局
soft：代表软件
hard：代表硬件
nproc：是代表最大进程数
nofile：是代表最大文件打开数
&lt;/code>&lt;/pre>&lt;p>修改完毕后，再次执行命令：&lt;code>ulimit -n&lt;/code>可以看到设置已经生效!&lt;/p>
&lt;h4 id="修改nginx打开文件限制">修改nginx打开文件限制&lt;/h4>
&lt;p>修改&lt;code>nginx.conf&lt;/code>在 http 和 events 外层加入一行:
&lt;code>worker_rlimit_nofile 65535;&lt;/code>
worker_rlimit_nofile这个参数的含义是：“为nginx工作进程改变打开最多文件描述符数目的限制。用来在不重启主进程的情况下增加限制。”&lt;/p>
&lt;p>Debian系统 看起来像这样的&lt;/p>
&lt;pre tabindex="0">&lt;code>user www-data;
worker_processes auto;
pid /run/nginx.pid;
###############################################################################################################
# Must be less than LimitNOFILE for systemd
# or /etc/security/limits.conf (non-systemd)
# E.g. if LimitNOFILE is 65535, I set to 30000 (systemd)
# E.g. if &amp;#34;nginx hard nofile 30000&amp;#34; in the /etc/security/limits.conf, I set to 30000 (non-systemd)
###############################################################################################################
worker_rlimit_nofile 30000; #vg
include /etc/nginx/modules-enabled/*.conf;
events {
worker_connections 65535; #vg
multi_accept on; #vg
}
http {
##
# Basic Settings
...
.....
&lt;/code>&lt;/pre>&lt;p>重载nginx配置:
&lt;code>nginx -s reload&lt;/code>&lt;/p>
&lt;h2 id="nginx的其他优化">Nginx的其他优化&lt;/h2>
&lt;p>编辑 &lt;code>/etc/sysctl.conf&lt;/code> 文件，添加或修改
&lt;code>fs.file-max = 70000&lt;/code>&lt;/p>
&lt;p>查看是否生效
&lt;code>sysctl -p&lt;/code>&lt;/p></description></item><item><title>Debian12 系统添加多个IP</title><link>https://blog.baicai.me/article/2025/ifconfig_interfaces/</link><pubDate>Fri, 21 Feb 2025 23:31:24 +0800</pubDate><author>admin@baicai.me (白菜)</author><guid>https://blog.baicai.me/article/2025/ifconfig_interfaces/</guid><description>&lt;p>对于使用 传统的 ifconfig 配置的系统（例如老版本的Ubuntu、Debian等）,直接修改 &lt;code>/etc/network/interfaces&lt;/code> 文件。&lt;/p>
&lt;h3 id="编辑配置文件">编辑配置文件：&lt;/h3>
&lt;p>&lt;code>sudo nano /etc/network/interfaces&lt;/code>&lt;/p>
&lt;h3 id="添加多个ip地址">添加多个IP地址：&lt;/h3>
&lt;p>在相应的网络接口下添加多个IP地址。例如：&lt;/p>
&lt;pre tabindex="0">&lt;code>iface enp30 inet static
address 192.168.0.250
netmask 255.255.255.0
gateway 192.168.0.1
iface enp30 inet static
address 192.168.0.251
netmask 255.255.255.0
&lt;/code>&lt;/pre>&lt;h3 id="重启网络服务">重启网络服务：&lt;/h3>
&lt;p>保存文件并退出后，重启网络服务：&lt;/p>
&lt;p>&lt;code>sudo systemctl restart networking&lt;/code>&lt;/p>
&lt;h3 id="检查配置">检查配置&lt;/h3>
&lt;p>通过以下命令验证多IP地址是否已成功添加：&lt;/p>
&lt;p>&lt;code>ip addr show enp30&lt;/code>&lt;/p>
&lt;p>这将显示 enp30 接口的所有IP地址。你应该能看到你配置的多个IP地址。&lt;/p>
&lt;h2 id="临时配置多个ip地址">临时配置多个IP地址&lt;/h2>
&lt;p>为 enp30 接口添加一个新的IP 192.168.0.251
执行以下命令：
&lt;code>ip addr add 192.168.0.251/24 dev enp30&lt;/code>
这操作是临时的，重启后会丢失。&lt;/p></description></item><item><title>linux测试url的访问速度</title><link>https://blog.baicai.me/article/2025/linux_curl/</link><pubDate>Fri, 21 Feb 2025 18:34:28 +0800</pubDate><author>admin@baicai.me (白菜)</author><guid>https://blog.baicai.me/article/2025/linux_curl/</guid><description>&lt;p>使用curl命令来测试URL的访问速度。&lt;/p>
&lt;p>以下是使用curl测试URL访问速度的步骤：&lt;/p>
&lt;ul>
&lt;li>打开终端或命令行界面。&lt;/li>
&lt;li>输入以下命令：&lt;/li>
&lt;/ul>
&lt;div class="highlight">&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;">&lt;code class="language-bash" data-lang="bash">&lt;span style="display:flex;">&lt;span> curl -o /dev/null -s -w &lt;span style="color:#e6db74">&amp;#34;time_namelookup: %{time_namelookup}\n time_connect: %{time_connect}\n time_pretransfer: %{time_pretransfer}\n time_starttransfer: %{time_starttransfer}\n time_total: %{time_total}\n&amp;#34;&lt;/span> &amp;lt;URL&amp;gt;
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>&lt;p>请将&lt;code>&amp;lt;URL&amp;gt;&lt;/code>替换为要测试的URL地址。&lt;/p>
&lt;p>执行命令后，curl将会发送请求并返回一些关于请求的统计信息，包括以下内容：&lt;/p>
&lt;ul>
&lt;li>time_namelookup：DNS解析耗时，即将URL解析为IP地址的时间。&lt;/li>
&lt;li>time_connect：建立TCP连接的耗时。&lt;/li>
&lt;li>time_pretransfer：从开始到传输开始之前的耗时。&lt;/li>
&lt;li>time_starttransfer：从开始到第一个字节接收完成的耗时。&lt;/li>
&lt;li>time_total：总耗时，即从开始到请求完成的时间。&lt;/li>
&lt;/ul>
&lt;p>这些时间单位都以秒为单位。&lt;/p>
&lt;p>通过这些统计信息，你可以了解到URL的访问速度和各个阶段的耗时情况。&lt;/p></description></item><item><title>Giffgaff 打开 wificall 的操作步骤及分流规则</title><link>https://blog.baicai.me/article/2025/giffgaff_wificall/</link><pubDate>Tue, 28 Jan 2025 11:38:45 +0800</pubDate><author>admin@baicai.me (白菜)</author><guid>https://blog.baicai.me/article/2025/giffgaff_wificall/</guid><description>&lt;p>打开wificall的好处：可以使用英国本地资费，免费接电话。&lt;/p>
&lt;h3 id="ios需要运营商刷到580版本或者ios174以上版本">ios:需要运营商刷到58.0版本，或者ios17.4以上版本&lt;/h3>
&lt;ul>
&lt;li>关闭wifi和wificall开关&lt;/li>
&lt;li>打开飞行模式&lt;/li>
&lt;li>关闭你的国内运营商&lt;/li>
&lt;li>打开你的wifi&lt;/li>
&lt;li>全局连接英国节点，或走规则&lt;/li>
&lt;li>打开giffgaff的wificall开关，正常就可以连接上了，成功为运营商名字变成giffgaff&lt;/li>
&lt;li>可以解除飞行模式和正常打开你的国内运营商了&lt;/li>
&lt;/ul>
&lt;h3 id="安卓origin-os系统">安卓:origin os系统&lt;/h3>
&lt;ul>
&lt;li>打开wificall开关&lt;/li>
&lt;li>全局连接英国节点，或走规则&lt;/li>
&lt;li>正常就可以直接连上wificall&lt;/li>
&lt;/ul>
&lt;h3 id="分流规则">分流规则&lt;/h3>
&lt;pre tabindex="0">&lt;code># 地区检测
DOMAIN-SUFFIX, gspe1-ssl.ls.apple.com
# 沃达丰
DOMAIN-SUFFIX, epdg.epc.mnc015.mcc234.pub.3gppnetwork.org
DOMAIN-SUFFIX, ss.epdg.epc.mnc015.mcc234.pub.3gppnetwork.org
DOMAIN-SUFFIX, ss.epdg.epc.geo.mnc015.mcc234.pub.3gppnetwork.org
DOMAIN-SUFFIX, entsrv-uk.vodafone.com
DOMAIN-SUFFIX, vuk-gto.prod.ondemandconnectivity.com
IP-CIDR,88.82.0.0/19
# CMLinkUK EE
IP-CIDR,46.68.0.0/17
# Giffgaff
IP-CIDR,87.194.0.0/16
&lt;/code>&lt;/pre>&lt;p>或&lt;/p>
&lt;pre tabindex="0">&lt;code> # 地区检测
- &amp;#39;DOMAIN-SUFFIX,gspe1-ssl.ls.apple.com,WifiCall&amp;#39;
# 沃达丰
- &amp;#39;DOMAIN-SUFFIX,epdg.epc.mnc015.mcc234.pub.3gppnetwork.org,WifiCall&amp;#39;
- &amp;#39;DOMAIN-SUFFIX,ss.epdg.epc.mnc015.mcc234.pub.3gppnetwork.org,WifiCall&amp;#39;
- &amp;#39;DOMAIN-SUFFIX,ss.epdg.epc.geo.mnc015.mcc234.pub.3gppnetwork.org,WifiCall&amp;#39;
- &amp;#39;DOMAIN-SUFFIX,entsrv-uk.vodafone.com,WifiCall&amp;#39;
- &amp;#39;DOMAIN-SUFFIX,vuk-gto.prod.ondemandconnectivity.com,WifiCall&amp;#39;
- &amp;#39;IP-CIDR,88.82.0.0/19,WifiCall,no-resolve&amp;#39;
# CMLinkUK EE
- &amp;#39;IP-CIDR,46.68.0.0/17,WifiCall,no-resolve&amp;#39;
# Giffgaff
- &amp;#39;IP-CIDR,87.194.0.0/16,WifiCall,no-resolve&amp;#39;
&lt;/code>&lt;/pre>&lt;p>节点需要支持UDP!!! wificall走的UDP的500和4500端口&lt;/p></description></item><item><title>Docker本地镜像的导出、导入 (export,import,save,load)</title><link>https://blog.baicai.me/article/2024/docker_export_import_save_load/</link><pubDate>Fri, 11 Oct 2024 14:53:59 +0800</pubDate><author>admin@baicai.me (白菜)</author><guid>https://blog.baicai.me/article/2024/docker_export_import_save_load/</guid><description>&lt;p>对于镜像的导出和导入，Docker 提供了两种方案，下面分别进行介绍。&lt;/p>
&lt;h2 id="一使用-export-和-import">一、使用 export 和 import&lt;/h2>
&lt;h3 id="1查看本机的容器">1，查看本机的容器&lt;/h3>
&lt;p>使用 &lt;code>docker ps -a&lt;/code> 命令查看本机所有的容器。&lt;/p>
&lt;h3 id="2导出镜像">2，导出镜像&lt;/h3>
&lt;p>（1）使用 &lt;code>docker export&lt;/code> 命令根据容器 ID 将镜像导出成一个文件。&lt;/p>
&lt;p>&lt;code>docker export 镜像ID &amp;gt; server.tar&lt;/code>&lt;/p>
&lt;p>（2）上面命令执行后，可以看到文件已经保存到当前的终端目录下。&lt;/p>
&lt;h3 id="3导入镜像">3，导入镜像&lt;/h3>
&lt;p>（1）使用 &lt;code>docker import&lt;/code> 命令则可将这个镜像文件导入进来。&lt;/p>
&lt;p>&lt;code>docker import - new_server &amp;lt; server.tar&lt;/code>&lt;/p>
&lt;p>（2）执行 &lt;code>docker images&lt;/code> 命令可以看到镜像确实已经导入进来了。&lt;/p>
&lt;h2 id="二使用-save-和-load">二、使用 save 和 load&lt;/h2>
&lt;h3 id="1查看本机的容器-1">1，查看本机的容器&lt;/h3>
&lt;p>这两个命令是通过镜像来保存、加载镜像文件的。首先我们使用 &lt;code>docker images&lt;/code> 命令查看本机所有的镜像。&lt;/p>
&lt;h3 id="2保存镜像">2，保存镜像&lt;/h3>
&lt;p>（1）下面使用 &lt;code>docker save&lt;/code> 命令根据 ID 将镜像保存成一个文件。&lt;/p>
&lt;p>&lt;code>docker save 镜像ID &amp;gt; server.tar&lt;/code>&lt;/p>
&lt;p>（2）我们还可以同时将多个 image 打包成一个文件，比如下面将镜像库中的 postgres 和 mongo 打包：&lt;/p>
&lt;p>&lt;code>docker save -o images.tar postgres mongo&lt;/code>&lt;/p>
&lt;h3 id="3载入镜像">3，载入镜像&lt;/h3>
&lt;p>使用 &lt;code>docker load&lt;/code> 命令则可将这个镜像文件载入进来。&lt;/p>
&lt;p>&lt;code>docker load &amp;lt; server.tar&lt;/code>&lt;/p>
&lt;h2 id="附两种方案的差别">附：两种方案的差别&lt;/h2>
&lt;p>特别注意：两种方法不可混用。&lt;br>
如果使用 &lt;code>import&lt;/code> 导入 &lt;code>save&lt;/code> 产生的文件，虽然导入不提示错误，但是启动容器时会提示失败，会出现类似&amp;quot;docker: Error response from daemon: Container command not found or does not exist&amp;quot;的错误。&lt;/p>
&lt;h3 id="1文件大小不同">1，文件大小不同&lt;/h3>
&lt;p>export 导出的镜像文件体积小于 save 保存的镜像&lt;/p>
&lt;h3 id="2是否可以对镜像重命名">2，是否可以对镜像重命名&lt;/h3>
&lt;p>docker import 可以为镜像指定新名称
docker load 不能对载入的镜像重命名&lt;/p>
&lt;h3 id="3是否可以同时将多个镜像打包到一个文件中">3，是否可以同时将多个镜像打包到一个文件中&lt;/h3>
&lt;p>docker export 不支持
docker save 支持&lt;/p>
&lt;h3 id="4是否包含镜像历史">4，是否包含镜像历史&lt;/h3>
&lt;p>export 导出（import 导入）是根据容器拿到的镜像，再导入时会丢失镜像所有的历史记录和元数据信息（即仅保存容器当时的快照状态），所以无法进行回滚操作。&lt;/p>
&lt;p>save 保存（load 加载）的镜像，没有丢失镜像的历史，可以回滚到之前的层（layer）。&lt;/p>
&lt;h3 id="5应用场景不同">5，应用场景不同&lt;/h3>
&lt;p>docker export 的应用场景：主要用来制作基础镜像，比如我们从一个 ubuntu 镜像启动一个容器，然后安装一些软件和进行一些设置后，使用 docker export 保存为一个基础镜像。然后，把这个镜像分发给其他人使用，比如作为基础的开发环境。&lt;/p>
&lt;p>docker save 的应用场景：如果我们的应用是使用 docker-compose.yml 编排的多个镜像组合，但我们要部署的客户服务器并不能连外网。这时就可以使用 docker save 将用到的镜像打个包，然后拷贝到客户服务器上使用 docker load 载入。&lt;/p></description></item><item><title>Go语言进制以及进制转换</title><link>https://blog.baicai.me/article/2024/fmt_int/</link><pubDate>Tue, 24 Sep 2024 19:52:33 +0800</pubDate><author>admin@baicai.me (白菜)</author><guid>https://blog.baicai.me/article/2024/fmt_int/</guid><description>&lt;h3 id="二进制-0b或者0b-表示">二进制 0B或者0b 表示&lt;/h3>
&lt;div class="highlight">&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;">&lt;code class="language-golang" data-lang="golang">&lt;span style="display:flex;">&lt;span>&lt;span style="color:#66d9ef">var&lt;/span> &lt;span style="color:#a6e22e">bin1&lt;/span> = &lt;span style="color:#ae81ff">0b1101&lt;/span>
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>&lt;div class="highlight">&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;">&lt;code class="language-golang" data-lang="golang">&lt;span style="display:flex;">&lt;span>&lt;span style="color:#f92672">package&lt;/span> &lt;span style="color:#a6e22e">main&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#f92672">import&lt;/span> &lt;span style="color:#e6db74">&amp;#34;fmt&amp;#34;&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#66d9ef">func&lt;/span> &lt;span style="color:#a6e22e">main&lt;/span>(){
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#66d9ef">var&lt;/span> &lt;span style="color:#a6e22e">num01&lt;/span> &lt;span style="color:#66d9ef">int&lt;/span> = &lt;span style="color:#ae81ff">0b1100&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#a6e22e">fmt&lt;/span>.&lt;span style="color:#a6e22e">Printf&lt;/span>(&lt;span style="color:#e6db74">&amp;#34;%b的十进制为%d&amp;#34;&lt;/span>, &lt;span style="color:#a6e22e">num01&lt;/span>,&lt;span style="color:#a6e22e">num01&lt;/span>)
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>}
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>&lt;h3 id="八进制-0o或者0o-表示">八进制 0O或者0o 表示&lt;/h3>
&lt;div class="highlight">&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;">&lt;code class="language-golang" data-lang="golang">&lt;span style="display:flex;">&lt;span>&lt;span style="color:#66d9ef">var&lt;/span> &lt;span style="color:#a6e22e">oct&lt;/span> = &lt;span style="color:#ae81ff">0&lt;/span>&lt;span style="color:#a6e22e">o1234567&lt;/span>
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>&lt;div class="highlight">&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;">&lt;code class="language-golang" data-lang="golang">&lt;span style="display:flex;">&lt;span>&lt;span style="color:#f92672">package&lt;/span> &lt;span style="color:#a6e22e">main&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#f92672">import&lt;/span> &lt;span style="color:#e6db74">&amp;#34;fmt&amp;#34;&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#66d9ef">func&lt;/span> &lt;span style="color:#a6e22e">main&lt;/span>(){
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#66d9ef">var&lt;/span> &lt;span style="color:#a6e22e">num01&lt;/span> &lt;span style="color:#66d9ef">int&lt;/span> = &lt;span style="color:#ae81ff">0&lt;/span>&lt;span style="color:#a6e22e">o10&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#a6e22e">fmt&lt;/span>.&lt;span style="color:#a6e22e">Printf&lt;/span>(&lt;span style="color:#e6db74">&amp;#34;%o的十进制为%d&amp;#34;&lt;/span>, &lt;span style="color:#a6e22e">num01&lt;/span>,&lt;span style="color:#a6e22e">num01&lt;/span>)
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>}
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>&lt;h3 id="十六进制-0x或者0x-表示">十六进制 0X或者0x 表示&lt;/h3>
&lt;div class="highlight">&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;">&lt;code class="language-golang" data-lang="golang">&lt;span style="display:flex;">&lt;span>&lt;span style="color:#66d9ef">var&lt;/span> &lt;span style="color:#a6e22e">hex&lt;/span> = &lt;span style="color:#ae81ff">0x1234&lt;/span>
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>&lt;div class="highlight">&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;">&lt;code class="language-golang" data-lang="golang">&lt;span style="display:flex;">&lt;span>&lt;span style="color:#f92672">package&lt;/span> &lt;span style="color:#a6e22e">main&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#f92672">import&lt;/span> &lt;span style="color:#e6db74">&amp;#34;fmt&amp;#34;&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#66d9ef">func&lt;/span> &lt;span style="color:#a6e22e">main&lt;/span>(){
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#66d9ef">var&lt;/span> &lt;span style="color:#a6e22e">num01&lt;/span> &lt;span style="color:#66d9ef">int&lt;/span> = &lt;span style="color:#ae81ff">0xf&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#a6e22e">fmt&lt;/span>.&lt;span style="color:#a6e22e">Printf&lt;/span>(&lt;span style="color:#e6db74">&amp;#34;%x的十进制为%d&amp;#34;&lt;/span>, &lt;span style="color:#a6e22e">num01&lt;/span>,&lt;span style="color:#a6e22e">num01&lt;/span>)
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>}
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>&lt;h3 id="进制转换">进制转换&lt;/h3>
&lt;pre tabindex="0">&lt;code>1. 二进制转八进制 %b -&amp;gt; %o
2. 二进制转十进制 %b -&amp;gt; %d
3. 二进制转十六进制 %b -&amp;gt; %x
4. 八进制转二进制 %o -&amp;gt; %b
5. 八进制转十进制 %o -&amp;gt; %d
6. 八进制转十六进制 %o -&amp;gt; %x
7. 十进制转二进制 %d -&amp;gt; %b
8. 十进制转八进制 %d -&amp;gt; %o
9. 十进制转十六进制 %d -&amp;gt; %x
10. 十六进制转二进制 %x -&amp;gt; %b
11. 十六进制转八进制 %x -&amp;gt; %o
12. 十六进制转十进制 %x -&amp;gt; %d
// 例
fmt.Printf(&amp;#34;十进制%d转成八进制%o&amp;#34;,num1,num2)
&lt;/code>&lt;/pre>&lt;pre tabindex="0">&lt;code>%b 表示为二进制
%c 该值对应的unicode码值
%d 表示为十进制
%o 表示为八进制
%q 该值对应的单引号括起来的go语法字符字面值，必要时会采用安全的转义表示
%x 表示为十六进制，使用a-f
%X 表示为十六进制，使用A-F
%U 表示为Unicode格式：U+1234，等价于&amp;#34;U+%04X&amp;#34;
%E 用科学计数法表示
%f 用浮点数表示
&lt;/code>&lt;/pre>&lt;p>快速测试
&lt;a href="https://go.dev/play/">go.dev/play&lt;/a>&lt;/p></description></item><item><title>Mac终端查看sqlite3数据库</title><link>https://blog.baicai.me/article/2024/cmd_sqlite/</link><pubDate>Tue, 24 Sep 2024 14:23:50 +0800</pubDate><author>admin@baicai.me (白菜)</author><guid>https://blog.baicai.me/article/2024/cmd_sqlite/</guid><description>&lt;h3 id="用sqlite命令打开数据库文件">用sqlite命令打开数据库文件&lt;/h3>
&lt;div class="highlight">&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;">&lt;code class="language-bash" data-lang="bash">&lt;span style="display:flex;">&lt;span>sqlite3 db.file
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>&lt;p>这样我们就进入了数据库操作，下面的命令都只能是sqlite下的命令，如果输入其他命令，都是无效的。&lt;/p>
&lt;p>我们可以输入 .help 先查看下大概的命令：&lt;/p>
&lt;div class="highlight">&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;">&lt;code class="language-bash" data-lang="bash">&lt;span style="display:flex;">&lt;span>.help
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>&lt;h3 id="常用的几种简单命令">常用的几种简单命令：&lt;/h3>
&lt;ol>
&lt;li>退出sqlite&lt;/li>
&lt;/ol>
&lt;div class="highlight">&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;">&lt;code class="language-bash" data-lang="bash">&lt;span style="display:flex;">&lt;span>.quit
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>&lt;ol start="2">
&lt;li>查看所有表&lt;/li>
&lt;/ol>
&lt;div class="highlight">&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;">&lt;code class="language-bash" data-lang="bash">&lt;span style="display:flex;">&lt;span>.tables
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>&lt;ol start="3">
&lt;li>配置情况&lt;/li>
&lt;/ol>
&lt;div class="highlight">&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;">&lt;code class="language-bash" data-lang="bash">&lt;span style="display:flex;">&lt;span>.show
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>&lt;ol start="4">
&lt;li>设置查询数据排列格式&lt;/li>
&lt;/ol>
&lt;div class="highlight">&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;">&lt;code class="language-bash" data-lang="bash">&lt;span style="display:flex;">&lt;span>.mode list
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>.mode line
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>.mode column
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>&lt;ol start="5">
&lt;li>是否显示头&lt;/li>
&lt;/ol>
&lt;div class="highlight">&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;">&lt;code class="language-bash" data-lang="bash">&lt;span style="display:flex;">&lt;span>.headers on
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div></description></item><item><title>解决 UFW 和 Docker 的问题</title><link>https://blog.baicai.me/article/2024/debian_ufw_docker/</link><pubDate>Thu, 11 Jul 2024 14:31:38 +0800</pubDate><author>admin@baicai.me (白菜)</author><guid>https://blog.baicai.me/article/2024/debian_ufw_docker/</guid><description>&lt;h2 id="问题">问题&lt;/h2>
&lt;p>UFW 是一个 iptables 前端，可以非常方便的管理防火墙的规则。但是当安装了 Docker，UFW 无法管理 Docker 发布出来的端口了。&lt;/p>
&lt;p>具体现象是：&lt;/p>
&lt;ol>
&lt;li>在一个对外提供服务的服务器上启用了 UFW，并且默认阻止所有未被允许的传入连接。&lt;/li>
&lt;li>运行了一个 Docker 容器，并且使用 &lt;code>-p&lt;/code> 选项来把该容器的某个端口发布到服务器的所有 IP 地址上。比如：&lt;code>docker run -d --name httpd -p 0.0.0.0:8080:80 httpd:alpine&lt;/code> 将会运行一个 httpd 服务，并且将容器的 &lt;code>80&lt;/code> 端口发布到服务器的 &lt;code>8080&lt;/code> 端口上。&lt;/li>
&lt;li>UFW 将不会阻止所有对 &lt;code>8080&lt;/code> 端口访问的请求，用命令 &lt;code>ufw deny 8080&lt;/code> 也无法阻止外部访问这个端口。&lt;/li>
&lt;/ol>
&lt;p>这个问题其实挺严重的，这意味着本来只是为了在内部提供服务的一个端口被暴露在公共网络上。&lt;/p>
&lt;h2 id="解决-ufw-和-docker-的问题">解决 UFW 和 Docker 的问题&lt;/h2>
&lt;h3 id="撤销原先的修改">撤销原先的修改&lt;/h3>
&lt;p>如果已经按照目前网络上搜索到解决方案修改过了，请先修改回来，包括：&lt;/p>
&lt;ol>
&lt;li>启用 Docker 的 iptables 功能，删除所有类似 &lt;code>--iptables=false&lt;/code> 的修改，包括 &lt;code>/etc/docker/daemon.json&lt;/code> 配置文件。&lt;/li>
&lt;li>UFW 的默认 &lt;code>FORWARD&lt;/code> 规则改回默认的 &lt;code>DROP&lt;/code>，而非 &lt;code>ACCEPT&lt;/code>。&lt;/li>
&lt;li>删除 UFW 配置文件 &lt;code>/etc/ufw/after.rules&lt;/code> 中与 Docker 网络相关的规则。&lt;/li>
&lt;li>如果修改了 Docker 相关的配置文件，重启 Docker。稍后还要修改 UFW 的配置，可以一并重启。&lt;/li>
&lt;/ol>
&lt;p>目前新的解决方案只需要修改一个 UFW 配置文件即可，Docker 的所有配置和选项都保持默认。&lt;/p>
&lt;p>修改 UFW 的配置文件 &lt;code>/etc/ufw/after.rules&lt;/code>，在最后添加上如下规则：&lt;/p>
&lt;pre tabindex="0">&lt;code> # BEGIN UFW AND DOCKER
*filter
:ufw-user-forward - [0:0]
:ufw-docker-logging-deny - [0:0]
:DOCKER-USER - [0:0]
-A DOCKER-USER -j ufw-user-forward
-A DOCKER-USER -j RETURN -s 10.0.0.0/8
-A DOCKER-USER -j RETURN -s 172.16.0.0/12
-A DOCKER-USER -j RETURN -s 192.168.0.0/16
-A DOCKER-USER -p udp -m udp --sport 53 --dport 1024:65535 -j RETURN
-A DOCKER-USER -j ufw-docker-logging-deny -p tcp -m tcp --tcp-flags FIN,SYN,RST,ACK SYN -d 192.168.0.0/16
-A DOCKER-USER -j ufw-docker-logging-deny -p tcp -m tcp --tcp-flags FIN,SYN,RST,ACK SYN -d 10.0.0.0/8
-A DOCKER-USER -j ufw-docker-logging-deny -p tcp -m tcp --tcp-flags FIN,SYN,RST,ACK SYN -d 172.16.0.0/12
-A DOCKER-USER -j ufw-docker-logging-deny -p udp -m udp --dport 0:32767 -d 192.168.0.0/16
-A DOCKER-USER -j ufw-docker-logging-deny -p udp -m udp --dport 0:32767 -d 10.0.0.0/8
-A DOCKER-USER -j ufw-docker-logging-deny -p udp -m udp --dport 0:32767 -d 172.16.0.0/12
-A DOCKER-USER -j RETURN
-A ufw-docker-logging-deny -m limit --limit 3/min --limit-burst 10 -j LOG --log-prefix &amp;#34;[UFW DOCKER BLOCK] &amp;#34;
-A ufw-docker-logging-deny -j DROP
COMMIT
# END UFW AND DOCKER
&lt;/code>&lt;/pre>&lt;p>然后重启 UFW，&lt;code>sudo systemctl restart ufw&lt;/code>。现在外部就已经无法访问 Docker 发布出来的任何端口了，但是容器内部以及私有网络地址上可以正常互相访问，而且容器也可以正常访问外部的网络。&lt;strong>可能由于某些未知原因，重启 UFW 之后规则也无法生效，请重启服务器。&lt;/strong>&lt;/p>
&lt;p>如果希望允许外部网络访问 Docker 容器提供的服务，比如有一个容器的服务端口是 &lt;code>80&lt;/code>。那就可以用以下命令来允许外部网络访问这个服务：&lt;/p>
&lt;pre tabindex="0">&lt;code> ufw route allow proto tcp from any to any port 80
&lt;/code>&lt;/pre>&lt;p>这个命令会允许外部网络访问所有用 Docker 发布出来的并且内部服务端口为 &lt;code>80&lt;/code> 的所有服务。&lt;/p>
&lt;p>如果有多个容器的服务端口为 80，但只希望外部网络访问某个特定的容器。比如该容器的私有地址为 &lt;code>172.17.0.2&lt;/code>，就用类似下面的命令：&lt;/p>
&lt;pre tabindex="0">&lt;code> ufw route allow proto tcp from any to 172.17.0.2 port 80
&lt;/code>&lt;/pre>&lt;p>如果一个容器的服务是 UDP 协议，假如是 DNS 服务，可以用下面的命令来允许外部网络访问所有发布出来的 DNS 服务：&lt;/p>
&lt;pre tabindex="0">&lt;code> ufw route allow proto udp from any to any port 53
&lt;/code>&lt;/pre>&lt;p>同样的，如果只针对一个特定的容器，比如 IP 地址为 &lt;code>172.17.0.2&lt;/code>：&lt;/p>
&lt;pre tabindex="0">&lt;code> ufw route allow proto udp from any to 172.17.0.2 port 53
&lt;/code>&lt;/pre>&lt;h3 id="解释">解释&lt;/h3>
&lt;p>在新增的这段规则中，下面这段规则是为了让私有网络地址可以互相访问。通常情况下，私有网络是比公共网络更信任的。&lt;/p>
&lt;pre tabindex="0">&lt;code> -A DOCKER-USER -j RETURN -s 10.0.0.0/8
-A DOCKER-USER -j RETURN -s 172.16.0.0/12
-A DOCKER-USER -j RETURN -s 192.168.0.0/16
&lt;/code>&lt;/pre>&lt;p>下面的规则是为了可以用 UFW 来管理外部网络是否允许访问 Docker 容器提供的服务，这样我们就可以在一个地方来管理防火墙的规则了。&lt;/p>
&lt;pre tabindex="0">&lt;code> -A DOCKER-USER -j ufw-user-forward
&lt;/code>&lt;/pre>&lt;p>例如，我们要阻止一个 IP 地址为 172.17.0.9 的容器内的所有对外连接，也就是阻止该容器访问外部网络，使用下列命令&lt;/p>
&lt;pre tabindex="0">&lt;code> ufw route deny from 172.17.0.9 to any
&lt;/code>&lt;/pre>&lt;p>下面的规则阻止了所有外部网络发起的连接请求，但是允许内部网络访问外部网络。对于 TCP 协议，是阻止了从外部网络主动建立 TCP 连接。对于 UDP，是阻止了所有小于端口 &lt;code>32767&lt;/code> 的访问。为什么是这个端口的？由于 UDP 协议是无状态的，无法像 TCP 那样阻止发起建立连接请求的握手信号。在 GNU/Linux 上查看文件 &lt;code>/proc/sys/net/ipv4/ip_local_port_range&lt;/code> 可以看到发出 TCP/UDP 数据后，本地源端口的范围，默认为 &lt;code>32768 60999&lt;/code>。当从一个运行的容器对外访问一个 UDP 协议的服务时，本地端口将会从这个端口范围里面随机选择一个，服务器将会把数据返回到这个随机端口上。所以，我们可以假定所有容器内部的 UDP 协议的监听端口都小余 &lt;code>32768&lt;/code>，不允许外部网络主动连接小余 &lt;code>32768&lt;/code> 的 UDP 端口。&lt;/p>
&lt;pre tabindex="0">&lt;code> -A DOCKER-USER -j DROP -p tcp -m tcp --tcp-flags FIN,SYN,RST,ACK SYN -d 192.168.0.0/16
-A DOCKER-USER -j DROP -p tcp -m tcp --tcp-flags FIN,SYN,RST,ACK SYN -d 10.0.0.0/8
-A DOCKER-USER -j DROP -p tcp -m tcp --tcp-flags FIN,SYN,RST,ACK SYN -d 172.16.0.0/12
-A DOCKER-USER -j DROP -p udp -m udp --dport 0:32767 -d 192.168.0.0/16
-A DOCKER-USER -j DROP -p udp -m udp --dport 0:32767 -d 10.0.0.0/8
-A DOCKER-USER -j DROP -p udp -m udp --dport 0:32767 -d 172.16.0.0/12
-A DOCKER-USER -j RETURN
&lt;/code>&lt;/pre>&lt;p>如果一个容器在接受数据的时候，端口号没有遵循操作系统的设定，也就是说最小端口号要小余 &lt;code>32768&lt;/code>。比如运行了一个 Dnsmasq 的容器，Dnsmasq 用于接受数据的最小端口号默认是 &lt;code>1024&lt;/code>。那可以用下面的命令来允许 Dnsmasq 这个容器使用一个更大的端口范围来接受数据。&lt;/p>
&lt;pre tabindex="0">&lt;code> ufw route allow proto udp from any port 53 to any port 1024:65535
&lt;/code>&lt;/pre>&lt;p>因为 DNS 是一个非常常见的服务，所以已经有一条规则用于允许使用一个更大的端口范围来接受 DNS 数据包&lt;/p>
&lt;h3 id="选择-ufw-user-forward-而不是-ufw-user-input-的原因">选择 &lt;code>ufw-user-forward&lt;/code> 而不是 &lt;code>ufw-user-input&lt;/code> 的原因&lt;/h3>
&lt;h4 id="使用-ufw-user-input">使用 &lt;code>ufw-user-input&lt;/code>&lt;/h4>
&lt;p>优点：&lt;/p>
&lt;p>使用的 UFW 命令比较简单，也比较容易理解&lt;/p>
&lt;p>比如，允许公众网络访问一个已经发布出来的容器端口 &lt;code>8080&lt;/code>，使用命令：&lt;/p>
&lt;pre tabindex="0">&lt;code> ufw allow 8080
&lt;/code>&lt;/pre>&lt;p>缺点：&lt;/p>
&lt;p>不仅仅是暴露了已经发布的容器端口，也暴露了主机上的端口。&lt;/p>
&lt;p>比如，如果在主机上运行了一个端口为 &lt;code>8080&lt;/code> 的服务。命令 &lt;code>ufw allow 8080&lt;/code> 允许了公共网络访问这个服务，也允许了访问所有已经发布的容器端口为 &lt;code>8080&lt;/code> 的服务。但是我们可能只是希望保留主机上的这个服务，或者是运行在容器里面的服务，而不是两个同时暴露。&lt;/p>
&lt;p>为了避免这个问题，我们可能需要使用类似下面的命令来管理已经发布的容器端口：&lt;/p>
&lt;pre tabindex="0">&lt;code> ufw allow proto tcp from any to 172.16.0.3 port 8080
&lt;/code>&lt;/pre>&lt;h4 id="使用-ufw-user-forward">使用 &lt;code>ufw-user-forward&lt;/code>&lt;/h4>
&lt;p>优点：&lt;/p>
&lt;p>不会因为同一条命令而同时暴露主机和容器里面的服务。&lt;/p>
&lt;p>比如，如果我们希望暴露所有容器端口为 &lt;code>8080&lt;/code> 的服务，使用下面的命令：&lt;/p>
&lt;pre tabindex="0">&lt;code> ufw route allow 8080
&lt;/code>&lt;/pre>&lt;p>现在公共网络可以访问所有容器端口为 &lt;code>8080&lt;/code> 的已经发布的服务，但是运行在主机上的 &lt;code>8080&lt;/code> 服务仍然不会被公开。如果我们希望公开主机上的 &lt;code>8080&lt;/code> 端口，可以执行下面的命令：&lt;/p>
&lt;pre tabindex="0">&lt;code> ufw allow 8080
&lt;/code>&lt;/pre>&lt;h4 id="结论">结论&lt;/h4>
&lt;p>如果我们正在使用老版本，我们可以使用 &lt;code>ufw-user-input&lt;/code>。但是要小心避免把不该暴露的服务暴露出去。&lt;/p>
&lt;p>如果正在使用支持 &lt;code>ufw route&lt;/code> 命令的新版本，我们最好使用 &lt;code>ufw-user-forward&lt;/code>，并且使用 &lt;code>ufw route&lt;/code> 来管理与容器相关的防火墙规则。&lt;/p></description></item><item><title>docker 映射某个范围内的端口列表</title><link>https://blog.baicai.me/article/2024/docker_ports/</link><pubDate>Sat, 09 Mar 2024 00:01:19 +0800</pubDate><author>admin@baicai.me (白菜)</author><guid>https://blog.baicai.me/article/2024/docker_ports/</guid><description>&lt;p>在Dockerfile、命令行或docker-compose.yml中，都可以使用类似于8080-8090:8080-8090的格式，来映射多个端口&lt;/p>
&lt;h3 id="docker-composeyml">docker-compose.yml&lt;/h3>
&lt;div class="highlight">&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;">&lt;code class="language-yaml" data-lang="yaml">&lt;span style="display:flex;">&lt;span>&lt;span style="color:#f92672">version&lt;/span>: &lt;span style="color:#e6db74">&amp;#39;3.6&amp;#39;&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#f92672">services&lt;/span>:
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#f92672">web&lt;/span>:
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#f92672">image&lt;/span>: &lt;span style="color:#ae81ff">nginx:1.18&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#f92672">ports&lt;/span>:
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#75715e"># 将会映射8080到8090这个范围内的端口&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> - &lt;span style="color:#ae81ff">8080-8090&lt;/span>:&lt;span style="color:#ae81ff">8080-8090&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#f92672">volumes&lt;/span>:
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> - &lt;span style="color:#ae81ff">./www:/www&lt;/span>
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>&lt;h3 id="命令行">命令行&lt;/h3>
&lt;div class="highlight">&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;">&lt;code class="language-bash" data-lang="bash">&lt;span style="display:flex;">&lt;span>docker run -p 8080-8090:8080-8090 nginx
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>&lt;h3 id="dockerfile">Dockerfile&lt;/h3>
&lt;pre tabindex="0">&lt;code>Dockerfile
EXPOSE 8080-8090
&lt;/code>&lt;/pre></description></item><item><title>使用adb命令和电脑互传文件</title><link>https://blog.baicai.me/article/2024/adb_push_pull/</link><pubDate>Mon, 04 Mar 2024 22:44:37 +0800</pubDate><author>admin@baicai.me (白菜)</author><guid>https://blog.baicai.me/article/2024/adb_push_pull/</guid><description>&lt;h3 id="电脑传文件到手机">电脑传文件到手机&lt;/h3>
&lt;p>把当前目录下的&lt;code>test.tex&lt;/code>文件传到手机 &lt;code>/sdcard/test&lt;/code>目录中&lt;/p>
&lt;div class="highlight">&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;">&lt;code class="language-bash" data-lang="bash">&lt;span style="display:flex;">&lt;span>adb push test.txt /sdcard/test
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>&lt;h3 id="手机文件传到电脑">手机文件传到电脑&lt;/h3>
&lt;p>把 &lt;code>/sdcard/test/&lt;/code> 目录下的&lt;code>test.txt&lt;/code>文件传到本机当前目录&lt;code>test&lt;/code>目录中&lt;/p>
&lt;div class="highlight">&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;">&lt;code class="language-bash" data-lang="bash">&lt;span style="display:flex;">&lt;span>adb pull /sdcard/test/test.txt ./test
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>&lt;h3 id="查看手机文件目录">查看手机文件目录&lt;/h3>
&lt;div class="highlight">&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;">&lt;code class="language-bash" data-lang="bash">&lt;span style="display:flex;">&lt;span>&lt;span style="color:#75715e">#进入到根目录&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>adb shell
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#75715e">#查看所有目录&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>ls
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#75715e">#进入到sdcard目录，安卓手机的文件管理一般都这这里&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>cd sdcard
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#75715e">#然后查看要传输哪些文件到哪个文件夹&lt;/span>
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div></description></item><item><title>查找子域名解析: 子域名探测方法大全</title><link>https://blog.baicai.me/article/2024/find_subdomain/</link><pubDate>Mon, 05 Feb 2024 18:58:56 +0800</pubDate><author>admin@baicai.me (白菜)</author><guid>https://blog.baicai.me/article/2024/find_subdomain/</guid><description>&lt;h2 id="子域名探测">子域名探测&lt;/h2>
&lt;p>通过收集子域名信息来进行渗透是目前常见的一种手法。
子域名信息收集可以通过手工，也可以通过工具，还可以通过普通及漏洞搜索引擎来进行分析。
在挖SRC漏洞时，子域名信息的收集至关重要！&lt;/p>
&lt;h2 id="为什么要进行子域名探测">为什么要进行子域名探测？&lt;/h2>
&lt;p>子域名探测可以帮我们发现渗透测试中更多的服务，这将增加发现漏洞的可能性&lt;br>
查找一些用户上较少，被人遗忘的子域名，其上运行的应用程序可能会使我们发现关键漏洞&lt;br>
通常，同一组织的不同域名/应用程序中存在相同的漏洞&lt;br>
子域名中的常见资产类型一般包括办公系统，邮箱系统，论坛，商城等，其他管理系统，网站管理后台等较少出现在子域名中&lt;/p>
&lt;h2 id="子域名探测方法大全">子域名探测方法大全&lt;/h2>
&lt;p>在线接口&lt;br>
暴力枚举&lt;br>
搜索引擎&lt;br>
Certificate Transparency（证书透明）&lt;br>
Subject Alternate Name (SAN) - 主题备用名称&lt;br>
Public datasets（公开数据集）&lt;br>
信息泄露&lt;br>
内容解析（HTML，JavaScript，文件）&lt;br>
DNS解析&lt;br>
区域传送&lt;br>
DNS aggregators（DNS聚合器）&lt;br>
DNS Cache Snooping（域名缓存侦测）&lt;br>
Alterations &amp;amp; permutations（换置 &amp;amp; 排序）&lt;br>
DNSSEC(Domain Name System Security Extensions)，DNS安全扩展，DNSSEC区域漫步&lt;br>
CSP HTTP首部&lt;br>
SPF记录&lt;br>
虚拟主机爆破&lt;br>
ASN发现&lt;br>
爬虫 Scraping（抓取）&lt;/p>
&lt;h3 id="在线接口">在线接口&lt;/h3>
&lt;pre tabindex="0">&lt;code>https://crt.sh/
https://censys.io/
https://transparencyreport.google.com/https/certificates
https://dnsdumpster.com/
https://hackertarget.com/find-dns-host-records/
https://x.threatbook.cn/
https://www.virustotal.com/gui/home/search
https://site.ip138.com/baidu.com/domain.htm
https://www.t1h2ua.cn/tools/
http://tool.chinaz.com/subdomain/
&lt;/code>&lt;/pre>&lt;h3 id="暴力枚举">暴力枚举&lt;/h3>
&lt;p>Layer子域名爆破机 Layer是windows下的一款子域名探测工具，其工作原理是利用子域名字典进行爆破，使用简单容易上手。&lt;/p>
&lt;p>Amass 工具描述：爆破, google, VirusTotal, alt names&lt;/p>
&lt;div class="highlight">&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;">&lt;code class="language-bash" data-lang="bash">&lt;span style="display:flex;">&lt;span>go install github.com/OWASP/Amass/...
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>amass -d target.com -o $outfile
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>&lt;p>Knock 工具描述：AXFR, virustotal, 爆破&lt;/p>
&lt;div class="highlight">&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;">&lt;code class="language-bash" data-lang="bash">&lt;span style="display:flex;">&lt;span>apt-get install python-dnspython git clone https://xxx.com/guelfoweb/knock.git
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>cd knock
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>nano knockpy/config.json &lt;span style="color:#75715e"># &amp;lt;- set your virustotal API_KEY python setup.py install&lt;/span>
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>&lt;h3 id="搜索引擎">搜索引擎&lt;/h3>
&lt;p>Google&lt;br>
intitle=公司名称&lt;br>
过滤掉 -site:www.target.com&lt;br>
我们可以在Google搜索中使用 site:运算符来查找一个域的所有子域名&lt;br>
谷歌还额外支持减号运算符 site:*.wikimedia.org -www -store -jobs -uk 以排除我们不感兴趣的子域名&lt;/p>
&lt;p>Bing&lt;br>
Bing搜索引擎也支持一些高级搜索运算符。&lt;br>
与Google一样，Bing也支持site:运算符，可以帮助您检查除Google搜索之外的其他结果。&lt;br>
发现子域名: site:target.com&lt;/p>
&lt;p>百度&lt;br>
intitle=公司名称&lt;/p>
&lt;p>钟馗之眼&lt;/p>
&lt;pre tabindex="0">&lt;code>https://www.zoomeye.org/ site=target.com
&lt;/code>&lt;/pre>&lt;p>duckduckgo&lt;/p>
&lt;pre tabindex="0">&lt;code>https://duckduckgo.com site:target.com
&lt;/code>&lt;/pre>&lt;h3 id="certificate-transparency-证书透明">Certificate Transparency （证书透明）&lt;/h3>
&lt;h5 id="ssltls证书">SSL/TLS证书&lt;/h5>
&lt;p>证书透明度(Certificate Transparency)是证书授权机构的一个项目，证书授权机构会将每个SSL/TLS证书发布到公共日志中。&lt;br>
一个SSL/TLS证书通常包含域名、子域名和邮件地址。&lt;br>
查找某个域名所属证书的最简单的方法就是使用搜索引擎搜索一些公开的CT日志。&lt;/p>
&lt;p>在线查询：&lt;/p>
&lt;pre tabindex="0">&lt;code>https://crt.sh/
https://censys.io/
https://developers.facebook.com/tools/ct/
https://google.com/transparencyreport/https/ct/
https://transparencyreport.google.com/https/certificates
&lt;/code>&lt;/pre>&lt;p>CTFR 工具描述：滥用证书透明记录&lt;/p>
&lt;div class="highlight">&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;">&lt;code class="language-bash" data-lang="bash">&lt;span style="display:flex;">&lt;span>git clone https://github.com/UnaPibaGeek/ctfr.git
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>cd ctfr
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>pip3 install -r requirements.txt
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>python3 ctfr.py -d target.com -o $outfile
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>&lt;p>Censys_subdomain_enum.py&lt;br>
工具描述：提取子域名，从Censys的SSL/TLS证书中收集子域名&lt;/p>
&lt;div class="highlight">&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;">&lt;code class="language-bash" data-lang="bash">&lt;span style="display:flex;">&lt;span>pip install censys
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>git clone https://github.com/appsecco/the-art-of-subdomain-enumeration.git
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>python censys_enumeration.py target.com
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>&lt;p>Cloudflare_enum.py&lt;br>
工具描述：从Cloudflare提取子域名 dns聚合器&lt;/p>
&lt;div class="highlight">&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;">&lt;code class="language-bash" data-lang="bash">&lt;span style="display:flex;">&lt;span>pip install censys
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>git clone https://github.com/appsecco/the-art-of-subdomain-enumeration.git
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>cloudflare_subdomain_enum.py your@cloudflare.email target.com
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>&lt;p>Crt_enum_web.py&lt;br>
工具描述：解析https://crt.sh/页面的子域名&lt;/p>
&lt;div class="highlight">&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;">&lt;code class="language-bash" data-lang="bash">&lt;span style="display:flex;">&lt;span>pip install psycopg2
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>git clone https://github.com/appsecco/the-art-of-subdomain-enumeration.git
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>python3 crtsh_enum_web.py target.com
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>&lt;p>San_subdomain_enum.py&lt;br>
工具描述：SSL/TLS证书中的SAN获取子域名&lt;/p>
&lt;div class="highlight">&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;">&lt;code class="language-bash" data-lang="bash">&lt;span style="display:flex;">&lt;span>git clone https://github.com/appsecco/the-art-of-subdomain-enumeration.git
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>./san_subdomain_enum.py target.com
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>&lt;h4 id="subject-alternate-name-san-主题备用名称">Subject Alternate Name （SAN）-主题备用名称&lt;/h4>
&lt;p>SAN(Subject Alternate Name)主题备用名称，主题备用名称证书简单来说，在需要多个域名，将其用于各项服务时，可使用SAN证书。&lt;br>
允许在安全证书中使用subjectAltName字段将多种值与证书关联，这些值被称为主题备用名称。名称可包括：IP地址、DNS名称等。&lt;/p>
&lt;p>San_subdomain_enum.py&lt;br>
工具描述：SSL/TLS证书中的SAN获取子域名 如上。&lt;/p>
&lt;h4 id="public-datasets-公开数据集">Public datasets （公开数据集）&lt;/h4>
&lt;p>有些项目收集了全互联网范围内的扫描数据，并将其提供给研究人员和安全社区。&lt;br>
该项目发布的数据集是子域名信息的宝库。&lt;br>
虽然在这个庞大的数据集中找到子域名就像大海捞针，但却值得我们去一试。&lt;/p>
&lt;p>Rapid7 Forward DNS dataset (Project Sonar)&lt;br>
工具描述：来自rapid7 sonar项目的公共数据集&lt;/p>
&lt;p>数据聚合网站&lt;/p>
&lt;pre tabindex="0">&lt;code>https://opendata.rapid7.com/
&lt;/code>&lt;/pre>&lt;h3 id="信息泄漏">信息泄漏&lt;/h3>
&lt;p>信息泄露&lt;br>
首先找到目标站点，在官网中可能会找到相关资产（多为办公系统，邮箱系统等），关注一下页面底部，也许有管理后台等收获。&lt;/p>
&lt;p>文件泄漏&lt;br>
crossdomain.xml(跨域策略文件cdx) robots.txt&lt;/p>
&lt;p>Git仓库泄露&lt;/p>
&lt;p>从流量中分析提取&lt;/p>
&lt;h3 id="内容解析htmljavascript文件">内容解析（HTML，JavaScript，文件）&lt;/h3>
&lt;p>BiLE-suite&lt;br>
工具描述：HTML解析，反向dns解析&lt;/p>
&lt;div class="highlight">&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;">&lt;code class="language-bash" data-lang="bash">&lt;span style="display:flex;">&lt;span>aptitude install httrack
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>git clone https://github.com/sensepost/BiLE-suite.git
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>perl BiLE.pl target.com
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>&lt;p>Second Order&lt;br>
工具描述：第二阶段域名扫描 通过HTML提取子域名&lt;/p>
&lt;div class="highlight">&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;">&lt;code class="language-bash" data-lang="bash">&lt;span style="display:flex;">&lt;span>go get xxx.com/mhmdiaa/second-order
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>cp ~/go/src/xxx.com/mhmdiaa/second-order/config.json
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>~/go/src/xxx.com/mhmdiaa/second-order/config-subs-enum.json
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>&lt;p>编辑修改LogCrawledURLs为True&lt;/p>
&lt;div class="highlight">&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;">&lt;code class="language-bash" data-lang="bash">&lt;span style="display:flex;">&lt;span>second-order -base https://target.com -config config.json -output target.com
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>&lt;h3 id="dns解析">DNS解析&lt;/h3>
&lt;p>在线查询:&lt;/p>
&lt;pre tabindex="0">&lt;code>VirusTotal(https://www.virustotal.com/)
ViewDNS(https://viewdns.info/)
DNSdumpster(https://dnsdumpster.com/)
&lt;/code>&lt;/pre>&lt;p>BiLE-suite&lt;br>
工具描述：HTML解析，反向dns解析 如上。&lt;/p>
&lt;p>Massdns&lt;br>
工具描述：dns解析&lt;/p>
&lt;div class="highlight">&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;">&lt;code class="language-bash" data-lang="bash">&lt;span style="display:flex;">&lt;span>git clone https://github.com/blechschmidt/massdns.git
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>cd massdns/
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>make
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>&lt;p>解析域名：&lt;/p>
&lt;div class="highlight">&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;">&lt;code class="language-bash" data-lang="bash">&lt;span style="display:flex;">&lt;span>/bin/massdns -r lists/resolvers.txt -t AAAA -w results.txt domains.txt -o S -w output.txt
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>&lt;p>爆破域名：&lt;/p>
&lt;div class="highlight">&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;">&lt;code class="language-bash" data-lang="bash">&lt;span style="display:flex;">&lt;span>./scripts/subbrute.py wordlist.txt target.com | ./bin/massdns -r lists/resolvers.txt -t A -o S -w output.txt
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>&lt;p>CT解析：&lt;/p>
&lt;div class="highlight">&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;">&lt;code class="language-bash" data-lang="bash">&lt;span style="display:flex;">&lt;span>./scripts/ct.py target.com | ./bin/massdns -r lists/resolvers.txt -t A -o S -w output.txt
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>&lt;h3 id="区域传送">区域传送&lt;/h3>
&lt;p>域传送是一种DNS事务，DNS服务器将其全部或部分域文件的副本传递给另一个DNS服务器。&lt;br>
如果未安全地配置域传输送，则任何人都可以对指定名称的服务器启动域传送并获取域文件的副本。&lt;br>
根据设计，域文件包含有关域和保存在域中的大量主机信息。&lt;/p>
&lt;p>Windows：&lt;br>
1.nslookup命令进入交互式shell&lt;br>
2.server命令 参数设定查询将要使用的DNS服务器&lt;br>
3.ls命令列出某个域中的所有域名&lt;/p>
&lt;p>Linux：&lt;br>
Dig&lt;br>
工具描述：dns区域传送，dns反向解析，dns解析&lt;/p>
&lt;div class="highlight">&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;">&lt;code class="language-bash" data-lang="bash">&lt;span style="display:flex;">&lt;span>dig +multi AXFR target.com
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>dig +multi AXFR $ns_server target.com
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>&lt;h3 id="dns-aggregators-dns聚合器">DNS aggregators （DNS聚合器）&lt;/h3>
&lt;p>Cloudflare_enum.py&lt;br>
工具描述：从Cloudflare提取子域名 dns聚合器&lt;/p>
&lt;div class="highlight">&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;">&lt;code class="language-bash" data-lang="bash">&lt;span style="display:flex;">&lt;span>pip install censys
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>git clone https://xxx.com/appsecco/the-art-of-subdomain-enumeration.git
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>cloudflare_subdomain_enum.py your@cloudflare.email&lt;span style="color:#f92672">[&lt;/span>4&lt;span style="color:#f92672">]&lt;/span> target.com
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>&lt;h3 id="dns-cache-snooping-域名缓存侦测">DNS Cache Snooping （域名缓存侦测）&lt;/h3>
&lt;p>域名缓存侦测（DNS Cache Snooping）技术&lt;br>
在企业网络中，通常都会配置DNS服务器，为网络内的主机提供域名解析服务。&lt;br>
这些DNS不仅解析自己的私有域名，还会用递归方式，请求公网的DNS解析第三方域名，如baidu.com之类。&lt;br>
为了提升性能，通常会使用缓存记录，记录解析过的域名，尤其是第三方域名。&lt;br>
域名缓存侦测（DNS Cache Snooping）技术就是向这些服务器发送域名解析请求，但要求不使用递归模式。&lt;br>
这样DNS只能解析私有域名和缓存中保存的域名。&lt;br>
借助该项技术，渗透测试人员就知道哪些域名是否被过请求过。&lt;br>
例如，测试人员可以提交某安全软件更新所使用的域名，如果有记录，说明该网络使用该种安全软件。&lt;/p>
&lt;h3 id="alterations--permutations-换置--排序">Alterations &amp;amp; permutations (换置 &amp;amp; 排序)&lt;/h3>
&lt;p>AltDNS&lt;br>
工具描述：通过换置&amp;amp;排序技术发现子域名&lt;/p>
&lt;div class="highlight">&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;">&lt;code class="language-bash" data-lang="bash">&lt;span style="display:flex;">&lt;span>git clone https://xxx.com/infosec-au/altdns.git
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>cd altdns
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>pip install -r requirements.txt
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>./altdns.py -i subdomains.txt -o data_output -w words.txt -r -s results_output.txt
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>&lt;h3 id="dnssecdomain-name-system-security-extensionsdns安全扩展dnssec区域漫步">DNSSEC(Domain Name System Security Extensions),DNS安全扩展，DNSSEC区域漫步&lt;/h3>
&lt;p>由于DNSSEC处理不存在域名的方式，您可以&amp;quot;遍历&amp;quot;DNSSEC域并枚举该域中的所有域名。&lt;/p>
&lt;p>Ldns-walk&lt;br>
工具描述：DNSSEC zone walking, 如果DNSSEC NSEC开启，可以获得全部域名。&lt;/p>
&lt;div class="highlight">&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;">&lt;code class="language-bash" data-lang="bash">&lt;span style="display:flex;">&lt;span>aptitude install ldnsutils
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>ldns-walk target.com
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>ldns-walk @nsserver.com target.com
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>&lt;p>如果DNSSEC NSEC开启，可以获得全部域名。&lt;/p>
&lt;h3 id="csp-http-首部">CSP HTTP 首部&lt;/h3>
&lt;p>Domains-from-csp&lt;br>
工具描述：从CSP头提取子域名&lt;/p>
&lt;div class="highlight">&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;">&lt;code class="language-bash" data-lang="bash">&lt;span style="display:flex;">&lt;span>git clone https://github.com/yamakira/domains-from-csp.git
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>pip install click
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>python csp_parser.py $URL
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>python csp_parser.py $URL -r
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>&lt;h3 id="spf记录">SPF记录&lt;/h3>
&lt;p>SPF是通过域名的TXT记录来进行设置的，SPF记录列出了所有被授权代表域名发送电子邮件的主机&lt;/p>
&lt;p>Assets-from-spf&lt;br>
工具描述：SPF域名记录&lt;/p>
&lt;div class="highlight">&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;">&lt;code class="language-bash" data-lang="bash">&lt;span style="display:flex;">&lt;span>git clone https://github.com/yamakira/assets-from-spf.git
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>pip install click ipwhois
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>python assets_from_spf.py target.com
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>&lt;h3 id="虚拟主机爆破">虚拟主机爆破&lt;/h3>
&lt;p>vhost-brute&lt;br>
工具描述：虚拟主机爆破&lt;/p>
&lt;div class="highlight">&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;">&lt;code class="language-bash" data-lang="bash">&lt;span style="display:flex;">&lt;span>aptitude install php-curl git clone https://github.com/gwen001/vhost-brute.git
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>&lt;p>Virtual-host-discovery&lt;br>
工具描述：虚拟主机爆破&lt;/p>
&lt;div class="highlight">&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;">&lt;code class="language-bash" data-lang="bash">&lt;span style="display:flex;">&lt;span>git clone https://github.com/jobertabma/virtual-host-discovery.git
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>ruby scan.rb --ip&lt;span style="color:#f92672">=&lt;/span>1.1.1.1 --host&lt;span style="color:#f92672">=&lt;/span>target.com --output output.txt
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>&lt;h3 id="asn发现">ASN发现&lt;/h3>
&lt;p>通过域名查询到 ASN，再通过 ASN 查询到所属的所有 ip 范围&lt;/p>
&lt;h3 id="爬虫-scraping抓取">爬虫 Scraping（抓取）&lt;/h3>
&lt;h4 id="泛解析问题">泛解析问题&lt;/h4>
&lt;p>目前最好的解决方式是通过先获取一个绝对不存在域名的响应内容，再遍历获取每个字典对应的子域名的响应内容，通过和不存在域名的内容做相似度比对，来枚举子域名，但这样的实现是以牺牲速度为代价&lt;/p>
&lt;h3 id="tools">Tools&lt;/h3>
&lt;ul>
&lt;li>
&lt;p>工具也有很多厉害的，平时我一般使用 OneForALL + ESD + JSfinder 来进行搜集，（ESD 可以加载 layer 的字典，很好用）
&lt;code>https://github.com/shmilylty/OneForAll&lt;/code>&lt;/p>
&lt;/li>
&lt;li>
&lt;p>强大的快速子域枚举工具
&lt;code>https://github.com/aboul3la/Sublist3r&lt;/code>&lt;/p>
&lt;/li>
&lt;li>
&lt;p>Knock子域名获取，可用于查找子域名接管漏洞
&lt;code>https://github.com/guelfoweb/knock&lt;/code>&lt;/p>
&lt;/li>
&lt;li>
&lt;p>一款便捷高效的子域名爆破工具
&lt;code>https://github.com/yanxiu0614/subdomain3&lt;/code>&lt;/p>
&lt;/li>
&lt;li>
&lt;p>Go语言开发的子域名枚举工具
&lt;code>https://github.com/caffix/amass&lt;/code>&lt;/p>
&lt;/li>
&lt;li>
&lt;p>继承于Sublist3r项目的模块化体系结构
&lt;code>https://github.com/Ice3man543/subfinder&lt;/code>&lt;/p>
&lt;/li>
&lt;li>
&lt;p>带有网页截图功能的子可视化域名枚举工具
&lt;code>https://github.com/janniskirschner/horn3t&lt;/code>&lt;/p>
&lt;/li>
&lt;li>
&lt;p>Lijiejie开发的一款使用广泛的子域名爆破枚举工具
&lt;code>https://github.com/lijiejie/subDomainsBrute&lt;/code>&lt;/p>
&lt;/li>
&lt;li>
&lt;p>猪猪侠开发的一款域名收集全面、精准的子域名枚举工具
&lt;code>https://github.com/ring04h/wydomain&lt;/code>&lt;/p>
&lt;/li>
&lt;/ul>
&lt;h3 id="子域名监控">子域名监控&lt;/h3>
&lt;p>&lt;code>https://github.com/LangziFun/LangSrcCurise&lt;/code>&lt;/p>
&lt;p>&lt;code>https://www.freebuf.com/sectool/198396.html&lt;/code>&lt;/p>
&lt;h3 id="参考">参考&lt;/h3>
&lt;p>&lt;a href="https://mp.weixin.qq.com/s/m8ucI1bDxILM8wLU6pLmoQ">1&lt;/a>
&lt;a href="https://xz.aliyun.com/t/3478">2&lt;/a>
&lt;a href="https://blog.csdn.net/qq_39293438/article/details/104829825">3&lt;/a>
&lt;a href="https://info.menandmice.com/blog/bid/73645/Take-your-DNSSEC-with-a-grain-of-salt">4&lt;/a>&lt;/p></description></item><item><title>开启 Telegram 的邮箱登录</title><link>https://blog.baicai.me/article/2023/telegram_email_login/</link><pubDate>Tue, 26 Dec 2023 15:00:23 +0800</pubDate><author>admin@baicai.me (白菜)</author><guid>https://blog.baicai.me/article/2023/telegram_email_login/</guid><description>&lt;h2 id="telegram的邮箱登录是什么-有什么用">Telegram的邮箱登录是什么? 有什么用?&lt;/h2>
&lt;p>邮箱登录就是通过电子邮件获取验证码来登录Telegram账户, 此功能可以在把验证码发送到Telegram客户端的情况下同时向邮箱发送一份验证码, 而不是通过短信发送验证码. 极大减少了Telegram官方的短信费用支出. 对于使用接码的用户来说, 再也不怕没客户端也没手机号的情况下收不到验证码了!&lt;/p>
&lt;h2 id="如何开启telegram邮箱登录">如何开启Telegram邮箱登录?&lt;/h2>
&lt;p>&lt;code>注意 账号绑定的手机号需要可以接收短信验证码, 否则无法设置邮箱登录&lt;/code>&lt;/p>
&lt;p>根据&lt;a href="https://core.telegram.org/api/auth">官方文档&lt;/a>来看,&lt;/p>
&lt;ul>
&lt;li>auth.sentCodeTypeSetUpEmailRequired: if the user logins often enough, Telegram will ask the user to verify an email that will be used to send the login code.&lt;/li>
&lt;li>当你的登录频率足够高时, Telegram服务器会要求客户端设置邮箱登录&lt;/li>
&lt;/ul>
&lt;h3 id="具体方法">具体方法&lt;/h3>
&lt;ul>
&lt;li>使用Telegram官方移动客户端登录, 登录时选择 Tap to get a code via SMS&lt;/li>
&lt;li>短信验证码和Telegram客户端验证码一致, 任选其一输入即可, 不需要输入2FA密码, 直接返回重新刷&lt;/li>
&lt;/ul>
&lt;p>如果过程中出现 &lt;code>Too many attemps, please try again later&lt;/code> 则需要休息一段时间再刷&lt;/p>
&lt;p>直到出现让你选择登录邮箱的提示界面&lt;/p>
&lt;p>根据提示输入完成邮箱验证码后会向你的账号绑定手机号码发送短信验证码, 输入完即可开启邮箱登录 (2FA可以不输入)&lt;/p>
&lt;h2 id="如何判断有没有开启邮箱登录">如何判断有没有开启邮箱登录?&lt;/h2>
&lt;p>在设置-隐私与安全界面，可看到已设置的“登录邮箱”&lt;/p>
&lt;h2 id="参考">参考：&lt;/h2>
&lt;p>&lt;a href="https://telegra.ph/Telegram%E7%9A%84%E9%82%AE%E7%AE%B1%E7%99%BB%E5%BD%95-12-26">Telegram的邮箱登录&lt;/a>&lt;br>
&lt;a href="https://core.telegram.org/api/auth#email-verification">User Authorization&lt;/a>&lt;/p></description></item><item><title>通过 ADB 卸载系统自带应用(无需Root),精简系统app</title><link>https://blog.baicai.me/article/2023/adb_pm_uninstall/</link><pubDate>Tue, 05 Dec 2023 13:31:02 +0800</pubDate><author>admin@baicai.me (白菜)</author><guid>https://blog.baicai.me/article/2023/adb_pm_uninstall/</guid><description>&lt;h3 id="准备-adb-使用条件">准备 ADB 使用条件&lt;/h3>
&lt;p>要使用 ADB（Android 调试桥），你需要按照以下步骤操作：&lt;/p>
&lt;p>下载并安装 ADB 工具：&lt;/p>
&lt;pre>&lt;code>在计算机上安装 Android SDK 或者仅安装 ADB 工具。你可以从 Android 官方网站或者其他可信赖的来源获取它们。
如果你使用 macOS 或 Linux，你可以通过终端使用系统包管理器或 Homebrew 安装 ADB。
如果你使用 Windows，你可以下载 Android Studio，它包含了 ADB 工具。
&lt;/code>&lt;/pre>
&lt;p>连接 Android 设备：&lt;/p>
&lt;pre>&lt;code>使用 USB 线将 Android 设备连接到计算机上。
在 Android 设备上打开开发者选项。这通常需要在设备设置中多次点击“关于手机” -&amp;gt; “版本号”或者类似的选项。一旦开启，返回设置菜单并找到“开发者选项”。
在“开发者选项”中，启用“USB 调试”。
&lt;/code>&lt;/pre>
&lt;p>打开命令提示符（Windows）/终端（macOS、Linux）：&lt;/p>
&lt;pre>&lt;code>运行以下命令以确保 ADB 正确识别设备：
&lt;/code>&lt;/pre>
&lt;div class="highlight">&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;">&lt;code class="language-bash" data-lang="bash">&lt;span style="display:flex;">&lt;span>adb devices
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>&lt;p>这应该显示已连接设备的列表。&lt;/p>
&lt;h3 id="使用-adb-列出已经安装的应用程序">使用 ADB 列出已经安装的应用程序&lt;/h3>
&lt;p>打开命令提示符（Windows）/终端（macOS、Linux）：&lt;/p>
&lt;pre>&lt;code>在命令提示符/终端中输入以下命令来列出已安装的应用程序：
&lt;/code>&lt;/pre>
&lt;div class="highlight">&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;">&lt;code class="language-bash" data-lang="bash">&lt;span style="display:flex;">&lt;span>adb shell pm list packages
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>&lt;p>如果你想筛选出包含特定关键词的应用程序，可以使用以下命令：&lt;/p>
&lt;div class="highlight">&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;">&lt;code class="language-bash" data-lang="bash">&lt;span style="display:flex;">&lt;span>adb shell pm list packages | grep keyword
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>&lt;p>将 &amp;ldquo;keyword&amp;rdquo; 替换为你想要搜索的关键词。
比如魅族的手机&lt;/p>
&lt;div class="highlight">&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;">&lt;code class="language-bash" data-lang="bash">&lt;span style="display:flex;">&lt;span>adb shell pm list packages | grep com.meizu
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>&lt;h3 id="使用-adb-在-android-设备上卸载普通应用程序">使用 ADB 在 Android 设备上卸载普通应用程序&lt;/h3>
&lt;p>打开命令提示符（Windows）/终端（macOS、Linux）：&lt;/p>
&lt;pre>&lt;code>在命令提示符/终端中输入以下命令来卸载应用程序：
&lt;/code>&lt;/pre>
&lt;div class="highlight">&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;">&lt;code class="language-bash" data-lang="bash">&lt;span style="display:flex;">&lt;span> adb uninstall package_name
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>&lt;pre>&lt;code>将 package_name 替换为你想要卸载的应用程序的包名。你可以通过之前提到的 adb shell pm list packages 命令来获取应用程序的包名列表。
&lt;/code>&lt;/pre>
&lt;p>示例：&lt;/p>
&lt;pre>&lt;code>假设你想卸载名为 &amp;quot;com.example.app&amp;quot; 的应用程序，命令将如下所示：
&lt;/code>&lt;/pre>
&lt;div class="highlight">&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;">&lt;code class="language-bash" data-lang="bash">&lt;span style="display:flex;">&lt;span> adb uninstall com.example.app
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>&lt;p>确认卸载：&lt;/p>
&lt;pre>&lt;code>执行命令后，ADB 会尝试卸载该应用程序。等待一段时间，命令提示符/终端会显示成功或失败的信息。
&lt;/code>&lt;/pre>
&lt;p>这个指令卸载系统自带应用可以能会遇到 &lt;code>Failure [DELETE_FAILED_INTERNAL_ERROR]&lt;/code> 错误提示&lt;/p>
&lt;h3 id="使用-adb-在-android-设备上卸载系统自带应用程序">使用 ADB 在 Android 设备上卸载系统自带应用程序&lt;/h3>
&lt;p>清除应用程序数据：&lt;/p>
&lt;pre>&lt;code>在卸载应用之前，尝试先清除该应用的数据。使用以下命令：
&lt;/code>&lt;/pre>
&lt;div class="highlight">&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;">&lt;code class="language-bash" data-lang="bash">&lt;span style="display:flex;">&lt;span> adb shell pm clear package_name
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>&lt;pre>&lt;code>将 package_name 替换为应用程序的包名。
&lt;/code>&lt;/pre>
&lt;p>强制停止应用程序：&lt;/p>
&lt;pre>&lt;code>如果应用程序正在运行，尝试通过 ADB 强制停止应用程序再进行卸载：
&lt;/code>&lt;/pre>
&lt;div class="highlight">&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;">&lt;code class="language-bash" data-lang="bash">&lt;span style="display:flex;">&lt;span>adb shell am force-stop package_name
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>&lt;p>将 package_name 替换为应用程序的包名。&lt;/p>
&lt;p>确保设备有足够的存储空间来完成卸载操作。有时设备存储空间不足可能会导致卸载失败。&lt;/p>
&lt;p>使用 ADB shell 运行命令：&lt;/p>
&lt;div class="highlight">&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;">&lt;code class="language-bash" data-lang="bash">&lt;span style="display:flex;">&lt;span>adb shell
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>pm uninstall -k --user &lt;span style="color:#ae81ff">0&lt;/span> package_name
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>&lt;p>将 package_name 替换为要卸载的系统应用的包名。&lt;/p>
&lt;h4 id="列出魅族自带的部分应用程序">列出魅族自带的部分应用程序&lt;/h4>
&lt;div class="highlight">&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;">&lt;code class="language-bash" data-lang="bash">&lt;span style="display:flex;">&lt;span>&lt;span style="color:#75715e">#列出包名前缀为 com.meizu 应用&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>$adb shell pm list packages | grep com.meizu
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>package:com.meizu.documentsui
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>package:com.meizu.flyme.hometools
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>package:com.meizu.flyme.launcher
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>package:com.meizu.desktopbackup
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>package:com.meizu.account.pay
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>package:com.meizu.powersave
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>package:com.meizu.mzsimcontacts
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>package:com.meizu.filemanager
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>package:com.meizu.flyme.directservice
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>package:com.meizu.compaign
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>package:com.meizu.splitloccontroller
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>package:com.meizu.backup
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>package:com.meizu.flyme.update
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>package:com.meizu.net.map
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>package:com.meizu.flyme.wallet
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>package:com.meizu.feedback
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>package:com.meizu.media.camera
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>package:com.meizu.flyme.providers.forcetouch
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>package:com.meizu.mstore
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>package:com.meizu.net.search
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>package:com.meizu.perfui
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>package:com.meizu.sceneinfo
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>package:com.meizu.flyme.telecom
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>package:com.meizu.notepaper
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>package:com.meizu.flyme.calculator
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>package:com.meizu.yellowpage
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>package:com.meizu.safe
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>package:com.meizu.media.reader
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>package:com.meizu.flyme.toolbox
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>package:com.meizu.connectivitysettings
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>package:com.meizu.flyme.childrenlauncher
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>package:com.meizu.gamecenter.service
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>package:com.meizu.mznfcpay
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>package:com.meizu.account
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>package:com.meizu.media.ebook
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>package:com.meizu.media.music
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>package:com.meizu.media.video
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>package:com.meizu.media.gallery
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>package:com.meizu.alphame
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>package:com.meizu.dataservice
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>package:com.meizu.systemwallpaper
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>package:com.meizu.flymecommunication
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>package:com.meizu.flyme.mall
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>package:com.meizu.voiceassistant
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>package:com.meizu.cloud
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>package:com.meizu.mcare
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>package:com.meizu.setup
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>package:com.meizu.share
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>package:com.meizu.flyme.easylauncher
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>package:com.meizu.battery
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>package:com.meizu.mzsyncservice
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>package:com.meizu.privacy
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>package:com.meizu.datamigration
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>package:com.meizu.location
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>package:com.meizu.flyme.input
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>package:com.meizu.flyme.service.find
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>package:com.meizu.customizecenter
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>package:com.meizu.flyme.gamecenter
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>package:com.meizu.experiencedatasync
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>package:com.meizu.callsetting
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>package:com.meizu.netcontactservice
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>package:com.meizu.media.life
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>package:com.meizu.flyme.weather
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>&lt;h4 id="卸载魅族自带的部分应用程序">卸载魅族自带的部分应用程序&lt;/h4>
&lt;div class="highlight">&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;">&lt;code class="language-bash" data-lang="bash">&lt;span style="display:flex;">&lt;span>$adb shell
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#75715e">#语音助手&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>$pm uninstall -k --user &lt;span style="color:#ae81ff">0&lt;/span> com.meizu.voiceassistant
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#75715e">#天气预报&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>$pm uninstall -k --user &lt;span style="color:#ae81ff">0&lt;/span> com.meizu.flyme.weather
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#75715e">#备份与恢复&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>$pm uninstall -k --user &lt;span style="color:#ae81ff">0&lt;/span> com.meizu.backup
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#75715e">#手机云备份&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>$pm uninstall -k --user &lt;span style="color:#ae81ff">0&lt;/span> com.meizu.desktopbackup
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#75715e">#换机助手&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>$pm uninstall -k --user &lt;span style="color:#ae81ff">0&lt;/span> com.meizu.datamigration
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#75715e">#福利中心&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>$pm uninstall -k --user &lt;span style="color:#ae81ff">0&lt;/span> com.meizu.compaign
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#75715e">#钱包&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>$pm uninstall -k --user &lt;span style="color:#ae81ff">0&lt;/span> com.meizu.flyme.wallet
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>$pm uninstall -k --user &lt;span style="color:#ae81ff">0&lt;/span> com.meizu.mznfcpay
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#75715e">#全球虚拟流量&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>$pm uninstall -k --user &lt;span style="color:#ae81ff">0&lt;/span> com.flyme.roamingpay
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#75715e">#地图&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>$pm uninstall -k --user &lt;span style="color:#ae81ff">0&lt;/span> com.meizu.net.map
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#75715e">#快应用引擎&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>$pm uninstall -k --user &lt;span style="color:#ae81ff">0&lt;/span> com.meizu.flyme.directservice
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#75715e">#云号码&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>$pm uninstall -k --user &lt;span style="color:#ae81ff">0&lt;/span> com.meizu.netcontactservice
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#75715e">#生活服务&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>$pm uninstall -k --user &lt;span style="color:#ae81ff">0&lt;/span> com.meizu.media.life
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#75715e">#游戏中心&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>$pm uninstall -k --user &lt;span style="color:#ae81ff">0&lt;/span> com.meizu.flyme.gamecenter
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>$pm uninstall -k --user &lt;span style="color:#ae81ff">0&lt;/span> com.meizu.gamecenter.service
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#75715e">#音乐&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>$pm uninstall -k --user &lt;span style="color:#ae81ff">0&lt;/span> com.meizu.media.music
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#75715e">#视频&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>$pm uninstall -k --user &lt;span style="color:#ae81ff">0&lt;/span> com.meizu.media.video
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#75715e">#读书&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>$pm uninstall -k --user &lt;span style="color:#ae81ff">0&lt;/span> com.meizu.media.ebook
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#75715e">#新闻资讯&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>$pm uninstall -k --user &lt;span style="color:#ae81ff">0&lt;/span> com.meizu.media.reader
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#75715e">#便签&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>$pm uninstall -k --user &lt;span style="color:#ae81ff">0&lt;/span> com.meizu.notepaper
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#75715e">#应用商店&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>$pm uninstall -k --user &lt;span style="color:#ae81ff">0&lt;/span> com.meizu.mstore
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>$pm uninstall -k --user &lt;span style="color:#ae81ff">0&lt;/span> com.flyme.meizu.store
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#75715e">#系统更新&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>$pm uninstall -k --user &lt;span style="color:#ae81ff">0&lt;/span> com.meizu.flyme.update
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#75715e">#魅族服务&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>$pm uninstall -k --user &lt;span style="color:#ae81ff">0&lt;/span> com.meizu.mcare
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>$pm uninstall -k --user &lt;span style="color:#ae81ff">0&lt;/span> com.meizu.flyme.mall
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#75715e">#用户帮助&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>$pm uninstall -k --user &lt;span style="color:#ae81ff">0&lt;/span> com.meizu.feedback
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#75715e">#搜索&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>$pm uninstall -k --user &lt;span style="color:#ae81ff">0&lt;/span> com.meizu.net.search
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#75715e">#文件管理&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>$pm uninstall -k --user &lt;span style="color:#ae81ff">0&lt;/span> com.meizu.filemanager
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#75715e">#动态壁纸&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>$pm uninstall -k --user &lt;span style="color:#ae81ff">0&lt;/span> com.vlife.mxlock.wallpaper
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#75715e">#输入法&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>$pm uninstall -k --user &lt;span style="color:#ae81ff">0&lt;/span> com.sohu.inputmethod.sogou
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#75715e">#浏览器&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>$pm uninstall -k --user &lt;span style="color:#ae81ff">0&lt;/span> com.android.browser
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#75715e"># 家庭守护&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>$pm uninstall -k --user &lt;span style="color:#ae81ff">0&lt;/span> com.meizu.sceneinfo
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#75715e">#京东&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>$pm uninstall -k --user &lt;span style="color:#ae81ff">0&lt;/span> com.jingdong.app.mall
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#75715e">#天猫&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>$pm uninstall -k --user &lt;span style="color:#ae81ff">0&lt;/span> com.tmall.wireless
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#75715e">#微博&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>$pm uninstall -k --user &lt;span style="color:#ae81ff">0&lt;/span> com.sina.weibo
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#75715e">#高德地图&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>$pm uninstall -k --user &lt;span style="color:#ae81ff">0&lt;/span> com.autonavi.minimap
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#75715e">#今日头条&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>$pm uninstall -k --user &lt;span style="color:#ae81ff">0&lt;/span> com.ss.android.article.news
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#75715e">#去哪儿&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>$pm uninstall -k --user &lt;span style="color:#ae81ff">0&lt;/span> com.Qunar
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#75715e">#喜马拉雅&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>$pm uninstall -k --user &lt;span style="color:#ae81ff">0&lt;/span> com.ximalaya.ting.android
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#75715e">#趣视频&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#75715e">#拼多多&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>pm uninstall -k --user &lt;span style="color:#ae81ff">0&lt;/span> com.xunmeng.pinduoduo
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#75715e">#百度搜索&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>pm uninstall -k --user &lt;span style="color:#ae81ff">0&lt;/span> com.baidu.searchbox
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#75715e">#微博&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>pm uninstall -k --user &lt;span style="color:#ae81ff">0&lt;/span> com.sina.weibolite
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#75715e">#flyme实验室&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>pm uninstall -k --user &lt;span style="color:#ae81ff">0&lt;/span> com.meizu.flymelab
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#75715e">#好看&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>pm uninstall -k --user &lt;span style="color:#ae81ff">0&lt;/span> com.baidu.haokan
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#75715e">#淘宝&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>pm uninstall -k --user &lt;span style="color:#ae81ff">0&lt;/span> com.taobao.taobao
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#75715e">#搜狗输入法&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>pm uninstall -k --user &lt;span style="color:#ae81ff">0&lt;/span> com.sohu.inputmethod.sogou.meizu
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#75715e">#唯品会&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>pm uninstall -k --user &lt;span style="color:#ae81ff">0&lt;/span> com.achievo.vipshop
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#75715e">#部分系统应用&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#75715e">#计步器&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> pm uninstall -k --user &lt;span style="color:#ae81ff">0&lt;/span> com.meizu.net.pedometer
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#75715e">#支付中心&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>pm uninstall -k --user &lt;span style="color:#ae81ff">0&lt;/span> com.meizu.account.pay
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#75715e">#个人助理&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>pm uninstall -k --user &lt;span style="color:#ae81ff">0&lt;/span> com.meizu.assistant
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#75715e">#智能识屏&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>pm uninstall -k --user &lt;span style="color:#ae81ff">0&lt;/span> com.meizu.picker
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#75715e">#工具箱&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>pm uninstall -k --user &lt;span style="color:#ae81ff">0&lt;/span> com.meizu.flyme.toolbox
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#75715e">#系统壁纸&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>pm uninstall -k --user &lt;span style="color:#ae81ff">0&lt;/span> com.meizu.systemwallpaper
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#75715e">#动态主题服务&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>pm uninstall -k --user &lt;span style="color:#ae81ff">0&lt;/span> com.ibimuyu.lockscreen
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#75715e">#下载&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>pm uninstall -k --user &lt;span style="color:#ae81ff">0&lt;/span> com.android.providers.downloads.ui
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#75715e">#动态壁纸 &lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>pm uninstall -k --user &lt;span style="color:#ae81ff">0&lt;/span> com.meizu.activeviewlivewallpaper
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#75715e">#主题美化&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>pm uninstall -k --user &lt;span style="color:#ae81ff">0&lt;/span> com.meizu.customizecenter
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#75715e">#onemind&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>pm uninstall -k --user &lt;span style="color:#ae81ff">0&lt;/span> com.meizu.alphame
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#75715e">#以下部分不建议删除应用&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>pm uninstall -k --user &lt;span style="color:#ae81ff">0&lt;/span> com.meizu.flyme.hometools
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>pm uninstall -k --user &lt;span style="color:#ae81ff">0&lt;/span> com.android.providers.downloads
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>pm uninstall -k --user &lt;span style="color:#ae81ff">0&lt;/span> com.meizu.flyme.calculator
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>pm uninstall -k --user &lt;span style="color:#ae81ff">0&lt;/span> com.meizu.yellowpage
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>pm uninstall -k --user &lt;span style="color:#ae81ff">0&lt;/span> com.meizu.safe
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>pm uninstall -k --user &lt;span style="color:#ae81ff">0&lt;/span> com.android.printspooler
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>pm uninstall -k --user &lt;span style="color:#ae81ff">0&lt;/span> com.meizu.media.gallery
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>pm uninstall -k --user &lt;span style="color:#ae81ff">0&lt;/span> com.meizu.cloud
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>pm uninstall -k --user &lt;span style="color:#ae81ff">0&lt;/span> com.meizu.share
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>pm uninstall -k --user &lt;span style="color:#ae81ff">0&lt;/span> com.meizu.location
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>pm uninstall -k --user &lt;span style="color:#ae81ff">0&lt;/span> com.android.email
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>pm uninstall -k --user &lt;span style="color:#ae81ff">0&lt;/span> com.meizu.mzsyncservice
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>pm uninstall -k --user &lt;span style="color:#ae81ff">0&lt;/span> com.android.wallpaperbackup
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>pm uninstall -k --user &lt;span style="color:#ae81ff">0&lt;/span> com.meizu.flyme.mmfvideo
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>pm uninstall -k --user &lt;span style="color:#ae81ff">0&lt;/span> com.flyme.telecom.usagedata.service
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#75715e">#谨慎删除&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>pm uninstall -k --user &lt;span style="color:#ae81ff">0&lt;/span> com.meizu.account
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>pm uninstall -k --user &lt;span style="color:#ae81ff">0&lt;/span> com.meizu.flyme.service.find
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>&lt;h3 id="附注">附注：&lt;/h3>
&lt;p>安装 APK 文件：
将要安装的 APK 文件复制到计算机上，并记住它的路径。
在命令提示符/终端中，使用以下命令安装 APK 文件到设备：&lt;/p>
&lt;div class="highlight">&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;">&lt;code class="language-bash" data-lang="bash">&lt;span style="display:flex;">&lt;span>adb install /path/to/your/app.apk
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>&lt;p>请将 &lt;code>/path/to/your/app.apk&lt;/code> 替换为实际 APK 文件的路径。&lt;/p>
&lt;h3 id="flyme9-应用列表">Flyme9 应用列表&lt;/h3>
&lt;pre tabindex="0">&lt;code>全球流量 com.flyme.roamingpay
旅行助手com.android.cts.priv.ctsshim
应用沙盒com.meizu.pps 不建议删除
计步器 com.meizu.net.pedometer
电话和短信存储 com.android.providers.telephony 不建议删除
日历存储com.android.providers.calendar 不建议删除
媒体存储设备 com.android.providers.media 不建议删除
mbn测试 com.qualcomm.qit.modemtestmode 不建议删除
系统桌面 com.meizu.flyme.launcher 不建议删除
支付中心 com.meizu.account.pay
时钟 com.andriod.alarmclock
html查看程序 com.android.htmlviewer 不建议删除
语音设置com.iflytek.speechsuite
mms短信服务 com.android.mms.service 不建议删除
下载管理器com.android.providers.downloads 不建议删除
文件管理 com.meizu.filemanager 不建议删除
通讯录counnunity.fairphone.mycontacts 不建议删除
魅族浏览器 com.android.browser
快应用引擎 com.meizu.flyme.directservice
福利中心 com.meizu.compaign
录音机 com.android.soundrecorder
软件包权限帮助程序com.android.defcontainer 不建议删除
备份和恢复com.meizu.backup
下载com.android.providers.downloads.ui 不建议删除
系统更新com.meizu.flyme.update
无线网络助手com.meizu.wifiadmin 不建议删除
证书安装程序com.android.certinstaller 不建议删除
个人助理com.meizu.assistant
钱包com.meizu.flyme.wallet
用户帮助com.meizu.feedback
相机com.meizu.media.camera 不建议删除
设备信息com.qti.qualcomm.deviceinfo 不建议删除
信息com.android.mms 不建议删除
应用商店com.meizu.mstore 不建议删除
mtp主机com.android.mtp 不建议删除
usim卡应用com.android.stk
搜索com.meizu.net.search
性能监视器com.meizu.perfui
智能识屏 com.meizu.picker
家庭守护com.meizu.sceneinfo
便笺com.meizu.notepaper
计算器com.flyme.caculator
日历com.android.calendar
手机管家com.meizu.safe 不建议删除
新闻资讯com.meizu.media.reader
工具箱com.flyme.toolbox
网络设置com.connectivitysettings 不建议删除
设置存储com.android.providers.settings 不建议删除
打印处理服务com.android.printspooler
通话com.android.incallui 不建议删除
输入设备com.android.inputdevices · 不建议删除
系统公共组件com.meizu.flyme.sdkstage 不建议删除
系统界面助手com.flyme.systemuiex 不建议删除
默认打印服务com.android.bips
魅族游戏框架com.meizu.gamecenter.service
动态主题服务com.ibimuyu.lockscreen 不建议删除
xdivert设置com.qti.xdivert
musicfx com.android.musicfx
通话控制com.android.server.telecom 不建议删除
魅族支付com.meizu.mznfcpay
密钥连com.android.keychain
电话com.android.dialer 不建议删除
系统界面工具com.flyme.systemuitools 不建议删除
flyme账号com.meizu.account 不建议删除 删除后进不了自带的系统设置
软件包安装程序com.android.packageinstaller 不建议删除
音乐com.meizu.media.music
视频com.meizu.media.video
运营商默认应用com.android.carrierdefaultapp
文本转语音组件com.svox.pico
图库com.meizu.media.gallery
onemind com.meizu.alphame
工作资料设置com.android.managedprovisioning 不建议删除
platformfx com.meizu.dateservice 不建议删除
网络管理com.flyme.netadmin 不建议删除
远程协助com.meizu.remotecooperation
工程模式com.meizu.telephonyengineermode
系统壁纸com.meizu.systemwallpaper
sms推送com.android.smspush 不建议删除
语音助手com.meizu.voiceassistant
推送服务com.meizu.cloud 不建议删除
魅族虚拟卡本地注册虚拟网络插件com.flyme.virtual.softsim 删除后无法使用全球流量功能
蓝牙分享com.meizu.share 不建议删除
魅族商城com.flyme.meizu.store
超大字体简易模式com.meizu.flyme.easylauncher
图像服务com.meizu.media.imageservice 不建议删除
存储空间管理器com.android.stooragemanager 不建议删除
人脸识别com.meizu.facerecognition
com.google.andriod.onetimeinitialzer
设置com.android.settings 不建议删除
电量管理com.meizu.battery
flyme云服务com.meizu.mzsyncservice
动态壁纸 com.meizu.activeviewlivewallpaper
换机助手com.meizu.datemigration
位置服务com.qualcomm.location 不建议删除
网络位置服务com.meizu.location 不建议删除
动态主题服务com.vlife.mxlock.wallpaper
桌面壁纸备份 com.android.wallpaperbackup
系统输入法com.meizu.flyme.input 不建议删除
查找手机服务com.meizu.flyme.service.find
电话服务com.android.phone 不建议删除
存储已屏蔽的号码com.android.providers.blockednumber 不建议删除
用户字典com.android.providers.userdictionary
急救信息com.android.emergency 不建议删除
主题美化com.meizu.customizecenter
flyme实验室com.meizu.flymelab
一体化位置信息com.android.location.fused 不建议删除
游戏中心com.meizu.flyme.gamecenter
系统界面com.android.systemui 不建议删除
崩溃数据上传 com.meizu.experiencedatasync
电话设置com.meizu.callsetting 不建议删除
关机闹钟com.qualcomm.qti.poweroffalarm 不建议删除
号码云服务com.meizu.netcontactservice
生活助手com.meizu.media.life
联系人存储com.android.providers.contacts 不建议删除
天气com.meizu.flyme.weather
支付宝com.eg.android.AlipayGphone
电话服务com.flyme.telecom.usagedate.service 不建议删除
com.qualcomm.qti.perfdump 不建议删除
com.android.webview 不建议删除
com.android.backupconfirm
书签com.android.bookmarkprovider
com.android.flyme.bridge.softsim
com.meizu.privacy
com.meizu.flyme.hometools 不建议删除
小区广播com.android.cellbroadcastreceiver 不建议删除
无线网络助手 com.meizu.wifiadmin 不建议删除
读书 com.meizu.media.ebook
邮件 com.android.email
趣视频 com.flyme.videoclips
新闻资讯 com.meizu.media.reader
换机助手 com.meizu.datamigration
语音设置 com.iflytek.speechsuite
魅族服务 com.meizu.mcare
开机引导 com.meizu.setup
极限模式 com.meizu.powersave 不建议删除
Aicy建议 com.meizu.suggestion
锁屏画报 com.meizu.net.nativelockscreen
伪基站拦截 com.meizu.mzbasestationsafe
打印服务处理 com.android.printspooler 不建议删除
html查看程序 com.android.htmlviewer
通话记录备份 com.android.calllogbackup
虚拟sim卡用的com.qualcomm.uimremoteclient
自带黑色主题com.android.systemui.theme.dark
无线电服务com.dsi.ant.server
&lt;/code>&lt;/pre></description></item><item><title>Kubernetes 停止和移除 pod</title><link>https://blog.baicai.me/article/2023/delete_pod/</link><pubDate>Mon, 20 Nov 2023 16:02:50 +0800</pubDate><author>admin@baicai.me (白菜)</author><guid>https://blog.baicai.me/article/2023/delete_pod/</guid><description>&lt;h2 id="停止和移除pod">停止和移除pod&lt;/h2>
&lt;h3 id="按名称删除pod">按名称删除pod&lt;/h3>
&lt;p>按名称删除kubia-gpu pod：&lt;/p>
&lt;div class="highlight">&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;">&lt;code class="language-bash" data-lang="bash">&lt;span style="display:flex;">&lt;span>kubectl delete po kubia-gpu
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>&lt;p>在删除pod的过程中，实际上我们在指示Kubernetes终止该pod中的所有容器。Kubernetes向进程发送一个SIGTERM信号并等待一定的秒数（默认为30），使其正常关闭。如果它没有及时关闭，则通过SIGKILL终止该进程。因此，为了确保你的进程总是正常关闭，进程需要正确处理SIGTERM信号。&lt;/p>
&lt;h4 id="提示">提示&lt;/h4>
&lt;p>还可以通过指定多个空格分隔的名称来删除多个pod（例如：kubectl delete po pod1 pod2）。&lt;/p>
&lt;h3 id="使用标签选择器删除pod">使用标签选择器删除pod&lt;/h3>
&lt;p>停止 kubia-manual 和 kubia-manual-v2 pod 。这两个pod都包含标签 &lt;code>creation_method=manual&lt;/code> ，因此可以通过使用一个标签选择器来删除它们：&lt;/p>
&lt;div class="highlight">&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;">&lt;code class="language-bash" data-lang="bash">&lt;span style="display:flex;">&lt;span>kubectl delete po -l creation_method&lt;span style="color:#f92672">=&lt;/span>manual
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>&lt;h3 id="通过删除整个命名空间来删除pod">通过删除整个命名空间来删除pod&lt;/h3>
&lt;p>以下命令删除custom-namespace：&lt;/p>
&lt;div class="highlight">&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;">&lt;code class="language-bash" data-lang="bash">&lt;span style="display:flex;">&lt;span>kubectl delete ns custom-namespace
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>&lt;h3 id="删除命名空间中的所有pod但保留命名空间">删除命名空间中的所有pod，但保留命名空间&lt;/h3>
&lt;p>查看 pods&lt;/p>
&lt;div class="highlight">&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;">&lt;code class="language-bash" data-lang="bash">&lt;span style="display:flex;">&lt;span>kubectl get pods
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>&lt;p>通过使用&amp;ndash;all选项告诉Kubernetes删除当前命名空间中的所有pod：&lt;/p>
&lt;div class="highlight">&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;">&lt;code class="language-bash" data-lang="bash">&lt;span style="display:flex;">&lt;span>kubectl delete po --all
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>&lt;h3 id="删除命名空间中的几乎所有资源">删除命名空间中的（几乎）所有资源&lt;/h3>
&lt;p>通过使用单个命令删除当前命名空间中的所有资源，可以删除ReplicationCcontroller和pod，以及我们创建的所有service：&lt;/p>
&lt;div class="highlight">&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;">&lt;code class="language-bash" data-lang="bash">&lt;span style="display:flex;">&lt;span>kubectl delete all --all
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>&lt;p>命令中的第一个all指定正在删除所有资源类型，而&amp;ndash;all选项指定将删除所有资源实例，而不是按名称指定它们（我们在运行前一个删除命令时已经使用过此选项）。&lt;/p>
&lt;h4 id="注意">注意&lt;/h4>
&lt;p>使用all关键字删除所有内容并不是真的完全删除所有内容。一些资源会被保留下来，并且需要被明确指定删除。&lt;/p>
&lt;p>删除资源时，kubectl将打印它删除的每个资源的名称。&lt;/p>
&lt;h4 id="注意-1">注意&lt;/h4>
&lt;p>&lt;code>kubectl delete all --all&lt;/code> 命令也会删除名为kubernetes的Service，但它应该会在几分钟后自动重新创建。&lt;/p>
&lt;h2 id="kubectl-命令演示">kubectl 命令演示&lt;/h2>
&lt;h3 id="kubectl-展示搜索出的pod列表含pod所在的namespace">kubectl 展示搜索出的pod列表（含pod所在的namespace）&lt;/h3>
&lt;div class="highlight">&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;">&lt;code class="language-bash" data-lang="bash">&lt;span style="display:flex;">&lt;span>kubectl get pod -A |grep &amp;lt;podname&amp;gt;
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#f92672">[&lt;/span>root@node ~&lt;span style="color:#f92672">]&lt;/span>&lt;span style="color:#75715e"># kubectl get pod -A |grep dashboard&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>kubernetes-dashboard dashboard-metrics-scraper-5657497c4c-j5kr8 1/1 Running &lt;span style="color:#ae81ff">0&lt;/span> 113m
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>kubernetes-dashboard kubernetes-dashboard-78f87ddfc-tlmjv 1/1 Running &lt;span style="color:#ae81ff">0&lt;/span> 113m
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>&lt;h3 id="kubectl-删除pod命令">kubectl 删除pod命令&lt;/h3>
&lt;div class="highlight">&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;">&lt;code class="language-bash" data-lang="bash">&lt;span style="display:flex;">&lt;span>kubectl delete pod &amp;lt;podname&amp;gt; -n &amp;lt;namespace&amp;gt;
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>&lt;p>在进行删除pod命令时，会发现pod并未被真正删除，原因是k8s误认为我们要删除的pod异常挂了，会启用容灾机制，导致重新在拉起一个新的pod。
故，我们想要正常且彻底的删除一个pod，必须要先破坏掉他的容灾机制，即删除deployment机制。&lt;/p>
&lt;h3 id="查看deployment信息">查看deployment信息&lt;/h3>
&lt;div class="highlight">&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;">&lt;code class="language-bash" data-lang="bash">&lt;span style="display:flex;">&lt;span>kubectl get deployment -n &amp;lt;namespace&amp;gt;
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#f92672">[&lt;/span>root@debian ~&lt;span style="color:#f92672">]&lt;/span>&lt;span style="color:#75715e"># kubectl get deployment --all-namespaces&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>NAMESPACE NAME READY UP-TO-DATE AVAILABLE AGE
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>kube-system coredns 2/2 &lt;span style="color:#ae81ff">2&lt;/span> &lt;span style="color:#ae81ff">2&lt;/span> 4h7m
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>kubernetes-dashboard dashboard-metrics-scraper 1/1 &lt;span style="color:#ae81ff">1&lt;/span> &lt;span style="color:#ae81ff">1&lt;/span> 117m
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>kubernetes-dashboard kubernetes-dashboard 1/1 &lt;span style="color:#ae81ff">1&lt;/span> &lt;span style="color:#ae81ff">1&lt;/span> 117m
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>&lt;h3 id="删除deployment配置">删除deployment配置&lt;/h3>
&lt;div class="highlight">&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;">&lt;code class="language-bash" data-lang="bash">&lt;span style="display:flex;">&lt;span>kubectl delete deployment &amp;lt;deployment名&amp;gt; -n &amp;lt;namespace&amp;gt;
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#f92672">[&lt;/span>root@node ~&lt;span style="color:#f92672">]&lt;/span>&lt;span style="color:#75715e"># kubectl delete deployment kubernetes-dashboard -n kubernetes-dashboard&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>deployment.apps &lt;span style="color:#e6db74">&amp;#34;kubernetes-dashboard&amp;#34;&lt;/span> deleted
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#f92672">[&lt;/span>root@node ~&lt;span style="color:#f92672">]&lt;/span>&lt;span style="color:#75715e"># kubectl delete deployment dashboard-metrics-scraper -n kubernetes-dashboard&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>deployment.apps &lt;span style="color:#e6db74">&amp;#34;dashboard-metrics-scraper&amp;#34;&lt;/span> deleted
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>&lt;h3 id="然后进行删除pod命令即可我删除deployment后再次查询pod发现上面的pod已经开始自行删除了这步可酌情处理">然后进行删除pod命令即可，我删除deployment后，再次查询pod发现，上面的pod已经开始自行删除了（这步可酌情处理）&lt;/h3>
&lt;div class="highlight">&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;">&lt;code class="language-bash" data-lang="bash">&lt;span style="display:flex;">&lt;span>kubectl delete pod &amp;lt;podname&amp;gt; -n &amp;lt;namespace&amp;gt;
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#f92672">[&lt;/span>root@node ~&lt;span style="color:#f92672">]&lt;/span>&lt;span style="color:#75715e"># delete pod dashboard-metrics-scraper-5657497c4c-j5kr8 -n kubernetes-dashboard&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>pod &lt;span style="color:#e6db74">&amp;#34;dashboard-metrics-scraper-5657497c4c-j5kr8&amp;#34;&lt;/span> deleted
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#75715e"># 附一个我这边删除deployment后pod自行删除的情况&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#f92672">[&lt;/span>root@node ~&lt;span style="color:#f92672">]&lt;/span>&lt;span style="color:#75715e"># kubectl get pod -A|grep dashboard&lt;/span>
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div></description></item><item><title>Docker的 privileged 选项解析（特权模式：赋予容器几乎与主机相同的权限）</title><link>https://blog.baicai.me/article/2023/docker_privileged/</link><pubDate>Fri, 17 Nov 2023 22:52:38 +0800</pubDate><author>admin@baicai.me (白菜)</author><guid>https://blog.baicai.me/article/2023/docker_privileged/</guid><description>&lt;h3 id="runtime-privilege-and-linux-capabilities">Runtime privilege and Linux capabilities&lt;/h3>
&lt;p>参考官方文档：&lt;a href="https://docs.docker.com/engine/reference/run/#runtime-privilege-and-linux-capabilities">Docker run reference&lt;/a>&lt;/p>
&lt;p>By default, Docker containers are &amp;ldquo;unprivileged&amp;rdquo; and cannot, for example, run a Docker daemon inside a Docker container. This is because by default a container is not allowed to access any devices, but a &amp;ldquo;privileged&amp;rdquo; container is given access to all devices (see the documentation on cgroups devices).&lt;/p>
&lt;p>The &amp;ndash;privileged flag gives all capabilities to the container. When the operator executes docker run &amp;ndash;privileged, Docker will enable access to all devices on the host as well as set some configuration in AppArmor or SELinux to allow the container nearly all the same access to the host as processes running outside containers on the host. Additional information about running with &amp;ndash;privileged is available on the &lt;a href="https://www.docker.com/blog/docker-can-now-run-within-docker/">Docker Blog&lt;/a>.&lt;/p>
&lt;h2 id="docker-容器的安全性">Docker 容器的安全性&lt;/h2>
&lt;h3 id="linux-namespace-和-capabilities">Linux Namespace 和 Capabilities&lt;/h3>
&lt;p>Docker使用Linux namespace和capabilities来实现容器隔离和限制权限。&lt;/p>
&lt;pre>&lt;code>Linux Namespace：Docker利用namespace技术，使得每个容器都有其自己的进程、网络、挂载、用户ID等独立的空间。这保证了容器与容器之间以及容器与主机之间的隔离性。
Capabilities：Linux capabilities允许将传统的root权限分割成多个不同的能力，例如CAP_NET_ADMIN能力允许操作网络配置，CAP_CHOWN能力允许改变文件所有权。Docker默认情况下会赋予容器一些必要的capabilities，但不包括全部的能力，从而降低了被攻击的风险。
&lt;/code>&lt;/pre>
&lt;p>Docker 通过 &amp;ndash;cap-add 和 &amp;ndash;cap-drop 两个参数，可以灵活地添加或删除容器的 capabilities。&lt;/p>
&lt;div class="highlight">&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;">&lt;code class="language-bash" data-lang="bash">&lt;span style="display:flex;">&lt;span>docker run --cap-add&lt;span style="color:#f92672">=&lt;/span>SYS_PTRACE --rm -it alpine
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>&lt;p>上面 &lt;code>--cap-add=SYS_PTRACE&lt;/code> 的意思就是：给容器添加 SYS_PTRACE 权限，允许容器内的进程可以 ptrace 和 debug 其他进程。&lt;/p>
&lt;h3 id="docker限制和权限">Docker限制和权限&lt;/h3>
&lt;p>在默认情况下，Docker对容器的权限进行了严格的限制，只提供了有限的capabilities。此外，许多系统级别的操作（例如挂载文件系统、修改内核参数等）都是被禁止的。这种安全模型使得Docker可以在不牺牲安全性的前提下，实现轻量级的虚拟化。&lt;/p>
&lt;p>然而，在某些情况下，我们可能需要赋予容器更多的权限。例如，如果我们需要在容器中运行一些需要特权的服务（如网络设备管理、硬件设备接口等），那么默认的权限可能就不够用了。这时候，&lt;code>--privileged=true&lt;/code> 选项就派上了用场。&lt;/p>
&lt;h4 id="docker的privilegedtrue选项">Docker的–privileged=true选项&lt;/h4>
&lt;p>当使用&amp;ndash;privileged=true选项运行容器时，Docker会赋予容器几乎与主机相同的权限。
具体来说，这个选项做了以下两件事情：&lt;/p>
&lt;pre tabindex="0">&lt;code> 给容器添加了所有的capabilities
允许容器访问主机的所有设备
&lt;/code>&lt;/pre>&lt;h4 id="privilegedtrue的风险">&amp;ndash;privileged=true的风险&lt;/h4>
&lt;p>尽管 &lt;code>--privileged=true&lt;/code> 选项为容器提供了强大的功能，但它也带来了一些严重的安全隐患。由于privileged容器具有几乎与主机相同的权限，所以如果容器被恶意代码控制，那么攻击者就可以轻易地突破容器的边界，对主机进行任意操作。&lt;/p>
&lt;p>因此，我们需要谨慎地使用 &lt;code>--privileged=true&lt;/code> 选项，只在真正需要的情况下才启用它。在可能的情况下，我们应该尽量使用其他更细粒度的权限控制手段，例如通过&lt;code>--cap-add&lt;/code>或&lt;code>--device&lt;/code>参数来分别添加必要的capabilities或设备访问权限。&lt;/p>
&lt;h4 id="细粒度的权限控制手段">细粒度的权限控制手段&lt;/h4>
&lt;div class="highlight">&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;">&lt;code class="language-bash" data-lang="bash">&lt;span style="display:flex;">&lt;span>&lt;span style="color:#75715e"># 添加单个capability&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>docker run --rm --cap-add NET_ADMIN -it alpine sh
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#75715e"># 添加设备访问权限&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>docker run --device&lt;span style="color:#f92672">=&lt;/span>/dev/sda:/dev/xvdc -it alpine
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>&lt;h4 id="docker-compose-参考">docker-compose 参考&lt;/h4>
&lt;div class="highlight">&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;">&lt;code class="language-yaml" data-lang="yaml">&lt;span style="display:flex;">&lt;span>&lt;span style="color:#f92672">version&lt;/span>: &lt;span style="color:#e6db74">&amp;#34;3&amp;#34;&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#f92672">services&lt;/span>:
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#f92672">baicai_image&lt;/span>:
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#f92672">image&lt;/span>: &lt;span style="color:#ae81ff">debian&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#f92672">container_name&lt;/span>: &lt;span style="color:#e6db74">&amp;#34;baicai_image&amp;#34;&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#f92672">restart&lt;/span>: &lt;span style="color:#ae81ff">unless-stopped&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#f92672">command&lt;/span>: &lt;span style="color:#ae81ff">run -c /app/config.json&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#f92672">volumes&lt;/span>:
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> - &lt;span style="color:#ae81ff">./config.json:/app/config.json&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#f92672">environment&lt;/span>:
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#f92672">TZ&lt;/span>: &lt;span style="color:#ae81ff">Asia/Shanghai&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#f92672">ports&lt;/span>:
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> - &lt;span style="color:#e6db74">&amp;#34;80:80&amp;#34;&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#f92672">privileged&lt;/span>: &lt;span style="color:#66d9ef">false&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#f92672">cap_add&lt;/span>:
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> - &lt;span style="color:#ae81ff">NET_ADMIN&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> - &lt;span style="color:#ae81ff">SYS_MODULE&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> - &lt;span style="color:#ae81ff">SYS_PTRACE&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> - &lt;span style="color:#ae81ff">SYS_ADMIN&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> - &lt;span style="color:#ae81ff">NET_RAW&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#f92672">cap_drop&lt;/span>:
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> - &lt;span style="color:#ae81ff">ALL&lt;/span>
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>&lt;h3 id="附注-在docker-debian容器中安装pstop等命令">附注: 在Docker Debian容器中安装ps、top等命令&lt;/h3>
&lt;p>debian镜像默认没有包括进程管理相关工具，在实际使用时可能有些麻烦，如果需要也可以自己安装，使用如下命令。&lt;/p>
&lt;div class="highlight">&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;">&lt;code class="language-bash" data-lang="bash">&lt;span style="display:flex;">&lt;span>apt update &lt;span style="color:#f92672">&amp;amp;&amp;amp;&lt;/span> apt install -y procps
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div></description></item><item><title>Debian 彻底卸载 LibreOffice</title><link>https://blog.baicai.me/article/2023/debian_remove_libreoffice/</link><pubDate>Mon, 09 Oct 2023 10:15:40 +0800</pubDate><author>admin@baicai.me (白菜)</author><guid>https://blog.baicai.me/article/2023/debian_remove_libreoffice/</guid><description>&lt;p>LibreOffice是一款非常优秀的开源且免费的办公软件。但我用不到，为了优化更新系统的速度，所以这就卸载了，这不就几条命令的事。&lt;/p>
&lt;p>下面的指令对所有基于 Debian 发行版（Debian, Ubuntu, Kubuntu, Xubuntu, buntu, Sidux, Knoppix, Linux Mint, Damn Small Linux, Crunchbag 等）都适用。&lt;/p>
&lt;h3 id="彻底卸载-libreoffice">彻底卸载 LibreOffice&lt;/h3>
&lt;p>终端中输入命令：&lt;/p>
&lt;div class="highlight">&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;">&lt;code class="language-bash" data-lang="bash">&lt;span style="display:flex;">&lt;span>&lt;span style="color:#75715e">#不要漏掉通配符“?”，否则无法清除/卸载全部 LibreOffice 软件包&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>sudo apt-get purge libreoffice?
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>&lt;p>或&lt;/p>
&lt;div class="highlight">&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;">&lt;code class="language-bash" data-lang="bash">&lt;span style="display:flex;">&lt;span>&lt;span style="color:#75715e">#不要漏掉通配符“?”，否则无法清除/卸载全部 LibreOffice 软件包&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>sudo aptitude purge libreoffice?
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>&lt;p>或&lt;/p>
&lt;div class="highlight">&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;">&lt;code class="language-bash" data-lang="bash">&lt;span style="display:flex;">&lt;span>&lt;span style="color:#75715e">#不要漏掉通配符“*”，否则无法清除/卸载全部 LibreOffice 软件包&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>sudo apt-get remove --purge libreoffice*
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>&lt;p>然后清理残留：&lt;/p>
&lt;div class="highlight">&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;">&lt;code class="language-bash" data-lang="bash">&lt;span style="display:flex;">&lt;span>sudo apt-get clean
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>sudo apt-get autoremove
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>&lt;h3 id="附注不完全卸载">附注（不完全卸载）：&lt;/h3>
&lt;p>卸载libreoffice表格&lt;/p>
&lt;div class="highlight">&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;">&lt;code class="language-bash" data-lang="bash">&lt;span style="display:flex;">&lt;span>sudo apt remove libreoffice-calc
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>&lt;p>卸载libreoffice绘图&lt;/p>
&lt;div class="highlight">&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;">&lt;code class="language-bash" data-lang="bash">&lt;span style="display:flex;">&lt;span>sudo apt remove libreoffice-draw
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>&lt;p>卸载libreoffice幻灯片&lt;/p>
&lt;div class="highlight">&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;">&lt;code class="language-bash" data-lang="bash">&lt;span style="display:flex;">&lt;span>sudo apt remove libreoffice-impress
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>&lt;p>卸载libreoffice word文档工具&lt;/p>
&lt;div class="highlight">&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;">&lt;code class="language-bash" data-lang="bash">&lt;span style="display:flex;">&lt;span>sudo apt remove libreoffice-writer
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>&lt;p>清理残留&lt;/p>
&lt;div class="highlight">&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;">&lt;code class="language-bash" data-lang="bash">&lt;span style="display:flex;">&lt;span>sudo apt autoremove
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>&lt;h3 id="libreoffice简介来自官网">LibreOffice简介（来自官网）：&lt;/h3>
&lt;p>LibreOffice 是一款功能强大的办公软件，默认使用开放文档格式 (OpenDocument Format , ODF), 并支持 *.docx, *.xlsx, *.pptx 等其他格式。&lt;/p>
&lt;p>它包含了 Writer, Calc, Impress, Draw, Base 以及 Math 等组件，可用于处理文本文档、电子表格、演示文稿、绘图以及公式编辑。&lt;/p>
&lt;p>它可以运行于 Windows, GNU/Linux 以及 macOS 等操作系统上，并具有一致的用户体验。&lt;/p></description></item><item><title>通过 WireGuard 搭建 VPN 访问家里内网</title><link>https://blog.baicai.me/article/2023/using_wireguard/</link><pubDate>Sun, 08 Oct 2023 15:19:08 +0800</pubDate><author>admin@baicai.me (白菜)</author><guid>https://blog.baicai.me/article/2023/using_wireguard/</guid><description>&lt;p>家里网络没有公网 IP，因此需要一台具有公网 IP 的服务器作为 WireGuard 网络的“server”。家中需要有一台设备作为 WireGuard 网络中的节点。我们将使用手机，在 4G 网络下检查 VPN 是否搭建成功。&lt;/p>
&lt;h2 id="ip-段选择">IP 段选择&lt;/h2>
&lt;p>WireGuard 组网需要使用一个不与你的任何设备的网络相冲突的 IP 地址段。像 192.0.2.0/24 、198.51.100.0/24 、203.0.113.0/24 这些分配为用于文档和示例中的“TEST-NET”，这些地址段通常不会被你需要连接的其他网络所使用。&lt;/p>
&lt;p>在下面的配置中，我会分别将 192.0.2.1、192.0.2.2、192.0.2.3 分配给公网服务器、家中的 Mac 和 iPhone。&lt;/p>
&lt;h2 id="在服务器上配置-wireguard">在服务器上配置 WireGuard&lt;/h2>
&lt;p>要使用 WireGuard，首先需要确保 Linux 内核支持。可使用 &lt;code>modinfo wireguard&lt;/code> 命令检查是否内置了 WireGuard。也可用过 &lt;code>uname -r&lt;/code> 检查内核版本是否为 5.6 以上。&lt;/p>
&lt;h3 id="安装-wireguard">安装 wireguard&lt;/h3>
&lt;p>Debian&lt;/p>
&lt;pre tabindex="0">&lt;code>apt install wireguard
&lt;/code>&lt;/pre>&lt;p>其他系统参考：&lt;a href="https://www.wireguard.com/install/">install&lt;/a>&lt;/p>
&lt;h3 id="完成服务器端的配置">完成服务器端的配置&lt;/h3>
&lt;p>在正确安装 wireguard 后，你可以通过如下命令快速创建一组公钥和私钥。&lt;/p>
&lt;pre tabindex="0">&lt;code>$ wg genkey | tee peer_A.key | wg pubkey &amp;gt; peer_A.pub &amp;amp;&amp;amp; cat peer_A.key &amp;amp;&amp;amp; cat peer_A.pub
&lt;/code>&lt;/pre>&lt;p>创建 &lt;code>/etc/wireguard/wg0.conf&lt;/code> 并填配置&lt;/p>
&lt;div class="highlight">&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;">&lt;code class="language-ini" data-lang="ini">&lt;span style="display:flex;">&lt;span>&lt;span style="color:#66d9ef">[Interface]&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#a6e22e">PrivateKey&lt;/span> &lt;span style="color:#f92672">=&lt;/span> &lt;span style="color:#e6db74">(your server private key here)&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#a6e22e">Address&lt;/span> &lt;span style="color:#f92672">=&lt;/span> &lt;span style="color:#e6db74">192.0.2.1/24&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#a6e22e">ListenPort&lt;/span> &lt;span style="color:#f92672">=&lt;/span> &lt;span style="color:#e6db74">51820&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#75715e">#PreUp = echo WireGuard PreUp&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#75715e">#PostUp = iptables -A FORWARD -i wg0 -j ACCEPT; iptables -t nat -A POSTROUTING -o eth0 -j MASQUERADE; ip6tables -A FORWARD -i wg0 -j ACCEPT; ip6tables -t nat -A POSTROUTING -o eth0 -j MASQUERADE&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#75715e">#PostDown = iptables -D FORWARD -i wg0 -j ACCEPT; iptables -t nat -D POSTROUTING -o eth0 -j MASQUERADE; ip6tables -D FORWARD -i wg0 -j ACCEPT; ip6tables -t nat -D POSTROUTING -o eth0 -j MASQUERADE&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#75715e">#PostUp = iptables -I INPUT -p udp --dport 51820 -j ACCEPT&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#75715e">#PostDown = iptables -D INPUT -p udp --dport 51820 -j ACCEPT&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#75715e">#ipv4 局域网够用配置&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#a6e22e">PostUp&lt;/span> &lt;span style="color:#f92672">=&lt;/span> &lt;span style="color:#e6db74">iptables -A FORWARD -i wg0 -j ACCEPT&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#a6e22e">PostDown&lt;/span> &lt;span style="color:#f92672">=&lt;/span> &lt;span style="color:#e6db74">iptables -D FORWARD -i wg0 -j ACCEPT&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#75715e">#ipv4防火墙放行转发和NAT(访问公共网络)&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#75715e">#PostUp = iptables -A FORWARD -i wg0 -j ACCEPT; iptables -t nat -A POSTROUTING -o eth0 -j MASQUERADE&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#75715e">#PostDown = iptables -D FORWARD -i wg0 -j ACCEPT; iptables -t nat -D POSTROUTING -o eth0 -j MASQUERADE&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#75715e">#ipv4防火墙放行转发和NAT(访问公共网络) 扩展防火墙规则(节点之间双向互联)&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#75715e">#PostUp = iptables -I FORWARD -i wg0 -j ACCEPT; iptables -I FORWARD -o wg0 -j ACCEPT; iptables -I INPUT -i wg0 -j ACCEPT; iptables -t nat -A POSTROUTING -o eth0 -j MASQUERADE&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#75715e">#PostDown = iptables -D FORWARD -i wg0 -j ACCEPT; iptables -D FORWARD -o wg0 -j ACCEPT; iptables -D INPUT -i wg0 -j ACCEPT; iptables -t nat -D POSTROUTING -o eth0 -j MASQUERADE&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#75715e">#PreDown = echo WireGuard PreDown&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#66d9ef">[Peer]&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#75715e"># Mac at home&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#a6e22e">PublicKey&lt;/span> &lt;span style="color:#f92672">=&lt;/span> &lt;span style="color:#e6db74">(Mac public key here)&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#a6e22e">AllowedIPs&lt;/span> &lt;span style="color:#f92672">=&lt;/span> &lt;span style="color:#e6db74">192.0.2.2/32, 192.168.1.0/24&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#66d9ef">[Peer]&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#75715e"># iPhone&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#a6e22e">PublicKey&lt;/span> &lt;span style="color:#f92672">=&lt;/span> &lt;span style="color:#e6db74">(iPhone public key here)&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#a6e22e">AllowedIPs&lt;/span> &lt;span style="color:#f92672">=&lt;/span> &lt;span style="color:#e6db74">192.0.2.3/32&lt;/span>
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>&lt;p>在 WireGuard 中，你需要手动给各个设备分配 IP，并确保每个设备都有唯一的 IP。Interface 包含了当前设备的设置，对于“服务端”来说，ListenPort 是必须的。下面的每一个 Peer 段代表了能连接到本设备的一个其他设备。&lt;/p>
&lt;p>配置文件保存后，我们可以使用 &lt;code>wg-quick up wg0&lt;/code> 来启用配置文件。wg-quick 会自动配置路由表，无需我们手动设置。&lt;/p>
&lt;p>记得放行 51820 UDP 端口。&lt;/p>
&lt;p>&lt;a href="https://blog.baicai.me/article/2023/oracle_vps_iptables/">iptables 配置参考&lt;/a>&lt;/p>
&lt;h2 id="家中mac端的配置">家中Mac端的配置&lt;/h2>
&lt;p>创建 &lt;code>/etc/wireguard/wg0.conf&lt;/code> 并填配置&lt;/p>
&lt;div class="highlight">&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;">&lt;code class="language-ini" data-lang="ini">&lt;span style="display:flex;">&lt;span>&lt;span style="color:#66d9ef">[Interface]&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#a6e22e">PrivateKey&lt;/span> &lt;span style="color:#f92672">=&lt;/span> &lt;span style="color:#e6db74">(private key of Mac)&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#a6e22e">Address&lt;/span> &lt;span style="color:#f92672">=&lt;/span> &lt;span style="color:#e6db74">192.0.2.2/24&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#a6e22e">DNS&lt;/span> &lt;span style="color:#f92672">=&lt;/span> &lt;span style="color:#e6db74">1.1.1.1&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#66d9ef">[Peer]&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#a6e22e">PublicKey&lt;/span> &lt;span style="color:#f92672">=&lt;/span> &lt;span style="color:#e6db74">(public key of server)&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#a6e22e">AllowedIPs&lt;/span> &lt;span style="color:#f92672">=&lt;/span> &lt;span style="color:#e6db74">192.0.2.0/24&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#a6e22e">Endpoint&lt;/span> &lt;span style="color:#f92672">=&lt;/span> &lt;span style="color:#e6db74">(server ip address):51820&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#a6e22e">PersistentKeepalive&lt;/span> &lt;span style="color:#f92672">=&lt;/span> &lt;span style="color:#e6db74">10&lt;/span>
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>&lt;p>在这里，我们将公网服务器作为唯一的 Peer，通过设置 PersistentKeepalive 来进行连接的保活。这里 AllowedIPs 的作用是确保来自于我们 WireGuard 子网网段来的流量能被本机的 WireGuard 虚拟网卡进行处理。&lt;/p>
&lt;h2 id="iphone-配置">iphone 配置&lt;/h2>
&lt;p>安装 WireGuard &lt;a href="https://itunes.apple.com/us/app/wireguard/id1441195209?ls=1&amp;amp;mt=8"> Download from App Store&lt;/a>&lt;/p>
&lt;p>这个配置可以参考应用商店的截屏。&lt;/p>
&lt;h2 id="设置开机启动">设置开机启动&lt;/h2>
&lt;p>如果你的系统使用systemd,如ubuntu，设置wireguard开机启动命令如下&lt;/p>
&lt;div class="highlight">&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;">&lt;code class="language-bash" data-lang="bash">&lt;span style="display:flex;">&lt;span>systemctl enable wg-quick@wg0
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>&lt;h2 id="启用服务器peer端转发">启用服务器Peer端转发&lt;/h2>
&lt;p>打开 &lt;code>/etc/sysctl.conf&lt;/code> 修改&lt;/p>
&lt;pre tabindex="0">&lt;code class="language-conf" data-lang="conf">net.ipv4.ip_forward=1
net.ipv6.conf.all.forwarding=1
&lt;/code>&lt;/pre>&lt;p>或&lt;/p>
&lt;div class="highlight">&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;">&lt;code class="language-bash" data-lang="bash">&lt;span style="display:flex;">&lt;span>echo &lt;span style="color:#e6db74">&amp;#39;net.ipv4.ip_forward=1&amp;#39;&lt;/span> &amp;gt;&amp;gt; /etc/sysctl.conf
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>echo &lt;span style="color:#e6db74">&amp;#39;net.ipv6.conf.all.forwarding=1&amp;#39;&lt;/span> &amp;gt;&amp;gt; /etc/sysctl.conf
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>sysctl -p
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>&lt;h2 id="附注">附注&lt;/h2>
&lt;h3 id="保留地址段">保留地址段&lt;/h3>
&lt;p>&lt;a href="https://zh.wikipedia.org/wiki/%E4%BF%9D%E7%95%99IP%E5%9C%B0%E5%9D%80">保留IP地址&lt;/a>&lt;/p>
&lt;h3 id="小插曲">小插曲&lt;/h3>
&lt;p>当遇到错误提示：&lt;/p>
&lt;pre tabindex="0">&lt;code>/usr/bin/wg-quick: line 31: resolvconf: command not found [WireGuard | Debian]
&lt;/code>&lt;/pre>&lt;p>可以创建软链接解决&lt;/p>
&lt;div class="highlight">&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;">&lt;code class="language-bash" data-lang="bash">&lt;span style="display:flex;">&lt;span>ln -s /usr/bin/resolvectl /usr/local/bin/resolvconf
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>&lt;p>当遇到错误提示：&lt;/p>
&lt;pre tabindex="0">&lt;code>[SELF-SOLVED] Unit dbus-org.freedesktop.resolve1.service not found
&lt;/code>&lt;/pre>&lt;p>可以通过启动 systemd-resolved 服务解决&lt;/p>
&lt;div class="highlight">&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;">&lt;code class="language-bash" data-lang="bash">&lt;span style="display:flex;">&lt;span>systemctl start systemd-resolved.service
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>systemctl enable systemd-resolved.service
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>&lt;h3 id="配置详解">配置详解&lt;/h3>
&lt;p>WireGuard 使用 INI 语法作为其配置文件格式。配置文件可以放在任何路径下，但必须通过绝对路径引用。默认路径是 &lt;code>/etc/wireguard/wg0.conf&lt;/code>。&lt;/p>
&lt;p>配置文件的命名形式必须为 &lt;code>${WireGuard 接口的名称}.conf&lt;/code>。通常情况下 WireGuard 接口名称以 &lt;code>wg&lt;/code> 为前缀，并从 &lt;code>0&lt;/code> 开始编号，但你也可以使用其他名称，只要符合正则表达式 &lt;code>^[a-zA-Z0-9_=+.-]{1,15}$&lt;/code> 就行。&lt;/p>
&lt;p>你可以选择使用 &lt;code>wg&lt;/code> 命令来手动配置 VPN，但一般建议使用 &lt;code>wg-quick&lt;/code>，它提供了更强大和用户友好的配置体验，可以通过配置文件来管理配置。&lt;/p>
&lt;h4 id="interface">[Interface]&lt;/h4>
&lt;p>定义本地 VPN 配置。例如：&lt;/p>
&lt;p>1.本地节点是客户端，只路由自身的流量，只暴露一个 IP。&lt;/p>
&lt;div class="highlight">&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;">&lt;code class="language-ini" data-lang="ini">&lt;span style="display:flex;">&lt;span>&lt;span style="color:#66d9ef">[Interface]&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#75715e"># Name = phone.example-vpn.dev&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#a6e22e">Address&lt;/span> &lt;span style="color:#f92672">=&lt;/span> &lt;span style="color:#e6db74">192.0.2.5/32&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#a6e22e">PrivateKey&lt;/span> &lt;span style="color:#f92672">=&lt;/span> &lt;span style="color:#e6db74">&amp;lt;private key for phone.example-vpn.dev&amp;gt;&lt;/span>
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>&lt;p>本地节点是中继服务器，它可以将流量转发到其他对等节点（peer），并公开整个 VPN 子网的路由。&lt;/p>
&lt;div class="highlight">&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;">&lt;code class="language-ini" data-lang="ini">&lt;span style="display:flex;">&lt;span>&lt;span style="color:#66d9ef">[Interface]&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#75715e"># Name = public-server1.example-vpn.tld&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#a6e22e">Address&lt;/span> &lt;span style="color:#f92672">=&lt;/span> &lt;span style="color:#e6db74">192.0.2.1/24&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#a6e22e">ListenPort&lt;/span> &lt;span style="color:#f92672">=&lt;/span> &lt;span style="color:#e6db74">51820&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#a6e22e">PrivateKey&lt;/span> &lt;span style="color:#f92672">=&lt;/span> &lt;span style="color:#e6db74">&amp;lt;private key for public-server1.example-vpn.tld&amp;gt;&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#a6e22e">DNS&lt;/span> &lt;span style="color:#f92672">=&lt;/span> &lt;span style="color:#e6db74">1.1.1.1&lt;/span>
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>&lt;h4 id="-name"># Name&lt;/h4>
&lt;p>这是 INI 语法中的标准注释，用于展示该配置部分属于哪个节点。这部分配置会被 WireGuard 完全忽略，对 VPN 的行为没有任何影响。&lt;/p>
&lt;h4 id="address">Address&lt;/h4>
&lt;p>定义本地节点应该对哪个地址范围进行路由。如果是常规的客户端，则将其设置为节点本身的单个 IP（使用 CIDR 指定，例如 192.0.2.3/32）；如果是中继服务器，则将其设置为可路由的子网范围。
例如：&lt;/p>
&lt;p>常规客户端，只路由自身的流量：&lt;/p>
&lt;div class="highlight">&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;">&lt;code class="language-ini" data-lang="ini">&lt;span style="display:flex;">&lt;span>&lt;span style="color:#a6e22e">Address&lt;/span> &lt;span style="color:#f92672">=&lt;/span> &lt;span style="color:#e6db74">192.0.2.3/32&lt;/span>
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>&lt;p>中继服务器，可以将流量转发到其他对等节点（peer）：&lt;/p>
&lt;div class="highlight">&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;">&lt;code class="language-ini" data-lang="ini">&lt;span style="display:flex;">&lt;span>&lt;span style="color:#a6e22e">Address&lt;/span> &lt;span style="color:#f92672">=&lt;/span> &lt;span style="color:#e6db74">192.0.2.1/24&lt;/span>
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>&lt;p>也可以指定多个子网或 IPv6 子网：&lt;/p>
&lt;div class="highlight">&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;">&lt;code class="language-ini" data-lang="ini">&lt;span style="display:flex;">&lt;span>&lt;span style="color:#a6e22e">Address&lt;/span> &lt;span style="color:#f92672">=&lt;/span> &lt;span style="color:#e6db74">192.0.2.1/24,2001:DB8::/64&lt;/span>
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>&lt;h4 id="listenport">ListenPort&lt;/h4>
&lt;p>当本地节点是中继服务器时，需要通过该参数指定端口来监听传入 VPN 连接，默认端口号是 51820。常规客户端不需要此选项。&lt;/p>
&lt;h4 id="privatekey">PrivateKey&lt;/h4>
&lt;p>本地节点的私钥，所有节点（包括中继服务器）都必须设置。不可与其他服务器共用。&lt;/p>
&lt;p>私钥可通过命令 &lt;code>wg genkey &amp;gt; example.key&lt;/code> 来生成。&lt;/p>
&lt;h4 id="dns">DNS&lt;/h4>
&lt;p>通过 DHCP 向客户端宣告 DNS 服务器。客户端将会使用这里指定的 DNS 服务器来处理 VPN 子网中的 DNS 请求，但也可以在系统中覆盖此选项。例如：&lt;/p>
&lt;div class="highlight">&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;">&lt;code class="language-ini" data-lang="ini">&lt;span style="display:flex;">&lt;span>&lt;span style="color:#75715e">#如果不配置则使用系统默认 DNS&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#75715e">#可以指定单个 DNS：&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#a6e22e">DNS&lt;/span> &lt;span style="color:#f92672">=&lt;/span> &lt;span style="color:#e6db74">1.1.1.1&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#75715e">#也可以指定多个 DNS：&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#a6e22e">DNS&lt;/span> &lt;span style="color:#f92672">=&lt;/span> &lt;span style="color:#e6db74">1.1.1.1,8.8.8.8&lt;/span>
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>&lt;h4 id="table">Table&lt;/h4>
&lt;p>定义 VPN 子网使用的路由表，默认不需要设置。该参数有两个特殊的值需要注意：&lt;/p>
&lt;div class="highlight">&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;">&lt;code class="language-ini" data-lang="ini">&lt;span style="display:flex;">&lt;span> &lt;span style="color:#a6e22e">Table&lt;/span> &lt;span style="color:#f92672">=&lt;/span> &lt;span style="color:#e6db74">off : 禁止创建路由
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#e6db74"> Table = auto（默认值） : 将路由添加到系统默认的 table 中，并启用对默认路由的特殊处理。&lt;/span>
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>&lt;p>例如：&lt;code>Table = 1234&lt;/code>&lt;/p>
&lt;h4 id="mtu">MTU&lt;/h4>
&lt;p>定义连接到对等节点（peer）的 MTU（Maximum Transmission Unit，最大传输单元），默认不需要设置，一般由系统自动确定。&lt;/p>
&lt;h4 id="preup">PreUp&lt;/h4>
&lt;p>启动 VPN 接口之前运行的命令。这个选项可以指定多次，按顺序执行。&lt;/p>
&lt;p>例如：
添加路由：&lt;/p>
&lt;div class="highlight">&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;">&lt;code class="language-ini" data-lang="ini">&lt;span style="display:flex;">&lt;span> &lt;span style="color:#a6e22e">PreUp&lt;/span> &lt;span style="color:#f92672">=&lt;/span> &lt;span style="color:#e6db74">ip rule add ipproto tcp dport 22 table 1234&lt;/span>
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>&lt;h4 id="postup">PostUp&lt;/h4>
&lt;p>启动 VPN 接口之后运行的命令。这个选项可以指定多次，按顺序执行。&lt;/p>
&lt;p>例如：&lt;/p>
&lt;pre>&lt;code>从文件或某个命令的输出中读取配置值：
&lt;/code>&lt;/pre>
&lt;div class="highlight">&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;">&lt;code class="language-ini" data-lang="ini">&lt;span style="display:flex;">&lt;span> &lt;span style="color:#a6e22e">PostUp&lt;/span> &lt;span style="color:#f92672">=&lt;/span> &lt;span style="color:#e6db74">wg set %i private-key /etc/wireguard/wg0.key &amp;lt;(some command here)&lt;/span>
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>&lt;pre>&lt;code>添加一行日志到文件中：
&lt;/code>&lt;/pre>
&lt;div class="highlight">&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;">&lt;code class="language-ini" data-lang="ini">&lt;span style="display:flex;">&lt;span> &lt;span style="color:#a6e22e">PostUp&lt;/span> &lt;span style="color:#f92672">=&lt;/span> &lt;span style="color:#e6db74">echo &amp;#34;$(date +%s) WireGuard Started&amp;#34; &amp;gt;&amp;gt; /var/log/wireguard.log&lt;/span>
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>&lt;pre>&lt;code>调用 WebHook：
&lt;/code>&lt;/pre>
&lt;div class="highlight">&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;">&lt;code class="language-ini" data-lang="ini">&lt;span style="display:flex;">&lt;span> &lt;span style="color:#a6e22e">PostUp&lt;/span> &lt;span style="color:#f92672">=&lt;/span> &lt;span style="color:#e6db74">curl https://events.example.dev/wireguard/started&lt;/span>
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>&lt;pre>&lt;code>添加路由：
&lt;/code>&lt;/pre>
&lt;div class="highlight">&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;">&lt;code class="language-ini" data-lang="ini">&lt;span style="display:flex;">&lt;span> &lt;span style="color:#a6e22e">PostUp&lt;/span> &lt;span style="color:#f92672">=&lt;/span> &lt;span style="color:#e6db74">ip rule add ipproto tcp dport 22 table 1234&lt;/span>
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>&lt;pre>&lt;code>添加 iptables 规则，启用数据包转发：
&lt;/code>&lt;/pre>
&lt;div class="highlight">&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;">&lt;code class="language-ini" data-lang="ini">&lt;span style="display:flex;">&lt;span> &lt;span style="color:#a6e22e">PostUp&lt;/span> &lt;span style="color:#f92672">=&lt;/span> &lt;span style="color:#e6db74">iptables -A FORWARD -i %i -j ACCEPT; iptables -A FORWARD -o %i -j ACCEPT; iptables -t nat -A POSTROUTING -o eth0 -j MASQUERADE&lt;/span>
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>&lt;pre>&lt;code>强制 WireGuard 重新解析对端域名的 IP 地址：
&lt;/code>&lt;/pre>
&lt;div class="highlight">&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;">&lt;code class="language-ini" data-lang="ini">&lt;span style="display:flex;">&lt;span> &lt;span style="color:#a6e22e">PostUp&lt;/span> &lt;span style="color:#f92672">=&lt;/span> &lt;span style="color:#e6db74">resolvectl domain %i &amp;#34;~.&amp;#34;; resolvectl dns %i 192.0.2.1; resolvectl dnssec %i yes&lt;/span>
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>&lt;h4 id="predown">PreDown&lt;/h4>
&lt;p>停止 VPN 接口之前运行的命令。这个选项可以指定多次，按顺序执行。
例如：&lt;/p>
&lt;pre>&lt;code>添加一行日志到文件中：
&lt;/code>&lt;/pre>
&lt;div class="highlight">&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;">&lt;code class="language-ini" data-lang="ini">&lt;span style="display:flex;">&lt;span> &lt;span style="color:#a6e22e">PreDown&lt;/span> &lt;span style="color:#f92672">=&lt;/span> &lt;span style="color:#e6db74">echo &amp;#34;$(date +%s) WireGuard Going Down&amp;#34; &amp;gt;&amp;gt; /var/log/wireguard.log&lt;/span>
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>&lt;h4 id="postdown">PostDown&lt;/h4>
&lt;p>停止 VPN 接口之后运行的命令。这个选项可以指定多次，按顺序执行。
例如：&lt;/p>
&lt;pre>&lt;code>添加一行日志到文件中：
&lt;/code>&lt;/pre>
&lt;div class="highlight">&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;">&lt;code class="language-ini" data-lang="ini">&lt;span style="display:flex;">&lt;span>&lt;span style="color:#a6e22e">PostDown&lt;/span> &lt;span style="color:#f92672">=&lt;/span> &lt;span style="color:#e6db74">echo &amp;#34;$(date +%s) WireGuard Down&amp;#34; &amp;gt;&amp;gt; /var/log/wireguard.log&lt;/span>
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>&lt;h4 id="peer">[Peer]&lt;/h4>
&lt;p>定义能够为一个或多个地址路由流量的对等节点（peer）的 VPN 设置。对等节点（peer）可以是将流量转发到其他对等节点（peer）的中继服务器，也可以是通过公网或内网直连的客户端。&lt;/p>
&lt;p>中继服务器必须将所有的客户端定义为对等节点（peer），除了中继服务器之外，其他客户端都不能将位于 NAT 后面的节点定义为对等节点（peer），因为路由不可达。对于那些只为自己路由流量的客户端，只需将中继服务器作为对等节点（peer），以及其他需要直接访问的节点。&lt;/p>
&lt;p>配置示例：&lt;/p>
&lt;p>对等节点（peer）是路由可达的客户端，只为自己路由流量&lt;/p>
&lt;div class="highlight">&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;">&lt;code class="language-ini" data-lang="ini">&lt;span style="display:flex;">&lt;span>&lt;span style="color:#66d9ef">[Peer]&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#75715e"># Name = public-server2.example-vpn.dev&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#a6e22e">Endpoint&lt;/span> &lt;span style="color:#f92672">=&lt;/span> &lt;span style="color:#e6db74">public-server2.example-vpn.dev:51820&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#a6e22e">PublicKey&lt;/span> &lt;span style="color:#f92672">=&lt;/span> &lt;span style="color:#e6db74">&amp;lt;public key for public-server2.example-vpn.dev&amp;gt;&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#a6e22e">AllowedIPs&lt;/span> &lt;span style="color:#f92672">=&lt;/span> &lt;span style="color:#e6db74">192.0.2.2/32&lt;/span>
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>&lt;p>对等节点（peer）是位于 NAT 后面的客户端，只为自己路由流量&lt;/p>
&lt;div class="highlight">&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;">&lt;code class="language-ini" data-lang="ini">&lt;span style="display:flex;">&lt;span>&lt;span style="color:#66d9ef">[Peer]&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#75715e"># Name = home-server.example-vpn.dev&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#a6e22e">Endpoint&lt;/span> &lt;span style="color:#f92672">=&lt;/span> &lt;span style="color:#e6db74">home-server.example-vpn.dev:51820&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#a6e22e">PublicKey&lt;/span> &lt;span style="color:#f92672">=&lt;/span> &lt;span style="color:#e6db74">&amp;lt;public key for home-server.example-vpn.dev&amp;gt;&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#a6e22e">AllowedIPs&lt;/span> &lt;span style="color:#f92672">=&lt;/span> &lt;span style="color:#e6db74">192.0.2.3/32&lt;/span>
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>&lt;p>对等节点（peer）是中继服务器，用来将流量转发到其他对等节点（peer）&lt;/p>
&lt;div class="highlight">&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;">&lt;code class="language-ini" data-lang="ini">&lt;span style="display:flex;">&lt;span>&lt;span style="color:#66d9ef">[Peer]&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#75715e"># Name = public-server1.example-vpn.tld&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#a6e22e">Endpoint&lt;/span> &lt;span style="color:#f92672">=&lt;/span> &lt;span style="color:#e6db74">public-server1.example-vpn.tld:51820&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#a6e22e">PublicKey&lt;/span> &lt;span style="color:#f92672">=&lt;/span> &lt;span style="color:#e6db74">&amp;lt;public key for public-server1.example-vpn.tld&amp;gt;&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#75715e"># 路由整个 VPN 子网的流量&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#a6e22e">AllowedIPs&lt;/span> &lt;span style="color:#f92672">=&lt;/span> &lt;span style="color:#e6db74">192.0.2.1/24&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#a6e22e">PersistentKeepalive&lt;/span> &lt;span style="color:#f92672">=&lt;/span> &lt;span style="color:#e6db74">25&lt;/span>
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>&lt;h4 id="endpoint">Endpoint&lt;/h4>
&lt;p>指定远端对等节点（peer）的公网地址。如果对等节点（peer）位于 NAT 后面或者没有稳定的公网访问地址，就忽略这个字段。通常只需要指定中继服务器的 Endpoint，当然有稳定公网 IP 的节点也可以指定。例如：&lt;/p>
&lt;p>通过 IP 指定：&lt;/p>
&lt;div class="highlight">&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;">&lt;code class="language-ini" data-lang="ini">&lt;span style="display:flex;">&lt;span>&lt;span style="color:#a6e22e">Endpoint&lt;/span> &lt;span style="color:#f92672">=&lt;/span> &lt;span style="color:#e6db74">123.124.125.126:51820&lt;/span>
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>&lt;p>通过域名指定：&lt;/p>
&lt;div class="highlight">&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;">&lt;code class="language-ini" data-lang="ini">&lt;span style="display:flex;">&lt;span>&lt;span style="color:#a6e22e">Endpoint&lt;/span> &lt;span style="color:#f92672">=&lt;/span> &lt;span style="color:#e6db74">public-server1.example-vpn.tld:51820&lt;/span>
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>&lt;h4 id="allowedips">AllowedIPs&lt;/h4>
&lt;p>允许该对等节点（peer）发送过来的 VPN 流量中的源地址范围。同时这个字段也会作为本机路由表中 wg0 绑定的 IP 地址范围。如果对等节点（peer）是常规的客户端，则将其设置为节点本身的单个 IP；如果对等节点（peer）是中继服务器，则将其设置为可路由的子网范围。可以使用 , 来指定多个 IP 或子网范围。该字段也可以指定多次。&lt;/p>
&lt;p>当决定如何对一个数据包进行路由时，系统首先会选择最具体的路由，如果不匹配再选择更宽泛的路由。例如，对于一个发往 192.0.2.3 的数据包，系统首先会寻找地址为 192.0.2.3/32 的对等节点（peer），如果没有再寻找地址为 192.0.2.1/24 的对等节点（peer），以此类推。&lt;/p>
&lt;p>例如：&lt;/p>
&lt;p>对等节点（peer）是常规客户端，只路由自身的流量：&lt;/p>
&lt;div class="highlight">&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;">&lt;code class="language-ini" data-lang="ini">&lt;span style="display:flex;">&lt;span>&lt;span style="color:#a6e22e">AllowedIPs&lt;/span> &lt;span style="color:#f92672">=&lt;/span> &lt;span style="color:#e6db74">192.0.2.3/32&lt;/span>
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>&lt;p>对等节点（peer）是中继服务器，可以将流量转发到其他对等节点（peer）：&lt;/p>
&lt;div class="highlight">&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;">&lt;code class="language-ini" data-lang="ini">&lt;span style="display:flex;">&lt;span>&lt;span style="color:#a6e22e">AllowedIPs&lt;/span> &lt;span style="color:#f92672">=&lt;/span> &lt;span style="color:#e6db74">192.0.2.1/24&lt;/span>
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>&lt;p>对等节点（peer）是中继服务器，可以转发所有的流量，包括外网流量和 VPN 流量：&lt;/p>
&lt;div class="highlight">&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;">&lt;code class="language-ini" data-lang="ini">&lt;span style="display:flex;">&lt;span>&lt;span style="color:#a6e22e">AllowedIPs&lt;/span> &lt;span style="color:#f92672">=&lt;/span> &lt;span style="color:#e6db74">0.0.0.0/0,::/0&lt;/span>
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>&lt;p>对等节点（peer）是中继服务器，可以路由其自身和其他对等节点（peer）的流量：&lt;/p>
&lt;div class="highlight">&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;">&lt;code class="language-ini" data-lang="ini">&lt;span style="display:flex;">&lt;span>&lt;span style="color:#a6e22e">AllowedIPs&lt;/span> &lt;span style="color:#f92672">=&lt;/span> &lt;span style="color:#e6db74">192.0.2.3/32,192.0.2.4/32&lt;/span>
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>&lt;p>对等节点（peer）是中继服务器，可以路由其自身的流量和它所在的内网的流量：&lt;/p>
&lt;div class="highlight">&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;">&lt;code class="language-ini" data-lang="ini">&lt;span style="display:flex;">&lt;span>&lt;span style="color:#a6e22e">AllowedIPs&lt;/span> &lt;span style="color:#f92672">=&lt;/span> &lt;span style="color:#e6db74">192.0.2.3/32,192.168.1.1/24&lt;/span>
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>&lt;h4 id="publickey">PublicKey&lt;/h4>
&lt;p>对等节点（peer）的公钥，所有节点（包括中继服务器）都必须设置。可与其他对等节点（peer）共用同一个公钥。&lt;/p>
&lt;p>公钥可通过命令 &lt;code>wg pubkey &amp;lt; example.key &amp;gt; example.key.pub&lt;/code> 来生成，其中 example.key 是上面生成的私钥。&lt;/p>
&lt;h4 id="persistentkeepalive">PersistentKeepalive&lt;/h4>
&lt;p>如果连接是从一个位于 NAT 后面的对等节点（peer）到一个公网可达的对等节点（peer），那么 NAT 后面的对等节点（peer）必须定期发送一个出站 ping 包来检查连通性，如果 IP 有变化，就会自动更新Endpoint。&lt;/p>
&lt;p>例如：&lt;/p>
&lt;p>本地节点与对等节点（peer）可直连：该字段不需要指定，因为不需要连接检查。&lt;/p>
&lt;p>对等节点（peer）位于 NAT 后面：该字段不需要指定，因为维持连接是客户端（连接的发起方）的责任。&lt;/p>
&lt;p>本地节点位于 NAT 后面，对等节点（peer）公网可达：需要指定该字段 PersistentKeepalive = 25，表示每隔 25 秒发送一次 ping 来检查连接。&lt;/p>
&lt;h3 id="共享一个-peersconf-文件">共享一个 peers.conf 文件&lt;/h3>
&lt;p>如果某个 peer 的公钥与本地接口的私钥能够配对，那么 WireGuard 会忽略该 &lt;code>peer&lt;/code>。利用这个特性，我们可以在所有节点上共用同一个 &lt;code>peer&lt;/code> 列表，每个节点只需要单独定义一个 &lt;code>[Interface]&lt;/code> 就行了，即使列表中有本节点，也会被忽略。具体方式如下：&lt;/p>
&lt;p>每个对等节点（peer）都有一个单独的 &lt;code>/etc/wireguard/wg0.conf&lt;/code> 文件，只包含 &lt;code>[Interface]&lt;/code> 部分的配置。&lt;/p>
&lt;p>每个对等节点（peer）共用同一个 &lt;code>/etc/wireguard/peers.conf&lt;/code> 文件，其中包含了所有的 peer。&lt;/p>
&lt;p>Wg0.conf 文件中需要配置一个 PostUp 钩子，内容为&lt;/p>
&lt;div class="highlight">&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;">&lt;code class="language-ini" data-lang="ini">&lt;span style="display:flex;">&lt;span>&lt;span style="color:#a6e22e">PostUp&lt;/span> &lt;span style="color:#f92672">=&lt;/span> &lt;span style="color:#e6db74">wg addconf /etc/wireguard/peers.conf&lt;/span>
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div></description></item><item><title>K3s 快速入门指南:构建多云环境下的K3S集群</title><link>https://blog.baicai.me/article/2023/quick_start/</link><pubDate>Thu, 28 Sep 2023 20:29:29 +0800</pubDate><author>admin@baicai.me (白菜)</author><guid>https://blog.baicai.me/article/2023/quick_start/</guid><description>&lt;p>K3s 是轻量级的 Kubernetes。server最低只需要512M内存即可运行。&lt;/p>
&lt;p>不同账号甚至不同云服务商， 内网是不通的。所以要想办法实现跨公网的容器网络通信，保障任意一台节点上的pod能访问任意节点上的pod和service，和正常的kubernetes集群体验一致。&lt;/p>
&lt;p>参考入门指南和多云解决方案，重新整理&lt;/p>
&lt;p>目标：实现混合云(腾讯云服务器+甲骨文服务器+微软Azure服务器)境下的K3S集群&lt;/p>
&lt;h3 id="server安装">Server安装&lt;/h3>
&lt;div class="highlight">&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;">&lt;code class="language-bash" data-lang="bash">&lt;span style="display:flex;">&lt;span>&lt;span style="color:#75715e"># 局域网方案&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>curl -sfL https://get.k3s.io | sh -
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#75715e"># 多云安装方案&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>curl -sfL https://get.k3s.io | sh -s - --node-external-ip&lt;span style="color:#f92672">=&lt;/span>Server公网地址 --flannel-backend&lt;span style="color:#f92672">=&lt;/span>wireguard-native
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>&lt;p>中国用户，可以使用以下方法加速安装：&lt;/p>
&lt;div class="highlight">&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;">&lt;code class="language-bash" data-lang="bash">&lt;span style="display:flex;">&lt;span>&lt;span style="color:#75715e"># 局域网方案&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>curl -sfL https://rancher-mirror.rancher.cn/k3s/k3s-install.sh | INSTALL_K3S_MIRROR&lt;span style="color:#f92672">=&lt;/span>cn sh -
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#75715e"># 多云安装方案&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>curl -sfL https://rancher-mirror.rancher.cn/k3s/k3s-install.sh | INSTALL_K3S_MIRROR&lt;span style="color:#f92672">=&lt;/span>cn sh -s - --node-external-ip&lt;span style="color:#f92672">=&lt;/span>Server公网地址 --flannel-backend&lt;span style="color:#f92672">=&lt;/span>wireguard-native --flannel-external-ip
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>&lt;p>运行此安装后：&lt;/p>
&lt;pre tabindex="0">&lt;code>K3s 服务将被配置为在节点重启后或进程崩溃或被杀死时自动重启。
将安装其他实用程序，包括 ```kubectl```、```crictl```、```ctr```、```k3s-killall.sh``` 和 ```k3s-uninstall.sh```。
kubeconfig 文件将写入到 ```/etc/rancher/k3s/k3s.yaml```，由 K3s 安装的 kubectl 将自动使用该文件。
&lt;/code>&lt;/pre>&lt;h3 id="安装其他-agent-节点">安装其他 Agent 节点&lt;/h3>
&lt;p>安装其他 Agent 节点并将它们添加到集群，请使用 K3S_URL 和 K3S_TOKEN 环境变量运行安装脚本&lt;/p>
&lt;div class="highlight">&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;">&lt;code class="language-bash" data-lang="bash">&lt;span style="display:flex;">&lt;span>&lt;span style="color:#75715e"># 局域网方案&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>curl -sfL https://get.k3s.io | K3S_URL&lt;span style="color:#f92672">=&lt;/span>https://myserver:6443 K3S_TOKEN&lt;span style="color:#f92672">=&lt;/span>mynodetoken sh -
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#75715e"># 多云安装方案&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>curl -sfL https://get.k3s.io | K3S_URL&lt;span style="color:#f92672">=&lt;/span>https://Server公网地址:6443 K3S_TOKEN&lt;span style="color:#f92672">=&lt;/span>mynodetoken sh -s - --node-external-ip&lt;span style="color:#f92672">=&lt;/span>Agent公网地址
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>&lt;div class="highlight">&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;">&lt;code class="language-bash" data-lang="bash">&lt;span style="display:flex;">&lt;span>&lt;span style="color:#75715e"># 局域网方案&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>curl -sfL https://rancher-mirror.rancher.cn/k3s/k3s-install.sh | INSTALL_K3S_MIRROR&lt;span style="color:#f92672">=&lt;/span>cn K3S_URL&lt;span style="color:#f92672">=&lt;/span>https://myserver:6443 K3S_TOKEN&lt;span style="color:#f92672">=&lt;/span>mynodetoken sh -
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#75715e"># 多云安装方案&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>curl -sfL https://rancher-mirror.rancher.cn/k3s/k3s-install.sh | INSTALL_K3S_MIRROR&lt;span style="color:#f92672">=&lt;/span>cn K3S_URL&lt;span style="color:#f92672">=&lt;/span>https://Server公网地址:6443 K3S_TOKEN&lt;span style="color:#f92672">=&lt;/span>mynodetoken sh -s - --node-external-ip&lt;span style="color:#f92672">=&lt;/span>Agent公网地址
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>&lt;p>备注：
&lt;code>K3S_URL&lt;/code> 参数会导致安装程序将 K3s 配置为 Agent 而不是 Server。K3s Agent 将注册到在 URL 上监听的 K3s Server。&lt;code>K3S_TOKEN&lt;/code> 使用的值存储在 Server 节点上的 &lt;code>/var/lib/rancher/k3s/server/node-token&lt;/code> 中。
每台主机必须具有唯一的主机名。如果你的计算机没有唯一的主机名，请传递 K3S_NODE_NAME 环境变量，并为每个节点提供一个有效且唯一的主机名。&lt;/p>
&lt;h3 id="在本机访问k3s集群">在本机访问k3s集群&lt;/h3>
&lt;p>安装kubectl&lt;/p>
&lt;div class="highlight">&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;">&lt;code class="language-bash" data-lang="bash">&lt;span style="display:flex;">&lt;span>brew install kubectl
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>&lt;p>复制 Server 中 &lt;code>/etc/rancher/k3s/k3s.yaml&lt;/code> 的内容&lt;/p>
&lt;p>写入本机的&lt;code>~/.kube/config&lt;/code>文件.&lt;/p>
&lt;p>参考scp复制指令：&lt;/p>
&lt;div class="highlight">&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;">&lt;code class="language-bash" data-lang="bash">&lt;span style="display:flex;">&lt;span>scp server:/etc/rancher/k3s/k3s.yaml ~/.kube/config
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>&lt;h3 id="测试指令">测试指令&lt;/h3>
&lt;p>查看节点状态：&lt;/p>
&lt;div class="highlight">&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;">&lt;code class="language-bash" data-lang="bash">&lt;span style="display:flex;">&lt;span>$ kubectl get node
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>NAME STATUS ROLES AGE VERSION
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>vm-4-10-debian Ready &amp;lt;none&amp;gt; 35m v1.27.6+k3s1
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>vm-4-9-debian Ready control-plane,master 39m v1.27.6+k3s1
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>&lt;p>检查跨网通讯：&lt;/p>
&lt;div class="highlight">&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;">&lt;code class="language-bash" data-lang="bash">&lt;span style="display:flex;">&lt;span>$ kubectl get pod -A -o wide
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>NAMESPACE NAME READY STATUS RESTARTS AGE IP NODE NOMINATED NODE READINESS GATES
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>kube-system local-path-provisioner-957fdf8bc-gcgj4 1/1 Running &lt;span style="color:#ae81ff">0&lt;/span> 38m 10.42.0.5 vm-4-9-debian &amp;lt;none&amp;gt; &amp;lt;none&amp;gt;
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>kube-system coredns-77ccd57875-vsxmt 1/1 Running &lt;span style="color:#ae81ff">0&lt;/span> 38m 10.42.0.6 vm-4-9-debian &amp;lt;none&amp;gt; &amp;lt;none&amp;gt;
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>kube-system helm-install-traefik-crd-sv9jh 0/1 Completed &lt;span style="color:#ae81ff">0&lt;/span> 38m 10.42.0.4 vm-4-9-debian &amp;lt;none&amp;gt; &amp;lt;none&amp;gt;
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>kube-system metrics-server-5f8b4ffd8-zd4db 1/1 Running &lt;span style="color:#ae81ff">0&lt;/span> 38m 10.42.0.3 vm-4-9-debian &amp;lt;none&amp;gt; &amp;lt;none&amp;gt;
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>kube-system helm-install-traefik-jp8sk 0/1 Completed &lt;span style="color:#ae81ff">2&lt;/span> 38m 10.42.0.2 vm-4-9-debian &amp;lt;none&amp;gt; &amp;lt;none&amp;gt;
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>kube-system svclb-traefik-0782c5d1-wr5kd 2/2 Running &lt;span style="color:#ae81ff">0&lt;/span> 37m 10.42.0.7 vm-4-9-debian &amp;lt;none&amp;gt; &amp;lt;none&amp;gt;
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>kube-system traefik-64f55bb67d-4lr2g 1/1 Running &lt;span style="color:#ae81ff">0&lt;/span> 37m 10.42.0.8 vm-4-9-debian &amp;lt;none&amp;gt; &amp;lt;none&amp;gt;
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>kube-system svclb-traefik-0782c5d1-444jv 2/2 Running &lt;span style="color:#ae81ff">0&lt;/span> 34m 10.42.1.2 vm-4-10-debian &amp;lt;none&amp;gt; &amp;lt;none&amp;gt;
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>&lt;p>查看节点资源使用情况：&lt;/p>
&lt;div class="highlight">&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;">&lt;code class="language-bash" data-lang="bash">&lt;span style="display:flex;">&lt;span>$ kubectl top node
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>NAME CPU&lt;span style="color:#f92672">(&lt;/span>cores&lt;span style="color:#f92672">)&lt;/span> CPU% MEMORY&lt;span style="color:#f92672">(&lt;/span>bytes&lt;span style="color:#f92672">)&lt;/span> MEMORY%
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>vm-4-9-debian 24m 2% 1369Mi 69%
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>vm-4-10-debian &amp;lt;unknown&amp;gt; &amp;lt;unknown&amp;gt; &amp;lt;unknown&amp;gt; &amp;lt;unknown&amp;gt;
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>&lt;p>查看POD资源使用情况:&lt;/p>
&lt;div class="highlight">&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;">&lt;code class="language-bash" data-lang="bash">&lt;span style="display:flex;">&lt;span>$ kubectl top pod -A
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>NAMESPACE NAME CPU&lt;span style="color:#f92672">(&lt;/span>cores&lt;span style="color:#f92672">)&lt;/span> MEMORY&lt;span style="color:#f92672">(&lt;/span>bytes&lt;span style="color:#f92672">)&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>kube-system coredns-77ccd57875-vsxmt 1m 20Mi
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>kube-system local-path-provisioner-957fdf8bc-gcgj4 1m 14Mi
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>kube-system metrics-server-5f8b4ffd8-zd4db 3m 24Mi
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>kube-system svclb-traefik-0782c5d1-wr5kd 0m 0Mi
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>kube-system traefik-64f55bb67d-4lr2g 1m 33Mi
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>&lt;p>到此k3s集群部署完成， 如果有更多的主机，可以重复agent的配置步骤进行添加。&lt;/p>
&lt;h3 id="k3s-server-节点的入站规则">K3s Server 节点的入站规则&lt;/h3>
&lt;table>
&lt;thead>
&lt;tr>
&lt;th style="text-align: left">协议&lt;/th>
&lt;th style="text-align: center">端口&lt;/th>
&lt;th style="text-align: center">源&lt;/th>
&lt;th style="text-align: center">目标&lt;/th>
&lt;th style="text-align: left">描述&lt;/th>
&lt;/tr>
&lt;/thead>
&lt;tbody>
&lt;tr>
&lt;td style="text-align: left">TCP&lt;/td>
&lt;td style="text-align: center">2379-2380&lt;/td>
&lt;td style="text-align: center">Servers&lt;/td>
&lt;td style="text-align: center">Servers&lt;/td>
&lt;td style="text-align: left">只有具有嵌入式 etcd 的 HA 需要&lt;/td>
&lt;/tr>
&lt;tr>
&lt;td style="text-align: left">TCP&lt;/td>
&lt;td style="text-align: center">6443&lt;/td>
&lt;td style="text-align: center">Agents&lt;/td>
&lt;td style="text-align: center">Servers&lt;/td>
&lt;td style="text-align: left">K3s supervisor 和 Kubernetes API Server&lt;/td>
&lt;/tr>
&lt;tr>
&lt;td style="text-align: left">UDP&lt;/td>
&lt;td style="text-align: center">8472&lt;/td>
&lt;td style="text-align: center">所有节点&lt;/td>
&lt;td style="text-align: center">所有节点&lt;/td>
&lt;td style="text-align: left">只有 Flannel VXLAN 需要&lt;/td>
&lt;/tr>
&lt;tr>
&lt;td style="text-align: left">TCP&lt;/td>
&lt;td style="text-align: center">10250&lt;/td>
&lt;td style="text-align: center">所有节点&lt;/td>
&lt;td style="text-align: center">所有节点&lt;/td>
&lt;td style="text-align: left">Kubelet 指标&lt;/td>
&lt;/tr>
&lt;tr>
&lt;td style="text-align: left">UDP&lt;/td>
&lt;td style="text-align: center">51820&lt;/td>
&lt;td style="text-align: center">所有节点&lt;/td>
&lt;td style="text-align: center">所有节点&lt;/td>
&lt;td style="text-align: left">只有使用 IPv4 的 Flannel Wireguard 才需要&lt;/td>
&lt;/tr>
&lt;tr>
&lt;td style="text-align: left">UDP&lt;/td>
&lt;td style="text-align: center">51821&lt;/td>
&lt;td style="text-align: center">所有节点&lt;/td>
&lt;td style="text-align: center">所有节点&lt;/td>
&lt;td style="text-align: left">只有使用 IPv6 的 Flannel Wireguard 才需要&lt;/td>
&lt;/tr>
&lt;/tbody>
&lt;/table>
&lt;p>所有出站流量通常都是允许的。&lt;/p>
&lt;h3 id="参考">参考：&lt;/h3>
&lt;p>&lt;a href="https://docs.k3s.io/zh/quick-start">快速入门指南&lt;/a>&lt;/p>
&lt;p>&lt;a href="https://docs.k3s.io/zh/installation/network-options#%E5%B5%8C%E5%85%A5%E5%BC%8F-k3s-%E5%A4%9A%E4%BA%91%E8%A7%A3%E5%86%B3%E6%96%B9%E6%A1%88">嵌入式 k3s 多云解决方案&lt;/a>&lt;/p></description></item><item><title>Telegram 界面自定义翻译</title><link>https://blog.baicai.me/article/2023/translations/</link><pubDate>Thu, 21 Sep 2023 00:01:03 +0800</pubDate><author>admin@baicai.me (白菜)</author><guid>https://blog.baicai.me/article/2023/translations/</guid><description>&lt;h3 id="语言包的获取方法">语言包的获取方法&lt;/h3>
&lt;p>进入官网翻译界面 &lt;a href="https://translations.telegram.org">https://translations.telegram.org&lt;/a>&lt;/p>
&lt;p>点击 &amp;ldquo;Start Translating&amp;rdquo;&lt;/p>
&lt;p>选择 对应语言 比如 简体中文 进入网址&lt;/p>
&lt;p>&lt;a href="https://translations.telegram.org/zh-hans/">https://translations.telegram.org/zh-hans/&lt;/a>&lt;/p>
&lt;p>底部有 &amp;ldquo;Sharing Link&amp;rdquo; 在 telegram 中打开这个网址 就可以换界面语言了。&lt;/p>
&lt;p>自定义界面语言的话，选择上面的 客户端类型，根据提示 编辑对应翻译内容 即可。&lt;/p>
&lt;h3 id="telegram-中文语言包">Telegram 中文语言包&lt;/h3>
&lt;p>&lt;a href="https://t.me/setlanguage/zh-hans-beta">https://t.me/setlanguage/zh-hans-beta&lt;/a>&lt;/p></description></item><item><title>搭建反向代理服务：Telegram Bot Api 反向代理搭建</title><link>https://blog.baicai.me/article/2023/reverse-proxy/</link><pubDate>Wed, 20 Sep 2023 12:06:18 +0800</pubDate><author>admin@baicai.me (白菜)</author><guid>https://blog.baicai.me/article/2023/reverse-proxy/</guid><description>&lt;p>上面一篇通过nginx和cloudflare workers 搭建的反向代理。&lt;/p>
&lt;p>这一篇通过更简单的代码重下搭建个。&lt;/p>
&lt;h2 id="通过-cloudflare-workers-搭建反向代理服务">通过 Cloudflare Workers 搭建反向代理服务&lt;/h2>
&lt;p>创建 Cloudflare workers 的步骤都是一样的，代码不一样。&lt;/p>
&lt;h3 id="创建一个worker">创建一个Worker&lt;/h3>
&lt;p>在首页选择Workers，若从未创建过则初始化，选择免费套餐，然后创建一个Worker。&lt;/p>
&lt;h3 id="编辑worker内容">编辑Worker内容&lt;/h3>
&lt;p>进入worker，点击快速编辑，将代码改为下方内容，其中hostname改为你自己的，然后点击保存部署，并可改名为例如cdn的worker。&lt;/p>
&lt;div class="highlight">&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;">&lt;code class="language-js" data-lang="js">&lt;span style="display:flex;">&lt;span>&lt;span style="color:#75715e">// 这就是需要代理的网址
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#75715e">&lt;/span>&lt;span style="color:#66d9ef">const&lt;/span> &lt;span style="color:#a6e22e">hostname&lt;/span> &lt;span style="color:#f92672">=&lt;/span> &lt;span style="color:#e6db74">&amp;#34;https://example.domain&amp;#34;&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#75715e">// const hostname = &amp;#34;http://192.168.0.1&amp;#34;
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#75715e">// const hostname = &amp;#34;https://your.domain&amp;#34;
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#75715e">// const hostname = &amp;#34;https://your.domain/api/path&amp;#34;
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#75715e">&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#66d9ef">function&lt;/span> &lt;span style="color:#a6e22e">handleRequest&lt;/span>(&lt;span style="color:#a6e22e">request&lt;/span>) {
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#66d9ef">let&lt;/span> &lt;span style="color:#a6e22e">url&lt;/span> &lt;span style="color:#f92672">=&lt;/span> &lt;span style="color:#66d9ef">new&lt;/span> &lt;span style="color:#a6e22e">URL&lt;/span>(&lt;span style="color:#a6e22e">request&lt;/span>.&lt;span style="color:#a6e22e">url&lt;/span>);
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#66d9ef">return&lt;/span> &lt;span style="color:#a6e22e">fetch&lt;/span>(&lt;span style="color:#66d9ef">new&lt;/span> &lt;span style="color:#a6e22e">Request&lt;/span>(&lt;span style="color:#a6e22e">hostname&lt;/span> &lt;span style="color:#f92672">+&lt;/span> &lt;span style="color:#a6e22e">url&lt;/span>.&lt;span style="color:#a6e22e">pathname&lt;/span>,&lt;span style="color:#a6e22e">request&lt;/span>))
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>}
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#a6e22e">addEventListener&lt;/span>(&lt;span style="color:#e6db74">&amp;#34;fetch&amp;#34;&lt;/span>, &lt;span style="color:#a6e22e">event&lt;/span> =&amp;gt; {
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#a6e22e">event&lt;/span>.&lt;span style="color:#a6e22e">respondWith&lt;/span>(&lt;span style="color:#a6e22e">handleRequest&lt;/span>(&lt;span style="color:#a6e22e">event&lt;/span>.&lt;span style="color:#a6e22e">request&lt;/span>))
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>})
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>&lt;h3 id="为域名添加dns">为域名添加DNS&lt;/h3>
&lt;p>添加路由，配置&lt;/p>
&lt;pre tabindex="0">&lt;code class="language-cn.you.domain/*" data-lang="cn.you.domain/*">&lt;/code>&lt;/pre>&lt;p>指向步骤1创建的 Worker，到此等待DNS生效即可。&lt;/p>
&lt;h2 id="通过-vercel-搭建反向代理服务">通过 Vercel 搭建反向代理服务&lt;/h2>
&lt;p>在github中新建个项目
创建一个文件，命名为 vercel.json 文件内容：&lt;/p>
&lt;div class="highlight">&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;">&lt;code class="language-json" data-lang="json">&lt;span style="display:flex;">&lt;span>{
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#f92672">&amp;#34;routes&amp;#34;&lt;/span>: [
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> { &lt;span style="color:#f92672">&amp;#34;src&amp;#34;&lt;/span>: &lt;span style="color:#e6db74">&amp;#34;/.*&amp;#34;&lt;/span>, &lt;span style="color:#f92672">&amp;#34;dest&amp;#34;&lt;/span>: &lt;span style="color:#e6db74">&amp;#34;https://example.domain&amp;#34;&lt;/span>}
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> ]
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>}
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>&lt;p>进入 vercel 后台 部署这个项目 配置好自定义域名，即可使用。&lt;/p>
&lt;p>通用代理 json 内容 参考：&lt;/p>
&lt;div class="highlight">&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;">&lt;code class="language-json" data-lang="json">&lt;span style="display:flex;">&lt;span>{
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#f92672">&amp;#34;routes&amp;#34;&lt;/span>: [
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> { &lt;span style="color:#f92672">&amp;#34;src&amp;#34;&lt;/span>: &lt;span style="color:#e6db74">&amp;#34;/redirect&amp;#34;&lt;/span>, &lt;span style="color:#f92672">&amp;#34;status&amp;#34;&lt;/span>: &lt;span style="color:#ae81ff">308&lt;/span>, &lt;span style="color:#f92672">&amp;#34;headers&amp;#34;&lt;/span>: { &lt;span style="color:#f92672">&amp;#34;Location&amp;#34;&lt;/span>: &lt;span style="color:#e6db74">&amp;#34;https://example.domain/&amp;#34;&lt;/span> } },
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> { &lt;span style="color:#f92672">&amp;#34;src&amp;#34;&lt;/span>: &lt;span style="color:#e6db74">&amp;#34;/custom-page&amp;#34;&lt;/span>, &lt;span style="color:#f92672">&amp;#34;headers&amp;#34;&lt;/span>: {&lt;span style="color:#f92672">&amp;#34;cache-control&amp;#34;&lt;/span>: &lt;span style="color:#e6db74">&amp;#34;s-maxage=1000&amp;#34;&lt;/span>}, &lt;span style="color:#f92672">&amp;#34;dest&amp;#34;&lt;/span>: &lt;span style="color:#e6db74">&amp;#34;/index.html&amp;#34;&lt;/span> },
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> { &lt;span style="color:#f92672">&amp;#34;src&amp;#34;&lt;/span>: &lt;span style="color:#e6db74">&amp;#34;/api&amp;#34;&lt;/span>, &lt;span style="color:#f92672">&amp;#34;dest&amp;#34;&lt;/span>: &lt;span style="color:#e6db74">&amp;#34;/my-api.js&amp;#34;&lt;/span> },
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> { &lt;span style="color:#f92672">&amp;#34;src&amp;#34;&lt;/span>: &lt;span style="color:#e6db74">&amp;#34;/users&amp;#34;&lt;/span>, &lt;span style="color:#f92672">&amp;#34;methods&amp;#34;&lt;/span>: [&lt;span style="color:#e6db74">&amp;#34;POST&amp;#34;&lt;/span>], &lt;span style="color:#f92672">&amp;#34;dest&amp;#34;&lt;/span>: &lt;span style="color:#e6db74">&amp;#34;/users-api.js&amp;#34;&lt;/span> },
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> { &lt;span style="color:#f92672">&amp;#34;src&amp;#34;&lt;/span>: &lt;span style="color:#e6db74">&amp;#34;/users/(?&amp;lt;id&amp;gt;[^/]*)&amp;#34;&lt;/span>, &lt;span style="color:#f92672">&amp;#34;dest&amp;#34;&lt;/span>: &lt;span style="color:#e6db74">&amp;#34;/users-api.js?id=$id&amp;#34;&lt;/span> },
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> { &lt;span style="color:#f92672">&amp;#34;src&amp;#34;&lt;/span>: &lt;span style="color:#e6db74">&amp;#34;/legacy&amp;#34;&lt;/span>, &lt;span style="color:#f92672">&amp;#34;status&amp;#34;&lt;/span>: &lt;span style="color:#ae81ff">404&lt;/span>},
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> { &lt;span style="color:#f92672">&amp;#34;src&amp;#34;&lt;/span>: &lt;span style="color:#e6db74">&amp;#34;/.*&amp;#34;&lt;/span>, &lt;span style="color:#f92672">&amp;#34;dest&amp;#34;&lt;/span>: &lt;span style="color:#e6db74">&amp;#34;https://example.domain/&amp;#34;&lt;/span>}
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> ]
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>}
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>&lt;h2 id="通过nginx-对网站进行反向代理">通过Nginx 对网站进行反向代理&lt;/h2>
&lt;h3 id="创建配置文件">创建配置文件&lt;/h3>
&lt;div class="highlight">&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;">&lt;code class="language-bash" data-lang="bash">&lt;span style="display:flex;">&lt;span>nano /etc/nginx/conf.d/tgapi.conf
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>&lt;p>输入一下内容并保存&lt;/p>
&lt;pre tabindex="0">&lt;code class="language-conf" data-lang="conf">server {
listen 80;
server_name tgapi.domain;
location / {
return 444;
}
location ~* ^/bot {
resolver 8.8.8.8;
proxy_buffering off;
proxy_pass https://example.domain$request_uri;
}
}
&lt;/code>&lt;/pre></description></item><item><title>Telegram Bot Api 反向代理搭建</title><link>https://blog.baicai.me/article/2023/nginx_tgapi_proxy/</link><pubDate>Tue, 19 Sep 2023 22:28:07 +0800</pubDate><author>admin@baicai.me (白菜)</author><guid>https://blog.baicai.me/article/2023/nginx_tgapi_proxy/</guid><description>&lt;p>由于一些原因，配置epusdt需要使用tg反向代理地址才能使用！&lt;/p>
&lt;div class="highlight">&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;">&lt;code class="language-env" data-lang="env">&lt;span style="display:flex;">&lt;span>&lt;span style="color:#75715e">#telegram代理url(大陆地区服务器可使用一台国外服务器做反代tg的url)，如果运行的本来就是境外服务器，则无需填写&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>tg_proxy&lt;span style="color:#f92672">=&lt;/span>
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>&lt;p>两种实现方案，根据个人喜好选择使用或发挥&lt;/p>
&lt;h2 id="nginx反代telegram-api">Nginx反代Telegram Api&lt;/h2>
&lt;h3 id="安装nginx">安装nginx&lt;/h3>
&lt;div class="highlight">&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;">&lt;code class="language-bash" data-lang="bash">&lt;span style="display:flex;">&lt;span>sudo apt update &lt;span style="color:#f92672">&amp;amp;&amp;amp;&lt;/span> sudo apt install -y nginx
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>&lt;h3 id="创建配置文件">创建配置文件&lt;/h3>
&lt;div class="highlight">&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;">&lt;code class="language-bash" data-lang="bash">&lt;span style="display:flex;">&lt;span>nano tgapi.conf
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>&lt;p>输入一下内容并保存&lt;/p>
&lt;pre tabindex="0">&lt;code class="language-conf" data-lang="conf">server {
listen 80;
server_name tgapi.domain;
location / {
return 444;
}
location ~* ^/bot {
resolver 8.8.8.8;
proxy_buffering off;
proxy_pass https://api.telegram.org$request_uri;
}
}
&lt;/code>&lt;/pre>&lt;h3 id="加载配置">加载配置&lt;/h3>
&lt;div class="highlight">&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;">&lt;code class="language-bash" data-lang="bash">&lt;span style="display:flex;">&lt;span>sudo systemctl reload nginx
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#75715e">#或&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>sudo nginx -s reload
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>&lt;h3 id="测试访问">测试访问&lt;/h3>
&lt;p>输入以下命令行,BOT_TOKEN换成自己机器人token。&lt;/p>
&lt;div class="highlight">&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;">&lt;code class="language-bash" data-lang="bash">&lt;span style="display:flex;">&lt;span>curl https://tgapi.domain/bot&amp;lt;BOT_TOKEN&amp;gt;/getMe
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>&lt;p>看的机器人信息，就说明可以使用了。&lt;/p>
&lt;h3 id="配置-epusdt-telegram代理url">配置 epusdt telegram代理url&lt;/h3>
&lt;p>epusdt 配置(.env)参考&lt;/p>
&lt;div class="highlight">&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;">&lt;code class="language-env" data-lang="env">&lt;span style="display:flex;">&lt;span>&lt;span style="color:#75715e">#telegram代理url(大陆地区服务器可使用一台国外服务器做反代tg的url)，如果运行的本来就是境外服务器，则无需填写&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>tg_proxy&lt;span style="color:#f92672">=&lt;/span>https://tgapi.domain
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>&lt;h3 id="docker-配置-nginx-参考-docker-composeyam-内容">docker 配置 nginx 参考 docker-compose.yam 内容&lt;/h3>
&lt;div class="highlight">&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;">&lt;code class="language-yaml" data-lang="yaml">&lt;span style="display:flex;">&lt;span>&lt;span style="color:#f92672">version&lt;/span>: &lt;span style="color:#e6db74">&amp;#34;3&amp;#34;&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#f92672">services&lt;/span>:
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#f92672">nginx&lt;/span>:
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#f92672">container_name&lt;/span>: &lt;span style="color:#e6db74">&amp;#34;nginx&amp;#34;&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#f92672">restart&lt;/span>: &lt;span style="color:#ae81ff">always&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#f92672">ports&lt;/span>:
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> - &lt;span style="color:#e6db74">&amp;#34;80:80&amp;#34;&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#f92672">image&lt;/span>: &lt;span style="color:#ae81ff">nginx:bookworm&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#f92672">volumes&lt;/span>:
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> - &lt;span style="color:#ae81ff">./conf.d:/etc/nginx/conf.d&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> - &lt;span style="color:#ae81ff">./log:/var/log/nginx&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#f92672">extra_hosts&lt;/span>:
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> - &lt;span style="color:#e6db74">&amp;#34;host.docker.internal:host-gateway&amp;#34;&lt;/span>
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>&lt;h2 id="使用-cloudflare-worker-代理-telegram-bot-api">使用 Cloudflare Worker 代理 Telegram Bot Api&lt;/h2>
&lt;p>使用前提&lt;/p>
&lt;ol>
&lt;li>一个托管在cloudflare的域名&lt;/li>
&lt;li>k开启cloudflare的免费worker服务&lt;/li>
&lt;/ol>
&lt;h3 id="首先登录cloudflare以后点击左侧的workers-和-pages">首先登录Cloudflare以后点击左侧的Workers 和 Pages&lt;/h3>
&lt;p>点击 &lt;code>创建应用程序&lt;/code>-&lt;code>创建 worker&lt;/code>&lt;/p>
&lt;p>&lt;code>名称&lt;/code> 随意填写，点击 &lt;code>部署&lt;/code>&lt;/p>
&lt;p>创建完成后，点击刚创建的Worker，再点击 &lt;code>快速编辑&lt;/code>&lt;/p>
&lt;p>在左侧删除原有的代码，填入下面给出的代码&lt;/p>
&lt;div class="highlight">&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;">&lt;code class="language-js" data-lang="js">&lt;span style="display:flex;">&lt;span>&lt;span style="color:#75715e">/**
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#75715e"> * Helper functions to check if the request uses
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#75715e"> * corresponding method.
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#75715e"> *
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#75715e"> */&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#66d9ef">const&lt;/span> &lt;span style="color:#a6e22e">Method&lt;/span> &lt;span style="color:#f92672">=&lt;/span> (&lt;span style="color:#a6e22e">method&lt;/span>) =&amp;gt; (&lt;span style="color:#a6e22e">req&lt;/span>) =&amp;gt; &lt;span style="color:#a6e22e">req&lt;/span>.&lt;span style="color:#a6e22e">method&lt;/span>.&lt;span style="color:#a6e22e">toLowerCase&lt;/span>() &lt;span style="color:#f92672">===&lt;/span> &lt;span style="color:#a6e22e">method&lt;/span>.&lt;span style="color:#a6e22e">toLowerCase&lt;/span>();
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#66d9ef">const&lt;/span> &lt;span style="color:#a6e22e">Get&lt;/span> &lt;span style="color:#f92672">=&lt;/span> &lt;span style="color:#a6e22e">Method&lt;/span>(&lt;span style="color:#e6db74">&amp;#39;get&amp;#39;&lt;/span>);
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#66d9ef">const&lt;/span> &lt;span style="color:#a6e22e">Post&lt;/span> &lt;span style="color:#f92672">=&lt;/span> &lt;span style="color:#a6e22e">Method&lt;/span>(&lt;span style="color:#e6db74">&amp;#39;post&amp;#39;&lt;/span>);
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#66d9ef">const&lt;/span> &lt;span style="color:#a6e22e">Path&lt;/span> &lt;span style="color:#f92672">=&lt;/span> (&lt;span style="color:#a6e22e">regExp&lt;/span>) =&amp;gt; (&lt;span style="color:#a6e22e">req&lt;/span>) =&amp;gt; {
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#66d9ef">const&lt;/span> &lt;span style="color:#a6e22e">url&lt;/span> &lt;span style="color:#f92672">=&lt;/span> &lt;span style="color:#66d9ef">new&lt;/span> &lt;span style="color:#a6e22e">URL&lt;/span>(&lt;span style="color:#a6e22e">req&lt;/span>.&lt;span style="color:#a6e22e">url&lt;/span>);
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#66d9ef">const&lt;/span> &lt;span style="color:#a6e22e">path&lt;/span> &lt;span style="color:#f92672">=&lt;/span> &lt;span style="color:#a6e22e">url&lt;/span>.&lt;span style="color:#a6e22e">pathname&lt;/span>;
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#66d9ef">return&lt;/span> &lt;span style="color:#a6e22e">path&lt;/span>.&lt;span style="color:#a6e22e">match&lt;/span>(&lt;span style="color:#a6e22e">regExp&lt;/span>) &lt;span style="color:#f92672">&amp;amp;&amp;amp;&lt;/span> &lt;span style="color:#a6e22e">path&lt;/span>.&lt;span style="color:#a6e22e">match&lt;/span>(&lt;span style="color:#a6e22e">regExp&lt;/span>)[&lt;span style="color:#ae81ff">0&lt;/span>] &lt;span style="color:#f92672">===&lt;/span> &lt;span style="color:#a6e22e">path&lt;/span>;
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>};
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#75715e">/*
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#75715e"> * The regex to get the bot_token and api_method from request URL
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#75715e"> * as the first and second backreference respectively.
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#75715e"> */&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#66d9ef">const&lt;/span> &lt;span style="color:#a6e22e">URL_PATH_REGEX&lt;/span> &lt;span style="color:#f92672">=&lt;/span> &lt;span style="color:#e6db74">/^\/bot(?&amp;lt;bot_token&amp;gt;[^/]+)\/(?&amp;lt;api_method&amp;gt;[a-z]+)/i&lt;/span>;
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#75715e">/**
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#75715e"> * Router handles the logic of what handler is matched given conditions
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#75715e"> * for each request
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#75715e"> */&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#66d9ef">class&lt;/span> &lt;span style="color:#a6e22e">Router&lt;/span> {
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#a6e22e">constructor&lt;/span>() {
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#66d9ef">this&lt;/span>.&lt;span style="color:#a6e22e">routes&lt;/span> &lt;span style="color:#f92672">=&lt;/span> [];
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> }
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#a6e22e">handle&lt;/span>(&lt;span style="color:#a6e22e">conditions&lt;/span>, &lt;span style="color:#a6e22e">handler&lt;/span>) {
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#66d9ef">this&lt;/span>.&lt;span style="color:#a6e22e">routes&lt;/span>.&lt;span style="color:#a6e22e">push&lt;/span>({
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#a6e22e">conditions&lt;/span>,
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#a6e22e">handler&lt;/span>,
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> });
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#66d9ef">return&lt;/span> &lt;span style="color:#66d9ef">this&lt;/span>;
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> }
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#a6e22e">get&lt;/span>(&lt;span style="color:#a6e22e">url&lt;/span>, &lt;span style="color:#a6e22e">handler&lt;/span>) {
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#66d9ef">return&lt;/span> &lt;span style="color:#66d9ef">this&lt;/span>.&lt;span style="color:#a6e22e">handle&lt;/span>([&lt;span style="color:#a6e22e">Get&lt;/span>, &lt;span style="color:#a6e22e">Path&lt;/span>(&lt;span style="color:#a6e22e">url&lt;/span>)], &lt;span style="color:#a6e22e">handler&lt;/span>);
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> }
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#a6e22e">post&lt;/span>(&lt;span style="color:#a6e22e">url&lt;/span>, &lt;span style="color:#a6e22e">handler&lt;/span>) {
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#66d9ef">return&lt;/span> &lt;span style="color:#66d9ef">this&lt;/span>.&lt;span style="color:#a6e22e">handle&lt;/span>([&lt;span style="color:#a6e22e">Post&lt;/span>, &lt;span style="color:#a6e22e">Path&lt;/span>(&lt;span style="color:#a6e22e">url&lt;/span>)], &lt;span style="color:#a6e22e">handler&lt;/span>);
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> }
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#a6e22e">all&lt;/span>(&lt;span style="color:#a6e22e">handler&lt;/span>) {
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#66d9ef">return&lt;/span> &lt;span style="color:#66d9ef">this&lt;/span>.&lt;span style="color:#a6e22e">handler&lt;/span>([], &lt;span style="color:#a6e22e">handler&lt;/span>);
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> }
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#a6e22e">route&lt;/span>(&lt;span style="color:#a6e22e">req&lt;/span>) {
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#66d9ef">const&lt;/span> &lt;span style="color:#a6e22e">route&lt;/span> &lt;span style="color:#f92672">=&lt;/span> &lt;span style="color:#66d9ef">this&lt;/span>.&lt;span style="color:#a6e22e">resolve&lt;/span>(&lt;span style="color:#a6e22e">req&lt;/span>);
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#66d9ef">if&lt;/span> (&lt;span style="color:#a6e22e">route&lt;/span>) {
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#66d9ef">return&lt;/span> &lt;span style="color:#a6e22e">route&lt;/span>.&lt;span style="color:#a6e22e">handler&lt;/span>(&lt;span style="color:#a6e22e">req&lt;/span>);
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> }
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#66d9ef">const&lt;/span> &lt;span style="color:#a6e22e">description&lt;/span> &lt;span style="color:#f92672">=&lt;/span> &lt;span style="color:#e6db74">&amp;#39;No matching route found&amp;#39;&lt;/span>;
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#66d9ef">const&lt;/span> &lt;span style="color:#a6e22e">error_code&lt;/span> &lt;span style="color:#f92672">=&lt;/span> &lt;span style="color:#ae81ff">404&lt;/span>;
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#66d9ef">return&lt;/span> &lt;span style="color:#66d9ef">new&lt;/span> &lt;span style="color:#a6e22e">Response&lt;/span>(
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#a6e22e">JSON&lt;/span>.&lt;span style="color:#a6e22e">stringify&lt;/span>({
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#a6e22e">ok&lt;/span>&lt;span style="color:#f92672">:&lt;/span> &lt;span style="color:#66d9ef">false&lt;/span>,
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#a6e22e">error_code&lt;/span>,
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#a6e22e">description&lt;/span>,
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> }),
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> {
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#a6e22e">status&lt;/span>&lt;span style="color:#f92672">:&lt;/span> &lt;span style="color:#a6e22e">error_code&lt;/span>,
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#a6e22e">statusText&lt;/span>&lt;span style="color:#f92672">:&lt;/span> &lt;span style="color:#a6e22e">description&lt;/span>,
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#a6e22e">headers&lt;/span>&lt;span style="color:#f92672">:&lt;/span> {
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#e6db74">&amp;#39;content-type&amp;#39;&lt;/span>&lt;span style="color:#f92672">:&lt;/span> &lt;span style="color:#e6db74">&amp;#39;application/json&amp;#39;&lt;/span>,
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> },
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> }
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> );
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> }
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#75715e">/**
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#75715e"> * It returns the matching route that returns true
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#75715e"> * for all the conditions if any.
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#75715e"> */&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#a6e22e">resolve&lt;/span>(&lt;span style="color:#a6e22e">req&lt;/span>) {
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#66d9ef">return&lt;/span> &lt;span style="color:#66d9ef">this&lt;/span>.&lt;span style="color:#a6e22e">routes&lt;/span>.&lt;span style="color:#a6e22e">find&lt;/span>((&lt;span style="color:#a6e22e">r&lt;/span>) =&amp;gt; {
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#66d9ef">if&lt;/span> (&lt;span style="color:#f92672">!&lt;/span>&lt;span style="color:#a6e22e">r&lt;/span>.&lt;span style="color:#a6e22e">conditions&lt;/span> &lt;span style="color:#f92672">||&lt;/span> (Array.&lt;span style="color:#a6e22e">isArray&lt;/span>(&lt;span style="color:#a6e22e">r&lt;/span>) &lt;span style="color:#f92672">&amp;amp;&amp;amp;&lt;/span> &lt;span style="color:#f92672">!&lt;/span>&lt;span style="color:#a6e22e">r&lt;/span>.&lt;span style="color:#a6e22e">conditions&lt;/span>.&lt;span style="color:#a6e22e">length&lt;/span>)) {
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#66d9ef">return&lt;/span> &lt;span style="color:#66d9ef">true&lt;/span>;
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> }
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#66d9ef">if&lt;/span> (&lt;span style="color:#66d9ef">typeof&lt;/span> &lt;span style="color:#a6e22e">r&lt;/span>.&lt;span style="color:#a6e22e">conditions&lt;/span> &lt;span style="color:#f92672">===&lt;/span> &lt;span style="color:#e6db74">&amp;#39;function&amp;#39;&lt;/span>) {
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#66d9ef">return&lt;/span> &lt;span style="color:#a6e22e">r&lt;/span>.&lt;span style="color:#a6e22e">conditions&lt;/span>(&lt;span style="color:#a6e22e">req&lt;/span>);
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> }
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#66d9ef">return&lt;/span> &lt;span style="color:#a6e22e">r&lt;/span>.&lt;span style="color:#a6e22e">conditions&lt;/span>.&lt;span style="color:#a6e22e">every&lt;/span>((&lt;span style="color:#a6e22e">c&lt;/span>) =&amp;gt; &lt;span style="color:#a6e22e">c&lt;/span>(&lt;span style="color:#a6e22e">req&lt;/span>));
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> });
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> }
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>}
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#75715e">/**
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#75715e"> * Sends a POST request with JSON data to Telegram Bot API
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#75715e"> * and reads in the response body.
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#75715e"> * @param {Request} request the incoming request
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#75715e"> */&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#66d9ef">async&lt;/span> &lt;span style="color:#66d9ef">function&lt;/span> &lt;span style="color:#a6e22e">handler&lt;/span>(&lt;span style="color:#a6e22e">request&lt;/span>) {
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#75715e">// Extract the URl method from the request.
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#75715e">&lt;/span> &lt;span style="color:#66d9ef">const&lt;/span> { &lt;span style="color:#a6e22e">url&lt;/span>, ...&lt;span style="color:#a6e22e">_request&lt;/span> } &lt;span style="color:#f92672">=&lt;/span> &lt;span style="color:#a6e22e">request&lt;/span>;
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#66d9ef">const&lt;/span> { &lt;span style="color:#a6e22e">pathname&lt;/span>&lt;span style="color:#f92672">:&lt;/span> &lt;span style="color:#a6e22e">path&lt;/span>, &lt;span style="color:#a6e22e">search&lt;/span> } &lt;span style="color:#f92672">=&lt;/span> &lt;span style="color:#66d9ef">new&lt;/span> &lt;span style="color:#a6e22e">URL&lt;/span>(&lt;span style="color:#a6e22e">url&lt;/span>);
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#75715e">// Leave the first match as we are interested only in backreferences.
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#75715e">&lt;/span> &lt;span style="color:#66d9ef">const&lt;/span> { &lt;span style="color:#a6e22e">bot_token&lt;/span>, &lt;span style="color:#a6e22e">api_method&lt;/span> } &lt;span style="color:#f92672">=&lt;/span> &lt;span style="color:#a6e22e">path&lt;/span>.&lt;span style="color:#a6e22e">match&lt;/span>(&lt;span style="color:#a6e22e">URL_PATH_REGEX&lt;/span>).&lt;span style="color:#a6e22e">groups&lt;/span>;
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#75715e">// Build the URL
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#75715e">&lt;/span> &lt;span style="color:#66d9ef">const&lt;/span> &lt;span style="color:#a6e22e">api_url&lt;/span> &lt;span style="color:#f92672">=&lt;/span> &lt;span style="color:#e6db74">&amp;#39;https://api.telegram.org/bot&amp;#39;&lt;/span> &lt;span style="color:#f92672">+&lt;/span> &lt;span style="color:#a6e22e">bot_token&lt;/span> &lt;span style="color:#f92672">+&lt;/span> &lt;span style="color:#e6db74">&amp;#39;/&amp;#39;&lt;/span> &lt;span style="color:#f92672">+&lt;/span> &lt;span style="color:#a6e22e">api_method&lt;/span> &lt;span style="color:#f92672">+&lt;/span> &lt;span style="color:#a6e22e">search&lt;/span>;
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#75715e">// Get the response from API.
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#75715e">&lt;/span> &lt;span style="color:#66d9ef">const&lt;/span> &lt;span style="color:#a6e22e">response&lt;/span> &lt;span style="color:#f92672">=&lt;/span> &lt;span style="color:#66d9ef">await&lt;/span> &lt;span style="color:#a6e22e">fetch&lt;/span>(&lt;span style="color:#a6e22e">api_url&lt;/span>, &lt;span style="color:#a6e22e">_request&lt;/span>);
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#66d9ef">const&lt;/span> &lt;span style="color:#a6e22e">result&lt;/span> &lt;span style="color:#f92672">=&lt;/span> &lt;span style="color:#66d9ef">await&lt;/span> &lt;span style="color:#a6e22e">response&lt;/span>.&lt;span style="color:#a6e22e">text&lt;/span>();
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#66d9ef">const&lt;/span> &lt;span style="color:#a6e22e">res&lt;/span> &lt;span style="color:#f92672">=&lt;/span> &lt;span style="color:#66d9ef">new&lt;/span> &lt;span style="color:#a6e22e">Response&lt;/span>(&lt;span style="color:#a6e22e">result&lt;/span>, &lt;span style="color:#a6e22e">_request&lt;/span>);
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#a6e22e">res&lt;/span>.&lt;span style="color:#a6e22e">headers&lt;/span>.&lt;span style="color:#a6e22e">set&lt;/span>(&lt;span style="color:#e6db74">&amp;#39;Content-Type&amp;#39;&lt;/span>, &lt;span style="color:#e6db74">&amp;#39;application/json&amp;#39;&lt;/span>);
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#66d9ef">return&lt;/span> &lt;span style="color:#a6e22e">res&lt;/span>;
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>}
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#75715e">/**
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#75715e"> * Handles the incoming request.
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#75715e"> * @param {Request} request the incoming request.
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#75715e"> */&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#66d9ef">async&lt;/span> &lt;span style="color:#66d9ef">function&lt;/span> &lt;span style="color:#a6e22e">handleRequest&lt;/span>(&lt;span style="color:#a6e22e">request&lt;/span>) {
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#66d9ef">const&lt;/span> &lt;span style="color:#a6e22e">r&lt;/span> &lt;span style="color:#f92672">=&lt;/span> &lt;span style="color:#66d9ef">new&lt;/span> &lt;span style="color:#a6e22e">Router&lt;/span>();
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#a6e22e">r&lt;/span>.&lt;span style="color:#a6e22e">get&lt;/span>(&lt;span style="color:#a6e22e">URL_PATH_REGEX&lt;/span>, (&lt;span style="color:#a6e22e">req&lt;/span>) =&amp;gt; &lt;span style="color:#a6e22e">handler&lt;/span>(&lt;span style="color:#a6e22e">req&lt;/span>));
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#a6e22e">r&lt;/span>.&lt;span style="color:#a6e22e">post&lt;/span>(&lt;span style="color:#a6e22e">URL_PATH_REGEX&lt;/span>, (&lt;span style="color:#a6e22e">req&lt;/span>) =&amp;gt; &lt;span style="color:#a6e22e">handler&lt;/span>(&lt;span style="color:#a6e22e">req&lt;/span>));
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#66d9ef">const&lt;/span> &lt;span style="color:#a6e22e">resp&lt;/span> &lt;span style="color:#f92672">=&lt;/span> &lt;span style="color:#66d9ef">await&lt;/span> &lt;span style="color:#a6e22e">r&lt;/span>.&lt;span style="color:#a6e22e">route&lt;/span>(&lt;span style="color:#a6e22e">request&lt;/span>);
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#66d9ef">return&lt;/span> &lt;span style="color:#a6e22e">resp&lt;/span>;
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>}
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#75715e">/**
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#75715e"> * Hook into the fetch event.
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#75715e"> */&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#a6e22e">addEventListener&lt;/span>(&lt;span style="color:#e6db74">&amp;#39;fetch&amp;#39;&lt;/span>, (&lt;span style="color:#a6e22e">event&lt;/span>) =&amp;gt; {
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#a6e22e">event&lt;/span>.&lt;span style="color:#a6e22e">respondWith&lt;/span>(&lt;span style="color:#a6e22e">handleRequest&lt;/span>(&lt;span style="color:#a6e22e">event&lt;/span>.&lt;span style="color:#a6e22e">request&lt;/span>));
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>});
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>&lt;p>&lt;code>保存并部署&lt;/code>&lt;/p>
&lt;p>回到管理后台首页，点击左侧的&lt;code>网站&lt;/code>，在右侧点击&lt;code>你已托管在Cloudflare的域名&lt;/code>&lt;/p>
&lt;p>选择该域名下的 &lt;code>Workers 路由&lt;/code>&lt;/p>
&lt;p>选择&lt;code>添加路由&lt;/code>&lt;/p>
&lt;p>&lt;code>路由&lt;/code> 填写你想要用的二级域名，比如：&lt;code>tgapi.domain/*&lt;/code> 注意后面必须是&lt;code>/*&lt;/code>结尾，&lt;code>Worker&lt;/code>选择刚才创建的服务，&lt;code>保存&lt;/code>就可以了。&lt;/p></description></item><item><title>甲骨文Vps iptables 开放端口设置</title><link>https://blog.baicai.me/article/2023/oracle_vps_iptables/</link><pubDate>Mon, 18 Sep 2023 10:20:17 +0800</pubDate><author>admin@baicai.me (白菜)</author><guid>https://blog.baicai.me/article/2023/oracle_vps_iptables/</guid><description>&lt;p>在甲骨文的网页后台先开放端口&lt;/p>
&lt;h2 id="iptables-开放所有端口">iptables 开放所有端口&lt;/h2>
&lt;div class="highlight">&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;">&lt;code class="language-bash" data-lang="bash">&lt;span style="display:flex;">&lt;span>sudo iptables -P INPUT ACCEPT
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>sudo iptables -P FORWARD ACCEPT
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>sudo iptables -P OUTPUT ACCEPT
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>sudo iptables -F
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>&lt;h2 id="oracle自带的镜像默认设置了iptable规则关闭它">Oracle自带的镜像默认设置了Iptable规则，关闭它&lt;/h2>
&lt;div class="highlight">&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;">&lt;code class="language-bash" data-lang="bash">&lt;span style="display:flex;">&lt;span>sudo apt-get purge netfilter-persistent &lt;span style="color:#f92672">&amp;amp;&amp;amp;&lt;/span> sudo reboot
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>&lt;p>测试端口是否已经开放&lt;/p>
&lt;h2 id="附注">附注：&lt;/h2>
&lt;h3 id="强制删除规则">强制删除规则&lt;/h3>
&lt;div class="highlight">&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;">&lt;code class="language-bash" data-lang="bash">&lt;span style="display:flex;">&lt;span>sudo rm -rf /etc/iptables &lt;span style="color:#f92672">&amp;amp;&amp;amp;&lt;/span> sudo reboot
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>&lt;h3 id="删除oracle-cloud-agent防止甲骨文监控">删除oracle-cloud-agent，防止甲骨文监控&lt;/h3>
&lt;div class="highlight">&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;">&lt;code class="language-bash" data-lang="bash">&lt;span style="display:flex;">&lt;span>snap remove oracle-cloud-agent
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>&lt;h3 id="检查防火墙服务状态">检查防火墙服务状态&lt;/h3>
&lt;div class="highlight">&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;">&lt;code class="language-bash" data-lang="bash">&lt;span style="display:flex;">&lt;span>sudo systemctl status iptables.service
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>sudo systemctl status netfilter-persistent.service
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>&lt;h3 id="远程检测端口开放状态">远程检测端口开放状态&lt;/h3>
&lt;div class="highlight">&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;">&lt;code class="language-bash" data-lang="bash">&lt;span style="display:flex;">&lt;span>nmap ip或域名
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>&lt;h2 id="附注2开放指定端口">附注2(开放指定端口):&lt;/h2>
&lt;h3 id="iptables-开放指定端口">iptables 开放指定端口&lt;/h3>
&lt;div class="highlight">&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;">&lt;code class="language-bash" data-lang="bash">&lt;span style="display:flex;">&lt;span> iptables -I INPUT -p tcp --dport &lt;span style="color:#ae81ff">80&lt;/span> -j ACCEPT
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>&lt;p>中间的 80 为所需要开放的端口，tcp 为传输协议&lt;/p>
&lt;h4 id="保存规则">保存规则&lt;/h4>
&lt;div class="highlight">&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;">&lt;code class="language-bash" data-lang="bash">&lt;span style="display:flex;">&lt;span> iptables-save
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>&lt;p>上述命令我们就完成了开放指定的端口，但是如果此时服务器重启，上述规则就没有了，所以我们需要对规则进行一下持久化操作&lt;/p>
&lt;h3 id="安装-iptables-persistent">安装 iptables-persistent&lt;/h3>
&lt;div class="highlight">&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;">&lt;code class="language-bash" data-lang="bash">&lt;span style="display:flex;">&lt;span> sudo apt-get install iptables-persistent
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>&lt;h4 id="持久化规则">持久化规则&lt;/h4>
&lt;div class="highlight">&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;">&lt;code class="language-bash" data-lang="bash">&lt;span style="display:flex;">&lt;span> sudo netfilter-persistent save
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> sudo netfilter-persistent reload
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div></description></item><item><title>Docker 搭建MTProto协议上网</title><link>https://blog.baicai.me/article/2023/docker_mtg/</link><pubDate>Thu, 07 Sep 2023 18:00:43 +0800</pubDate><author>admin@baicai.me (白菜)</author><guid>https://blog.baicai.me/article/2023/docker_mtg/</guid><description>&lt;p>系统环境：
Debian系（其他系只需要更换apt为对应系统的软件包管理工具名称即可）&lt;/p>
&lt;h2 id="安装docker">安装Docker&lt;/h2>
&lt;h3 id="安装docker相关工具">安装Docker相关工具&lt;/h3>
&lt;div class="highlight">&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;">&lt;code class="language-bash" data-lang="bash">&lt;span style="display:flex;">&lt;span>sudo apt update &lt;span style="color:#f92672">&amp;amp;&amp;amp;&lt;/span> sudo apt -y upgrade &lt;span style="color:#f92672">&amp;amp;&amp;amp;&lt;/span> sudo apt install -y docker docker.io docker-compose
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>&lt;h3 id="启动docker">启动docker&lt;/h3>
&lt;div class="highlight">&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;">&lt;code class="language-bash" data-lang="bash">&lt;span style="display:flex;">&lt;span>sudo systemctl enable docker &lt;span style="color:#f92672">&amp;amp;&amp;amp;&lt;/span> sudo systemctl start docker
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>&lt;h3 id="验证是否安装成功">验证是否安装成功&lt;/h3>
&lt;div class="highlight">&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;">&lt;code class="language-bash" data-lang="bash">&lt;span style="display:flex;">&lt;span>sudo docker run hello-world
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>&lt;h2 id="mtg-v2版本-docker运行">mtg v2版本 docker运行&lt;/h2>
&lt;h3 id="生成密钥">生成密钥&lt;/h3>
&lt;div class="highlight">&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;">&lt;code class="language-bash" data-lang="bash">&lt;span style="display:flex;">&lt;span>sudo docker pull baicailin/mtg
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>sudo docker run --rm baicailin/mtg generate-secret --hex trade.aliexpress.com
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#75715e">#会看到一串ee开头的密钥，形如：&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>eexxx44f3762c8a97d14f89df8c0174726164652e616c69657870726573732e636f6d
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>&lt;h3 id="写入简单配置">写入简单配置&lt;/h3>
&lt;div class="highlight">&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;">&lt;code class="language-bash" data-lang="bash">&lt;span style="display:flex;">&lt;span>echo &lt;span style="color:#e6db74">&amp;#34;secret = \&amp;#34;把上面一步生成的密钥填进来\&amp;#34;&amp;#34;&lt;/span> &amp;gt;config.toml
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>echo &lt;span style="color:#e6db74">&amp;#34;bind-to = \&amp;#34;0.0.0.0:443\&amp;#34;&amp;#34;&lt;/span> &amp;gt;&amp;gt;config.toml
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>&lt;h3 id="运行docker镜像命令">运行docker镜像命令&lt;/h3>
&lt;div class="highlight">&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;">&lt;code class="language-bash" data-lang="bash">&lt;span style="display:flex;">&lt;span>sudo docker run -d -v $PWD/config.toml:/config.toml -p 443:443 --name baicai_mtg --restart&lt;span style="color:#f92672">=&lt;/span>unless-stopped baicailin/mtg
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>&lt;h3 id="docker-compose-启动可代替上面这个命令启动方式">docker-compose 启动（可代替上面这个命令启动方式）&lt;/h3>
&lt;p>一键启动 docker-compose.yaml 文件参考&lt;/p>
&lt;div class="highlight">&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;">&lt;code class="language-yaml" data-lang="yaml">&lt;span style="display:flex;">&lt;span>&lt;span style="color:#f92672">version&lt;/span>: &lt;span style="color:#e6db74">&amp;#34;3&amp;#34;&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#f92672">services&lt;/span>:
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#f92672">mtg_v2&lt;/span>:
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#f92672">image&lt;/span>: &lt;span style="color:#ae81ff">baicailin/mtg&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#f92672">container_name&lt;/span>: &lt;span style="color:#e6db74">&amp;#34;mtg_v2&amp;#34;&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#f92672">restart&lt;/span>: &lt;span style="color:#ae81ff">unless-stopped&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#f92672">command&lt;/span>: &lt;span style="color:#ae81ff">run /config.toml&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#f92672">volumes&lt;/span>:
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> - &lt;span style="color:#ae81ff">./config.toml:/config.toml&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#f92672">environment&lt;/span>:
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#f92672">TZ&lt;/span>: &lt;span style="color:#ae81ff">Asia/Shanghai&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#f92672">ports&lt;/span>:
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> - &lt;span style="color:#e6db74">&amp;#34;443:443&amp;#34;&lt;/span>
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>&lt;h3 id="生成mtproto协议服务配置">生成MTProto协议服务配置&lt;/h3>
&lt;div class="highlight">&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;">&lt;code class="language-bash" data-lang="bash">&lt;span style="display:flex;">&lt;span>sudo docker exec mtg_v2 /mtg access /config.toml
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>&lt;h2 id="mtg_v1-版本支持adtag-赞助选项运行">mtg_v1 版本(支持adtag 赞助选项)运行&lt;/h2>
&lt;p>生成密钥&lt;/p>
&lt;div class="highlight">&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;">&lt;code class="language-bash" data-lang="bash">&lt;span style="display:flex;">&lt;span>$ docker run --rm baicailin/mtg:1 generate-secret tls -c bing.com
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>eedf71035a8ed48a623d8e83e66aec4d0562696e672e636f6d
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>&lt;h3 id="docker-compose-启动可代替上面这个命令启动方式-1">docker-compose 启动（可代替上面这个命令启动方式）&lt;/h3>
&lt;p>一键启动 docker-compose.yaml 文件参考：&lt;/p>
&lt;div class="highlight">&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;">&lt;code class="language-yaml" data-lang="yaml">&lt;span style="display:flex;">&lt;span>&lt;span style="color:#f92672">version&lt;/span>: &lt;span style="color:#e6db74">&amp;#34;3&amp;#34;&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#f92672">services&lt;/span>:
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#f92672">mtg_v1&lt;/span>:
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#f92672">image&lt;/span>: &lt;span style="color:#ae81ff">baicailin/mtg:1&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#f92672">container_name&lt;/span>: &lt;span style="color:#e6db74">&amp;#34;mtg_v1&amp;#34;&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#f92672">restart&lt;/span>: &lt;span style="color:#ae81ff">unless-stopped&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#75715e"># deploy:&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#75715e"># resources:&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#75715e"># limits:&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#75715e"># cpus: 0.50&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#75715e"># memory: 256M&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#75715e"># reservations:&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#75715e"># memory: 128M&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#f92672">command&lt;/span>: &lt;span style="color:#ae81ff">run eedf71035a8ed48a623d8e83e66aec4d0562696e672e636f6d adtag&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#f92672">environment&lt;/span>:
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#f92672">TZ&lt;/span>: &lt;span style="color:#ae81ff">Asia/Shanghai&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#75715e"># MTG_DEBUG: &amp;#34;true&amp;#34;&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#75715e"># MTG_BIND: &amp;#34;0.0.0.0:3128&amp;#34;&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#75715e"># MTG_IPV4: &amp;#34;公网ip:端口&amp;#34;&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#75715e"># MTG_IPV6: &amp;#34;公网ip:端口&amp;#34;&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#75715e"># MTG_STATS_BIND: &amp;#34;127.0.0.1:3129&amp;#34;&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#75715e"># network_mode: host &lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#f92672">ports&lt;/span>:
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> - &lt;span style="color:#e6db74">&amp;#34;1443:3128&amp;#34;&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> - &lt;span style="color:#e6db74">&amp;#34;1444:3129&amp;#34;&lt;/span>
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>&lt;p>运行参数中的 &lt;code>adtag&lt;/code> 可以通过tg机器人 &lt;code>@MTProxybot&lt;/code> 创建获得&lt;/p>
&lt;h3 id="查看mtproto协议服务配置">查看MTProto协议服务配置&lt;/h3>
&lt;p>在mtg v1 docker-compose.yml文件目录下运行&lt;/p>
&lt;div class="highlight">&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;">&lt;code class="language-bash" data-lang="bash">&lt;span style="display:flex;">&lt;span>docker-compose logs
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div></description></item><item><title>docker golang:alpine CGO 制作镜像的正确姿势</title><link>https://blog.baicai.me/article/2023/docker_golang_alpine_cgo_build/</link><pubDate>Mon, 04 Sep 2023 23:23:09 +0800</pubDate><author>admin@baicai.me (白菜)</author><guid>https://blog.baicai.me/article/2023/docker_golang_alpine_cgo_build/</guid><description>&lt;p>当程序需要引入C/C++库（比如支持Sqlite数据库）的时候，编译环境需要打开CGO，否则打包完成后的程序就不能顺利运行（数据库初始化失败）。&lt;/p>
&lt;p>这时就需要安装 build-base 配置编译环境。&lt;/p>
&lt;p>参考 Dockerfile 如下：&lt;/p>
&lt;pre tabindex="0">&lt;code>FROM golang:alpine as builder
ENV CGO_ENABLED=1
WORKDIR /app
COPY . .
RUN apk add --no-cache --update git build-base
RUN go mod tidy \
&amp;amp;&amp;amp; go build -o api_client_linux ./cmd/api_client/
FROM alpine:latest as runner
ENV TZ=Asia/Shanghai
RUN apk --no-cache add ca-certificates tzdata libc6-compat libgcc libstdc++
WORKDIR /app
COPY --from=builder /app/api_client_linux .
VOLUME /app/conf
EXPOSE 8080
ENTRYPOINT [&amp;#34;./api_client_linux&amp;#34; ,&amp;#34;-c&amp;#34;,&amp;#34;/app/conf/config.yaml&amp;#34;]
&lt;/code>&lt;/pre>&lt;p>运行镜像我们也使用 Alpine ，由于 Alpine 极为精简，并没有常用的时区、证书等，会导致不可预料的错误。所以我们需要安装这些东西：&lt;/p>
&lt;table>
&lt;thead>
&lt;tr>
&lt;th style="text-align: left">包名&lt;/th>
&lt;th style="text-align: left">用途&lt;/th>
&lt;/tr>
&lt;/thead>
&lt;tbody>
&lt;tr>
&lt;td style="text-align: left">ca-certificates:&lt;/td>
&lt;td style="text-align: left">CA证书，使用TLS&lt;/td>
&lt;/tr>
&lt;tr>
&lt;td style="text-align: left">tzdata:&lt;/td>
&lt;td style="text-align: left">时区配置&lt;/td>
&lt;/tr>
&lt;tr>
&lt;td style="text-align: left">libc6-compat:&lt;/td>
&lt;td style="text-align: left">C 标准库&lt;/td>
&lt;/tr>
&lt;tr>
&lt;td style="text-align: left">libgcc:&lt;/td>
&lt;td style="text-align: left">GCC 相关库，CGO编译程序依赖&lt;/td>
&lt;/tr>
&lt;tr>
&lt;td style="text-align: left">libstdc++:&lt;/td>
&lt;td style="text-align: left">C++ 标准库&lt;/td>
&lt;/tr>
&lt;/tbody>
&lt;/table></description></item><item><title>网站迁移完成</title><link>https://blog.baicai.me/article/2023/blog_20230902/</link><pubDate>Sat, 02 Sep 2023 16:46:04 +0800</pubDate><author>admin@baicai.me (白菜)</author><guid>https://blog.baicai.me/article/2023/blog_20230902/</guid><description>&lt;p>实施：&lt;/p>
&lt;p>hugo + github action + git pages + cloudflare&lt;/p>
&lt;p>目前通过本地 vscode 写完日志后，直接推送到 github 私有仓库，通过 github action 生成静态内容自动推送到 github pages 仓库，完成部署。&lt;/p>
&lt;p>静态内容存放： github pages&lt;/p>
&lt;p>域名解析使用： cloudflare&lt;/p>
&lt;p>附注：&lt;/p>
&lt;p>github pages 自定义域名 解析设置（支持A记录）&lt;/p>
&lt;p>&lt;a href="https://docs.github.com/en/pages/configuring-a-custom-domain-for-your-github-pages-site/managing-a-custom-domain-for-your-github-pages-site">https://docs.github.com/en/pages/configuring-a-custom-domain-for-your-github-pages-site/managing-a-custom-domain-for-your-github-pages-site&lt;/a>&lt;/p></description></item><item><title>SSH使用ProxyCommand通过代理服务器远程连接其他服务器</title><link>https://blog.baicai.me/article/2023/ssh_proxycommand/</link><pubDate>Thu, 31 Aug 2023 12:12:33 +0800</pubDate><author>admin@baicai.me (白菜)</author><guid>https://blog.baicai.me/article/2023/ssh_proxycommand/</guid><description>&lt;p>OpenSSH的客户端有一个 ProxyCommand 的选项，用于 SSH 客户端与服务器之间的隧道通信(tunneling)。所谓的隧道技术，也称代理技术，是网络通信技术的一个普遍概念，就是把一条信道建立于另外一条信道之上。&lt;/p>
&lt;p>SSH 会话基于一个 TCP 连接，如果我们把连接的两个端口各自的出口（也即入口）进行截获，就可以用其它的信道来传输。而且 SSH 仍然认为它用的是和另一端连接一条 TCP 连接。&lt;/p>
&lt;p>ProxyCommand 指定一个命令（称为 Proxy），SSH 客户端将通过标准输入输出和这个命令启动后的进程进行正常的 SSH 通信，而 Proxy 连接着 SSH 服务器（一般是一个 Server Proxy，再由该 Server Proxy 连接服务器）。&lt;/p>
&lt;p>环境说明&lt;/p>
&lt;pre tabindex="0">&lt;code> 远程服务器的IP地址为 0.0.0.1，代号为X；
另一个远程服务器的IP为 0.0.0.2，代号为Y；
目前本机的IP地址为 0.0.0.3，代号为A，本地可以利用SSH客户端通过密钥或密码连接X和Y；
&lt;/code>&lt;/pre>&lt;p>这里全部使用密钥的方式进行访问，&lt;strong>本机 A 与 Y 之间无法进行访问&lt;/strong>。&lt;/p>
&lt;p>本地的
&lt;code>～/.ssh/config&lt;/code>
的配置文件信息如下，通过X连接到Y；&lt;/p>
&lt;div class="highlight">&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;">&lt;code class="language-bash" data-lang="bash">&lt;span style="display:flex;">&lt;span>Host X
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> HostName 0.0.0.1
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> User root
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> Port &lt;span style="color:#ae81ff">22&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> PreferredAuthentications publickey
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> IdentityFile ~/.ssh/id_rsa_1
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>Host Y
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> HostName 0.0.0.2
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> User root
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> Port &lt;span style="color:#ae81ff">22&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> PreferredAuthentications publickey
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> IdentityFile ~/.ssh/id_rsa_2
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>Host test
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> HostName 0.0.0.2
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> User root
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> Port &lt;span style="color:#ae81ff">22&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> IdentityFile ~/.ssh/id_rsa_2
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> ProxyCommand ssh X -W %h:%p
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>&lt;p>测试本机通过 X 连接到 Y 服务器&lt;/p>
&lt;div class="highlight">&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;">&lt;code class="language-bash" data-lang="bash">&lt;span style="display:flex;">&lt;span>ssh test
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>&lt;p>附注：&lt;/p>
&lt;div class="highlight">&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;">&lt;code class="language-bash" data-lang="bash">&lt;span style="display:flex;">&lt;span>-W host:port
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> Requests that standard input and output on the client be forwarded to host on port over the secure channel. Implies -N, -T, ExitOnForwardFailure and
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> ClearAllForwardings, though these can be overridden in the configuration file or using -o command line options.
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>-W：该参数在OpenSSH 5.4及之后的版本才支持，参考官方的Release信息；
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>在使用-W之前，通常都是使用nc选项，nc允许你转发TCP/UDP数据包到指定（备用）位置并且基本上与ssh -W相同；
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>&lt;p>参考：
&lt;a href="http://www.openssh.com/txt/release-5.4">openssh&lt;/a>&lt;/p></description></item><item><title>检查网络延时测试 URL 汇总，可用于软件测试延时</title><link>https://blog.baicai.me/article/2023/urltest-urltest/</link><pubDate>Mon, 28 Aug 2023 23:04:59 +0800</pubDate><author>admin@baicai.me (白菜)</author><guid>https://blog.baicai.me/article/2023/urltest-urltest/</guid><description>&lt;table>
&lt;thead>
&lt;tr>
&lt;th style="text-align: left">服务提供者&lt;/th>
&lt;th style="text-align: left">链接&lt;/th>
&lt;th style="text-align: center">大陆体验&lt;/th>
&lt;th style="text-align: center">境外体验&lt;/th>
&lt;th style="text-align: center">http/https&lt;/th>
&lt;th style="text-align: center">IP Version&lt;/th>
&lt;th style="text-align: left">备注&lt;/th>
&lt;/tr>
&lt;/thead>
&lt;tbody>
&lt;tr>
&lt;td style="text-align: left">Google&lt;/td>
&lt;td style="text-align: left">&lt;a href="http://www.gstatic.com/generate_204">http://www.gstatic.com/generate_204&lt;/a>&lt;/td>
&lt;td style="text-align: center">5&lt;/td>
&lt;td style="text-align: center">10&lt;/td>
&lt;td style="text-align: center">204/204&lt;/td>
&lt;td style="text-align: center">4+6&lt;/td>
&lt;td style="text-align: left">Google网络联通性测试地址&lt;/td>
&lt;/tr>
&lt;tr>
&lt;td style="text-align: left">Google&lt;/td>
&lt;td style="text-align: left">&lt;a href="http://www.google-analytics.com/generate_204">http://www.google-analytics.com/generate_204&lt;/a>&lt;/td>
&lt;td style="text-align: center">6&lt;/td>
&lt;td style="text-align: center">10&lt;/td>
&lt;td style="text-align: center">204/204&lt;/td>
&lt;td style="text-align: center">4+6&lt;/td>
&lt;td style="text-align: left">Google网络联通性测试地址&lt;/td>
&lt;/tr>
&lt;tr>
&lt;td style="text-align: left">Google&lt;/td>
&lt;td style="text-align: left">&lt;a href="http://www.google.com/generate_204">http://www.google.com/generate_204&lt;/a>&lt;/td>
&lt;td style="text-align: center">0&lt;/td>
&lt;td style="text-align: center">10&lt;/td>
&lt;td style="text-align: center">204/204&lt;/td>
&lt;td style="text-align: center">4+6&lt;/td>
&lt;td style="text-align: left">Google网络联通性测试地址&lt;/td>
&lt;/tr>
&lt;tr>
&lt;td style="text-align: left">Google&lt;/td>
&lt;td style="text-align: left">&lt;a href="http://connectivitycheck.gstatic.com/generate_204">http://connectivitycheck.gstatic.com/generate_204&lt;/a>&lt;/td>
&lt;td style="text-align: center">4&lt;/td>
&lt;td style="text-align: center">10&lt;/td>
&lt;td style="text-align: center">204/204&lt;/td>
&lt;td style="text-align: center">4+6&lt;/td>
&lt;td style="text-align: left">Google网络联通性测试地址&lt;/td>
&lt;/tr>
&lt;tr>
&lt;td style="text-align: left">Apple&lt;/td>
&lt;td style="text-align: left">&lt;a href="http://captive.apple.com">http://captive.apple.com&lt;/a>&lt;/td>
&lt;td style="text-align: center">3&lt;/td>
&lt;td style="text-align: center">10&lt;/td>
&lt;td style="text-align: center">200/200&lt;/td>
&lt;td style="text-align: center">4+6&lt;/td>
&lt;td style="text-align: left">苹果设备用于检测 Wi-Fi 是否需要认证登陆的链接&lt;/td>
&lt;/tr>
&lt;tr>
&lt;td style="text-align: left">Apple&lt;/td>
&lt;td style="text-align: left">&lt;a href="http://www.apple.com/library/test/success.html">http://www.apple.com/library/test/success.html&lt;/a>&lt;/td>
&lt;td style="text-align: center">7&lt;/td>
&lt;td style="text-align: center">10&lt;/td>
&lt;td style="text-align: center">200/200&lt;/td>
&lt;td style="text-align: center">4+6&lt;/td>
&lt;td style="text-align: left">苹果设备用于检测 Wi-Fi 是否需要认证登陆的链接&lt;/td>
&lt;/tr>
&lt;tr>
&lt;td style="text-align: left">MicroSoft&lt;/td>
&lt;td style="text-align: left">&lt;a href="http://www.msftconnecttest.com/connecttest.txt">http://www.msftconnecttest.com/connecttest.txt&lt;/a>&lt;/td>
&lt;td style="text-align: center">5&lt;/td>
&lt;td style="text-align: center">10&lt;/td>
&lt;td style="text-align: center">200/error&lt;/td>
&lt;td style="text-align: center">4&lt;/td>
&lt;td style="text-align: left">微软的网络联通性测试地址&lt;/td>
&lt;/tr>
&lt;tr>
&lt;td style="text-align: left">Cloudflare&lt;/td>
&lt;td style="text-align: left">&lt;a href="http://cp.cloudflare.com/generate_204">http://cp.cloudflare.com/generate_204&lt;/a>&lt;/td>
&lt;td style="text-align: center">4&lt;/td>
&lt;td style="text-align: center">10&lt;/td>
&lt;td style="text-align: center">204/204&lt;/td>
&lt;td style="text-align: center">4+6&lt;/td>
&lt;td style="text-align: left">Cloudflare的联通性测试地址&lt;/td>
&lt;/tr>
&lt;tr>
&lt;td style="text-align: left">Firefox&lt;/td>
&lt;td style="text-align: left">&lt;a href="http://detectportal.firefox.com/success.txt">http://detectportal.firefox.com/success.txt&lt;/a>&lt;/td>
&lt;td style="text-align: center">5&lt;/td>
&lt;td style="text-align: center">10&lt;/td>
&lt;td style="text-align: center">200/200&lt;/td>
&lt;td style="text-align: center">4+6&lt;/td>
&lt;td style="text-align: left">火狐的网络联通性测试地址&lt;/td>
&lt;/tr>
&lt;tr>
&lt;td style="text-align: left">V2ex&lt;/td>
&lt;td style="text-align: left">&lt;a href="http://www.v2ex.com/generate_204">http://www.v2ex.com/generate_204&lt;/a>&lt;/td>
&lt;td style="text-align: center">0&lt;/td>
&lt;td style="text-align: center">10&lt;/td>
&lt;td style="text-align: center">204/301&lt;/td>
&lt;td style="text-align: center">4+6&lt;/td>
&lt;td style="text-align: left">v2ex 的联通性测试地址&lt;/td>
&lt;/tr>
&lt;tr>
&lt;td style="text-align: left">小米&lt;/td>
&lt;td style="text-align: left">&lt;a href="http://connect.rom.miui.com/generate_204">http://connect.rom.miui.com/generate_204&lt;/a>&lt;/td>
&lt;td style="text-align: center">10&lt;/td>
&lt;td style="text-align: center">4&lt;/td>
&lt;td style="text-align: center">204/204&lt;/td>
&lt;td style="text-align: center">4&lt;/td>
&lt;td style="text-align: left">小米的联通性测试地址&lt;/td>
&lt;/tr>
&lt;tr>
&lt;td style="text-align: left">华为&lt;/td>
&lt;td style="text-align: left">&lt;a href="http://connectivitycheck.platform.hicloud.com/generate_204">http://connectivitycheck.platform.hicloud.com/generate_204&lt;/a>&lt;/td>
&lt;td style="text-align: center">10&lt;/td>
&lt;td style="text-align: center">5&lt;/td>
&lt;td style="text-align: center">204/204&lt;/td>
&lt;td style="text-align: center">4&lt;/td>
&lt;td style="text-align: left">华为的联通性测试地址&lt;/td>
&lt;/tr>
&lt;tr>
&lt;td style="text-align: left">Vivo&lt;/td>
&lt;td style="text-align: left">&lt;a href="http://wifi.vivo.com.cn/generate_204">http://wifi.vivo.com.cn/generate_204&lt;/a>&lt;/td>
&lt;td style="text-align: center">10&lt;/td>
&lt;td style="text-align: center">5&lt;/td>
&lt;td style="text-align: center">204/204&lt;/td>
&lt;td style="text-align: center">4&lt;/td>
&lt;td style="text-align: left">vivo 的联通性测试地址&lt;/td>
&lt;/tr>
&lt;/tbody>
&lt;/table>
&lt;p>以上大陆指中国大陆，境外指非中国大陆。&lt;/p>
&lt;p>体验目前仅进行粗略测试延迟，大概率实际不符，仅作参考。&lt;/p>
&lt;p>http/https一列表示使用指定协议进行请求，返回的状态码。部分场合对状态码要求较严格。&lt;/p></description></item><item><title>Hugo + GitHub Action + Github Pages，搭建博客自动发布</title><link>https://blog.baicai.me/article/2023/hugo_github_action_blog/</link><pubDate>Sun, 13 Aug 2023 11:31:48 +0800</pubDate><author>admin@baicai.me (白菜)</author><guid>https://blog.baicai.me/article/2023/hugo_github_action_blog/</guid><description>&lt;p>我的方案由以下两个核心部分：&lt;/p>
&lt;ul>
&lt;li>博客源仓库，对博客配置及所有文章 .md 源文件进行版本管理，配合 GitHub Action 进行自动化部署，自动生成静态站点推送到 GitHub Pages 博客发布仓库。&lt;/li>
&lt;li>GitHub Pages 博客发布仓库，使用 GitHub Pages 实现网站部署，可以通过域名 CNAME 解析使用自定义域名。&lt;/li>
&lt;/ul>
&lt;h2 id="使用-hugo-搭建博客">使用 Hugo 搭建博客&lt;/h2>
&lt;p>Hugo 是用 Go 实现的博客工具，采用 Markdown 进行文章编辑，生成静态站点文件，支持丰富的主题配置，也可以通过 js 嵌入像是评论系统等插件，高度定制化。除了 Hugo 外， 还有 Gatsby、Jekyll、Hexo、Ghost 等选择，实现和使用都差不多，可以根据自己的偏好进行选择。&lt;/p>
&lt;h3 id="安装-hugo">安装 Hugo&lt;/h3>
&lt;p>我使用的是 macOS，所以使用官方推荐的 homebrew 方式进行 hugo 程序的安装，其他系统可参考官方文档。&lt;/p>
&lt;div class="highlight">&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;">&lt;code class="language-bash" data-lang="bash">&lt;span style="display:flex;">&lt;span>brew install hugo
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>&lt;p>完成后，使用以下命令进行验证(查看版本号)：&lt;/p>
&lt;div class="highlight">&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;">&lt;code class="language-bash" data-lang="bash">&lt;span style="display:flex;">&lt;span>hugo version
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>&lt;h3 id="创建-hugo-网站">创建 Hugo 网站&lt;/h3>
&lt;div class="highlight">&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;">&lt;code class="language-bash" data-lang="bash">&lt;span style="display:flex;">&lt;span>hugo new site blog-demo
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>&lt;h3 id="配置主题">配置主题&lt;/h3>
&lt;p>创建我们的站点后，需要进行主题配置，Hugo 社区有很丰富的主题，可以通过官网 Themes 菜单选择自己喜欢的风格，查看预览效果，选择后可以进入主题项目仓库，一般都会有很详细的安装及配置说明。下面我就以我目前在使用的 smol 这个主题为例，演示一下配置流程。&lt;/p>
&lt;div class="highlight">&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;">&lt;code class="language-bash" data-lang="bash">&lt;span style="display:flex;">&lt;span>cd blog-demo
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>git clone git@github.com:colorchestra/smol.git themes/smol
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>cd themes/smol
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>rm -rf .git
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>&lt;p>初始化主题基础配置后，我们可以在 config.toml 文件中进行站点细节配置，具体配置项参考主题说明文档。&lt;/p>
&lt;p>参考config.toml内容&lt;/p>
&lt;div class="highlight">&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;">&lt;code class="language-toml" data-lang="toml">&lt;span style="display:flex;">&lt;span>&lt;span style="color:#a6e22e">theme&lt;/span> = &lt;span style="color:#e6db74">&amp;#34;smol&amp;#34;&lt;/span>
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>&lt;h3 id="发布新文章">发布新文章&lt;/h3>
&lt;pre tabindex="0">&lt;code>hugo new posts/blog-test.md
&lt;/code>&lt;/pre>&lt;h3 id="本地调试站点">本地调试站点&lt;/h3>
&lt;p>进行本地实时调试预览。&lt;/p>
&lt;div class="highlight">&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;">&lt;code class="language-bash" data-lang="bash">&lt;span style="display:flex;">&lt;span>hugo server
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>&lt;p>运行服务后，我们可以通过浏览器 http://localhost:1313 地址访问我们的本地预览网页。&lt;/p>
&lt;h2 id="github-pages-仓库">GITHUB PAGES 仓库&lt;/h2>
&lt;p>GitHub Pages 仓库建立完成后，可以在设置中配置自己注册的自定义域名来指向 GitHub Pages 生成的网址。此外，需要将博客站点配置文件 config.toml 中的 baseURL 改为自己的自定义域名。&lt;/p>
&lt;h3 id="github-pages-发布博客">GitHub Pages 发布博客&lt;/h3>
&lt;p>我们现在已经可以通过自定义域名来访问我们的 GitHub Pages 页面了，目前因为项目仓库是空的，访问后会报 404 页面。&lt;/p>
&lt;p>Hugo 生成的静态网站通过 GitHub Pages 服务进行托管，因此我们需要上传 Hugo 生成的静态网页文件至 GitHub Page 项目仓库。&lt;/p>
&lt;h3 id="手动发布">手动发布&lt;/h3>
&lt;div class="highlight">&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;">&lt;code class="language-bash" data-lang="bash">&lt;span style="display:flex;">&lt;span>hugo
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>cd public
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>&lt;p>Hugo 默认会将生成的静态网页文件存放在 public/ 目录下，我们可以通过将 public/ 目录初始化为 git 仓库并关联我们的 clin003/blog_html 远程仓库来推送我们的网页静态文件。&lt;/p>
&lt;div class="highlight">&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;">&lt;code class="language-bash" data-lang="bash">&lt;span style="display:flex;">&lt;span>git init
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>git remote add origin git@github.com:baicaime/meBlog
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>git add .
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>git commit -m &lt;span style="color:#e6db74">&amp;#34;debug&amp;#34;&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>git push origin main
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>&lt;p>推送到 GitHub Pages 仓库，稍等几分钟即可通过我们的自定义域名来访问我们的博客站点了，和&lt;/p>
&lt;div class="highlight">&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;">&lt;code class="language-bash" data-lang="bash">&lt;span style="display:flex;">&lt;span>hugo server
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>&lt;p>本地调试完全一致。&lt;/p>
&lt;h3 id="自动发布">自动发布&lt;/h3>
&lt;p>因为我们的博客基于 GitHub 与 GitHub Pages，可以通过官方提供的 GitHub Action 进行 CI 自动发布。
GitHub Action 是一个持续集成和持续交付(CI/CD) 平台，可用于自动执行构建、测试和部署管道，可以通过简单的配置即可直接使用。&lt;/p>
&lt;p>配置在仓库目录
&lt;code>.github/workflows&lt;/code>
下，以 .yml 为后缀。我的 GitHub Action 配置为
&lt;code>deploy.yml&lt;/code>
自动发布示例配置如下：&lt;/p>
&lt;div class="highlight">&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;">&lt;code class="language-yaml" data-lang="yaml">&lt;span style="display:flex;">&lt;span>&lt;span style="color:#f92672">name&lt;/span>: &lt;span style="color:#ae81ff">Deploy Hugo site to Pages&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#f92672">on&lt;/span>:
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#f92672">push&lt;/span>:
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#f92672">branches&lt;/span>: [ &lt;span style="color:#e6db74">&amp;#34;main&amp;#34;&lt;/span> ]
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#f92672">workflow_dispatch&lt;/span>:
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#f92672">permissions&lt;/span>:
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#f92672">contents&lt;/span>: &lt;span style="color:#ae81ff">read&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#f92672">pages&lt;/span>: &lt;span style="color:#ae81ff">write&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#f92672">id-token&lt;/span>: &lt;span style="color:#ae81ff">write&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#f92672">defaults&lt;/span>:
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#f92672">run&lt;/span>:
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#f92672">shell&lt;/span>: &lt;span style="color:#ae81ff">bash&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#f92672">env&lt;/span>:
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#f92672">NAME&lt;/span>: &lt;span style="color:#ae81ff">BLOG_push&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#75715e"># 推送目标仓库 格式 用户名/仓库名&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#f92672">TARGET_REPOSITORY_NAME&lt;/span>: &lt;span style="color:#ae81ff">baicaime/meBlog&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#75715e"># 同步临时目录(可选)&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#f92672">CLONE_DIR&lt;/span>: &lt;span style="color:#ae81ff">tmp_public&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#75715e"># 构建临时目录(可选)&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#f92672">BUILD_DIR&lt;/span>: &lt;span style="color:#ae81ff">tmp_build&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#75715e"># 配置git用户名&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#f92672">GIT_USERNAME&lt;/span>: &lt;span style="color:#ae81ff">baicaime&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#f92672">jobs&lt;/span>:
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#75715e"># This workflow contains a single job called &amp;#34;build&amp;#34;&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#f92672">build&lt;/span>:
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#f92672">runs-on&lt;/span>: &lt;span style="color:#ae81ff">ubuntu-latest&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#f92672">env&lt;/span>:
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#f92672">HUGO_VERSION&lt;/span>: &lt;span style="color:#ae81ff">0.117.0&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#f92672">steps&lt;/span>:
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> - &lt;span style="color:#f92672">name&lt;/span>: &lt;span style="color:#ae81ff">Install Hugo CLI&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#f92672">run&lt;/span>: |&lt;span style="color:#e6db74">
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#e6db74"> wget -O ${{ runner.temp }}/hugo.deb https://github.com/gohugoio/hugo/releases/download/v${HUGO_VERSION}/hugo_extended_${HUGO_VERSION}_linux-amd64.deb \
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#e6db74"> &amp;amp;&amp;amp; sudo dpkg -i ${{ runner.temp }}/hugo.deb&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> - &lt;span style="color:#f92672">uses&lt;/span>: &lt;span style="color:#ae81ff">actions/checkout@v3&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> - &lt;span style="color:#f92672">name&lt;/span>: &lt;span style="color:#ae81ff">Build with Hugo&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#f92672">env&lt;/span>:
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#75715e"># For maximum backward compatibility with Hugo modules&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#f92672">HUGO_ENVIRONMENT&lt;/span>: &lt;span style="color:#ae81ff">production&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#f92672">HUGO_ENV&lt;/span>: &lt;span style="color:#ae81ff">production&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#f92672">run&lt;/span>: |&lt;span style="color:#e6db74">
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#e6db74"> hugo \
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#e6db74"> --minify \
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#e6db74"> --baseURL &amp;#34;${{ steps.pages.outputs.base_url }}/&amp;#34; \
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#e6db74"> -d ${{ env.BUILD_DIR }}&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> - &lt;span style="color:#f92672">name&lt;/span>: &lt;span style="color:#ae81ff">Git Config&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#f92672">run&lt;/span>: |&lt;span style="color:#e6db74">
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#e6db74"> git config --global user.email &amp;#34;actions-push-noreply@baicai.me&amp;#34;
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#e6db74"> git config --global user.name &amp;#34;${{ env.GIT_USERNAME }}&amp;#34;
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#e6db74"> echo &amp;#34;配置git完成&amp;#34;&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> - &lt;span style="color:#f92672">name&lt;/span>: &lt;span style="color:#ae81ff">Git clone&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#f92672">run&lt;/span>: |&lt;span style="color:#e6db74">
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#e6db74"> echo &amp;#34;同步目标仓库(开始)&amp;#34;
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#e6db74"> git clone --depth 1 https://github.com/${{ env.TARGET_REPOSITORY_NAME }}.git ${{ env.CLONE_DIR }} &amp;amp;&amp;gt; /dev/null
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#e6db74"> echo &amp;#34;同步目标仓库(完成)&amp;#34;&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> - &lt;span style="color:#f92672">name&lt;/span>: &lt;span style="color:#ae81ff">Git push&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#f92672">run&lt;/span>: |&lt;span style="color:#e6db74">
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#e6db74"> cp -rf ${{ env.BUILD_DIR }}/* ${{ env.CLONE_DIR }}/
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#e6db74"> cd ${{ env.CLONE_DIR }}
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#e6db74"> echo &amp;#34;${{ github.event.head_commit.message }} `date +%FT%T%z`&amp;#34; &amp;gt; _pub_time.html
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#e6db74"> git add .
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#e6db74"> git commit --message &amp;#34;Update ${{ env.NAME }} from ${{ env.TARGET_REPOSITORY_NAME }} ${{ github.event.head_commit.message }}&amp;#34;
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#e6db74"> git push -f -q https://oauth2:${{ secrets.GIT_TOKEN }}@github.com/${{ env.TARGET_REPOSITORY_NAME }}.git main
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#e6db74"> echo &amp;#34;git push ${{ env.TARGET_REPOSITORY_NAME }} (完成)&amp;#34;&lt;/span>
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>&lt;p>on 表示 GitHub Action 触发条件，我设置了 push 和 workflow_dispatch 两个条件：&lt;/p>
&lt;ul>
&lt;li>push，当这个项目仓库发生推送动作后，执行 GitHub Action&lt;/li>
&lt;li>workflow_dispatch，可以在 GitHub 项目仓库的 Action 工具栏进行手动调用&lt;/li>
&lt;/ul>
&lt;p>jobs 表示 GitHub Action 中的任务，我们设置了一个 build 任务，
runs-on 表示 GitHub Action 运行环境，我们选择了 ubuntu-latest。
build 任务包含了 Install Hugo CLI 、Checkout、Build with Hugo、Git Config、Git clone 和 Git push 六个主要步骤，
其中 run 是执行的命令，uses 是 GitHub Action 中的一个插件，我们使用了 actions/checkout 这个插件。
其中 Checkout 步骤中，可以在 with 中配置 submodules 值为 true 同步博客源仓库的子模块（比如主题模块，由于我们没有使用子模块方式安装hugo主题，所以不需要这个参数）。&lt;/p>
&lt;h4 id="需要将上述-deployyml-中">需要将上述 deploy.yml 中：&lt;/h4>
&lt;pre>&lt;code>TARGET_REPOSITORY_NAME 改为自己的 GitHub Pages 仓库，如我的设置为 baicaime/meBlog
GIT_USERNAME 改为自己 GitHub Pages 仓库的用户名
&lt;/code>&lt;/pre>
&lt;p>因为我们需要从博客仓库推送到外部 GitHub Pages 仓库，需要特定权限，要在 GitHub 账户下 &lt;a href="https://github.com/settings/tokens?type=beta">Setting - Developer setting - Personal access tokens&lt;/a> 下创建一个 Token。&lt;/p>
&lt;p>权限需要：&lt;/p>
&lt;pre>&lt;code>Contents read/write
&lt;/code>&lt;/pre>
&lt;p>
&lt;figure>
&lt;img src="https://blog.baicai.me/posts/2023/0813/hugo_github_token.png" alt="Contents read/write" />
&lt;/figure>
&lt;/p>
&lt;p>配置后复制生成的 Token（注：只会出现一次），然后在博客源仓库的&lt;/p>
&lt;pre tabindex="0">&lt;code>Settings - secrets and variables - Actions
&lt;/code>&lt;/pre>&lt;p>中添加&lt;/p>
&lt;pre tabindex="0">&lt;code>GIT_TOKEN
&lt;/code>&lt;/pre>&lt;p>环境变量为刚才的 Token，这样 GitHub Action 就可以获取到 Token 了。&lt;/p>
&lt;h4 id="推送测试">推送测试&lt;/h4>
&lt;p>完成上述配置后，推送代码至仓库，即可触发 GitHub Action，自动生成博客页面并推送至 GitHub Pages 仓库。&lt;/p>
&lt;p>GitHub Pages 仓库更新后，又会自动触发官方页面部署 CI，实现网站发布。&lt;/p>
&lt;p>现在每当我们本地通过熟悉的 Markdown 语法完成博客内容编辑后，只需要推送代码，等待几分钟，即可通过我们的自定义域名访问更新后的网站。&lt;/p>
&lt;p>以上就是我通过 Hugo 与 GitHub Action 实现的博客自动部署系统，我自己的实现仓库在 &lt;a href="https://github.com/baicaime/meBlog">baicaime/meBlog&lt;/a> 仓库中&lt;/p></description></item><item><title>从 Debian 11 升级到 Debian 12</title><link>https://blog.baicai.me/article/2023/upgrading-debian-from-bullseye-to-bookworm/</link><pubDate>Tue, 13 Jun 2023 21:27:52 +0800</pubDate><author>admin@baicai.me (白菜)</author><guid>https://blog.baicai.me/article/2023/upgrading-debian-from-bullseye-to-bookworm/</guid><description>&lt;p>如果有必要，可以查阅(Debian 12 发行说明)[https://www.debian.org/releases/stable/releasenotes]，内附详细的升级和错误处理指南。&lt;/p>
&lt;h2 id="准备工作">准备工作&lt;/h2>
&lt;p>一定要备份重要数据！&lt;/p>
&lt;p>以下操作需要在 root 用户下完成，请使用 sudo -i 或 su root 切换到 root 用户进行操作&lt;/p>
&lt;p>Debian 软件源一般以发行代号如：bullseye、bookworm 引用，但是也可能使用状态名如：stable、unstable、testing 引用。在 Debian 12 稳定版正式发布后，stable 就会从 bullseye 指向 bookworm 了。&lt;/p>
&lt;p>检查软件源，确保下面的输出为空，否则请手动更改软件源为 bullseye&lt;/p>
&lt;div class="highlight">&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;">&lt;code class="language-bash" data-lang="bash">&lt;span style="display:flex;">&lt;span>cat /etc/apt/sources.list | grep stable
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>&lt;p>更新 apt 源，替换 bullseye 为 bookworm：&lt;/p>
&lt;div class="highlight">&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;">&lt;code class="language-bash" data-lang="bash">&lt;span style="display:flex;">&lt;span>sed -i &lt;span style="color:#e6db74">&amp;#39;s/bullseye/bookworm/g&amp;#39;&lt;/span> /etc/apt/sources.list
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>sed -i &lt;span style="color:#e6db74">&amp;#39;s/bullseye/bookworm/g&amp;#39;&lt;/span> /etc/apt/sources.list.d/*.list
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>&lt;p>对于 Debian 12 以后的版本，所有 Debian 可以分发的打包的非自由固件二进制文件（non-free），比如某些驱动，都被转移到 Debian Archive 中的一个新组件，称为非自由固件（non-free-firmware）。如果您从旧版的 Debian 升级，并且需要这些固件二进制文件，您应该更新您系统上的 /etc/apt/sources.list，以使用这个新组件（来源）：&lt;/p>
&lt;div class="highlight">&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;">&lt;code class="language-bash" data-lang="bash">&lt;span style="display:flex;">&lt;span>sed -i &lt;span style="color:#e6db74">&amp;#39;s/non-free/non-free non-free-firmware/g&amp;#39;&lt;/span> /etc/apt/sources.list
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>&lt;p>默认的系统 apt 源文件 /etc/apt/sources.list 应该是类似这样的：&lt;/p>
&lt;pre tabindex="0">&lt;code>deb http://deb.debian.org/debian bookworm main contrib non-free non-free-firmware
deb-src http://deb.debian.org/debian bookworm main contrib non-free non-free-firmware
deb http://security.debian.org/debian-security bookworm-security main contrib non-free non-free-firmware
deb-src http://security.debian.org/debian-security bookworm-security main contrib non-free non-free-firmware
deb http://deb.debian.org/debian bookworm-updates main contrib non-free non-free-firmware
deb-src http://deb.debian.org/debian bookworm-updates main contrib non-free non-free-firmware
&lt;/code>&lt;/pre>&lt;h2 id="开始升级">开始升级&lt;/h2>
&lt;p>更新软件源&lt;/p>
&lt;div class="highlight">&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;">&lt;code class="language-bash" data-lang="bash">&lt;span style="display:flex;">&lt;span>sudo apt update
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>&lt;p>先进行最小系统升级&lt;/p>
&lt;div class="highlight">&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;">&lt;code class="language-bash" data-lang="bash">&lt;span style="display:flex;">&lt;span>sudo apt upgrade --without-new-pkgs
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>&lt;p>没问题的话开始进行全面升级，会下载好几百 MB 文件，下载速度取决于服务器网络带宽&lt;/p>
&lt;div class="highlight">&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;">&lt;code class="language-bash" data-lang="bash">&lt;span style="display:flex;">&lt;span>sudo apt full-upgrade
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>&lt;p>如果修改过 SSH 配置文件，出现提示时，请选择保留本地配置&lt;/p>
&lt;p>更新过程种会提示一些软件是否需要自动重启，选 Yes 即可，以及一些软件的配置文件是否需要更新，按照自己的情况选择即可，默认回车即视为使用旧的配置文件，一般会出现在 OpenSSH 等软件的更新上。&lt;/p>
&lt;p>在 apt-listchanges: News 界面可以按 q 退出：&lt;/p>
&lt;p>全面升级结束后，重新启动&lt;/p>
&lt;div class="highlight">&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;">&lt;code class="language-bash" data-lang="bash">&lt;span style="display:flex;">&lt;span>sudo reboot
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>&lt;p>更新后删除不必要的软件和依赖：&lt;/p>
&lt;div class="highlight">&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;">&lt;code class="language-bash" data-lang="bash">&lt;span style="display:flex;">&lt;span>apt autoclean
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>apt autoremove -y
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>&lt;p>查看最新的系统版本：&lt;/p>
&lt;div class="highlight">&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;">&lt;code class="language-bash" data-lang="bash">&lt;span style="display:flex;">&lt;span>cat /etc/debian_version
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>lsb_release -a
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>uname -a
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>&lt;h2 id="升级之后">升级之后&lt;/h2>
&lt;p>列出已删除的软件包&lt;/p>
&lt;div class="highlight">&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;">&lt;code class="language-bash" data-lang="bash">&lt;span style="display:flex;">&lt;span>apt list &lt;span style="color:#e6db74">&amp;#39;~c&amp;#39;&lt;/span>
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>&lt;p>清理已删除的软件包&lt;/p>
&lt;div class="highlight">&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;">&lt;code class="language-bash" data-lang="bash">&lt;span style="display:flex;">&lt;span>sudo apt purge &lt;span style="color:#e6db74">&amp;#39;~c&amp;#39;&lt;/span>
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div></description></item><item><title>Linux 命令</title><link>https://blog.baicai.me/article/2023/linux_cmd_list/</link><pubDate>Mon, 10 Apr 2023 17:53:52 +0800</pubDate><author>admin@baicai.me (白菜)</author><guid>https://blog.baicai.me/article/2023/linux_cmd_list/</guid><description>&lt;h2 id="基本命令">基本命令&lt;/h2>
&lt;pre>&lt;code>uname -m 显示机器的处理器架构
uname -r 显示正在使用的内核版本
dmidecode -q 显示硬件系统部件
(SMBIOS / DMI) hdparm -i /dev/hda 罗列一个磁盘的架构特性
hdparm -tT /dev/sda 在磁盘上执行测试性读取操作系统信息
arch 显示机器的处理器架构
uname -m 显示机器的处理器架构
uname -r 显示正在使用的内核版本
dmidecode -q 显示硬件系统部件 - (SMBIOS / DMI)
hdparm -i /dev/hda 罗列一个磁盘的架构特性
hdparm -tT /dev/sda 在磁盘上执行测试性读取操作
cat /proc/cpuinfo 显示CPU info的信息
cat /proc/interrupts 显示中断
cat /proc/meminfo 校验内存使用
cat /proc/swaps 显示哪些swap被使用
cat /proc/version 显示内核的版本
cat /proc/net/dev 显示网络适配器及统计
cat /proc/mounts 显示已加载的文件系统
lspci -tv 罗列 PCI 设备
lsusb -tv 显示 USB 设备
date 显示系统日期
cal 2007 显示2007年的日历表
date 041217002007.00 设置日期和时间 - 月日时分年.秒
clock -w 将时间修改保存到 BIOS
&lt;/code>&lt;/pre>
&lt;h2 id="关机">关机&lt;/h2>
&lt;pre>&lt;code>shutdown -h now 关闭系统(1)
init 0 关闭系统(2)
telinit 0 关闭系统(3)
shutdown -h hours:minutes &amp;amp; 按预定时间关闭系统
shutdown -c 取消按预定时间关闭系统
shutdown -r now 重启(1)
reboot 重启(2)
logout 注销
&lt;/code>&lt;/pre>
&lt;h2 id="文件和目录">文件和目录&lt;/h2>
&lt;pre>&lt;code>cd /home 进入 '/ home' 目录'
cd .. 返回上一级目录
cd ../.. 返回上两级目录
cd 进入个人的主目录
cd ~user1 进入个人的主目录
cd - 返回上次所在的目录
pwd 显示工作路径
ls 查看目录中的文件
ls -F 查看目录中的文件
ls -l 显示文件和目录的详细资料
ls -a 显示隐藏文件
ls *[0-9]* 显示包含数字的文件名和目录名
tree 显示文件和目录由根目录开始的树形结构(1)
lstree 显示文件和目录由根目录开始的树形结构(2)
mkdir dir1 创建一个叫做 'dir1' 的目录'
mkdir dir1 dir2 同时创建两个目录
mkdir -p /tmp/dir1/dir2 创建一个目录树
rm -f file1 删除一个叫做 'file1' 的文件'
rmdir dir1 删除一个叫做 'dir1' 的目录'
rm -rf dir1 删除一个叫做 'dir1' 的目录并同时删除其内容
rm -rf dir1 dir2 同时删除两个目录及它们的内容
mv dir1 new_dir 重命名/移动 一个目录
cp file1 file2 复制一个文件
cp dir/* . 复制一个目录下的所有文件到当前工作目录
cp -a /tmp/dir1 . 复制一个目录到当前工作目录
cp -a dir1 dir2 复制一个目录
ln -s file1 lnk1 创建一个指向文件或目录的软链接
ln file1 lnk1 创建一个指向文件或目录的物理链接
touch -t 0712250000 file1 修改一个文件或目录的时间戳 - (YYMMDDhhmm)
file file1 outputs the mime type of the file as text
iconv -l 列出已知的编码
iconv -f fromEncoding -t toEncoding inputFile &amp;gt; outputFile creates a new from the given input file by assuming it is encoded in fromEncoding and converting it to toEncoding.
find . -maxdepth 1 -name *.jpg -print -exec convert &amp;quot;{}&amp;quot; -resize 80x60 &amp;quot;thumbs/{}&amp;quot; \; batch resize files in the current directory and send them to a thumbnails directory (requires convert from Imagemagick)
&lt;/code>&lt;/pre>
&lt;h2 id="文件搜索">文件搜索&lt;/h2>
&lt;pre>&lt;code>find / -name file1 从 '/' 开始进入根文件系统搜索文件和目录
find / -user user1 搜索属于用户 'user1' 的文件和目录
find /home/user1 -name \*.bin 在目录 '/ home/user1' 中搜索带有'.bin' 结尾的文件
find /usr/bin -type f -atime +100 搜索在过去100天内未被使用过的执行文件
find /usr/bin -type f -mtime -10 搜索在10天内被创建或者修改过的文件
find / -name \*.rpm -exec chmod 755 '{}' \; 搜索以 '.rpm' 结尾的文件并定义其权限
find / -xdev -name \*.rpm 搜索以 '.rpm' 结尾的文件，忽略光驱、捷盘等可移动设备
locate \*.ps 寻找以 '.ps' 结尾的文件 - 先运行 'updatedb' 命令
whereis halt 显示一个二进制文件、源码或man的位置
which halt 显示一个二进制文件或可执行文件的完整路径
&lt;/code>&lt;/pre>
&lt;h2 id="挂载一个文件系统">挂载一个文件系统&lt;/h2>
&lt;pre>&lt;code>mount /dev/hda2 /mnt/hda2 挂载一个叫做hda2的盘 - 确定目录 '/ mnt/hda2' 已经存在
umount /dev/hda2 卸载一个叫做hda2的盘 - 先从挂载点 '/ mnt/hda2' 退出
fuser -km /mnt/hda2 当设备繁忙时强制卸载
umount -n /mnt/hda2 运行卸载操作而不写入 /etc/mtab 文件- 当文件为只读或当磁盘写满时非常有用
mount /dev/fd0 /mnt/floppy 挂载一个软盘
mount /dev/cdrom /mnt/cdrom 挂载一个cdrom或dvdrom
mount /dev/hdc /mnt/cdrecorder 挂载一个cdrw或dvdrom
mount /dev/hdb /mnt/cdrecorder 挂载一个cdrw或dvdrom
mount -o loop file.iso /mnt/cdrom 挂载一个文件或ISO镜像文件
mount -t vfat /dev/hda5 /mnt/hda5 挂载一个Windows FAT32文件系统
mount /dev/sda1 /mnt/usbdisk 挂载一个usb 捷盘或闪存设备
mount -t smbfs -o username=user,password=pass //WinClient/share /mnt/share 挂载一个windows网络共享
&lt;/code>&lt;/pre>
&lt;h2 id="磁盘空间">磁盘空间&lt;/h2>
&lt;pre>&lt;code>df -h 显示已经挂载的分区列表
ls -lSr |more 以尺寸大小排列文件和目录
du -sh dir1 估算目录 'dir1' 已经使用的磁盘空间'
du -sk * | sort -rn 以容量大小为依据依次显示文件和目录的大小
rpm -q -a --qf '%10{SIZE}t%{NAME}n' | sort -k1,1n 以大小为依据依次显示已安装的rpm包所使用的空间 (fedora, redhat类系统)
dpkg-query -W -f='${Installed-Size;10}t${Package}n' | sort -k1,1n 以大小为依据显示已安装的deb包所使用的空间 (ubuntu, debian类系统)
&lt;/code>&lt;/pre>
&lt;h2 id="用户和群组">用户和群组&lt;/h2>
&lt;pre>&lt;code>groupadd group_name 创建一个新用户组
groupdel group_name 删除一个用户组
groupmod -n new_group_name old_group_name 重命名一个用户组
useradd -c &amp;quot;Name Surname &amp;quot; -g admin -d /home/user1 -s /bin/bash user1 创建一个属于 &amp;quot;admin&amp;quot; 用户组的用户
useradd user1 创建一个新用户
userdel -r user1 删除一个用户 ( '-r' 排除主目录)
usermod -c &amp;quot;User FTP&amp;quot; -g system -d /ftp/user1 -s /bin/nologin user1 修改用户属性
passwd 修改口令
passwd user1 修改一个用户的口令 (只允许root执行)
chage -E 2005-12-31 user1 设置用户口令的失效期限
pwck 检查 '/etc/passwd' 的文件格式和语法修正以及存在的用户
grpck 检查 '/etc/passwd' 的文件格式和语法修正以及存在的群组
newgrp group_name 登陆进一个新的群组以改变新创建文件的预设群组
&lt;/code>&lt;/pre>
&lt;h2 id="文件的权限使用设置权限使用-用于取消">文件的权限，使用“+”设置权限，使用“-”用于取消&lt;/h2>
&lt;pre>&lt;code>chattr +a file1 只允许以追加方式读写文件
chattr +c file1 允许这个文件能被内核自动压缩/解压
chattr +d file1 在进行文件系统备份时，dump程序将忽略这个文件
chattr +i file1 设置成不可变的文件，不能被删除、修改、重命名或者链接
chattr +s file1 允许一个文件被安全地删除
chattr +S file1 一旦应用程序对这个文件执行了写操作，使系统立刻把修改的结果写到磁盘
chattr +u file1 若文件被删除，系统会允许你在以后恢复这个被删除的文件
lsattr 显示特殊的属性
&lt;/code>&lt;/pre>
&lt;h2 id="文件的特殊属性-使用--设置权限使用---用于取消">文件的特殊属性 ，使用 “+” 设置权限，使用 “-” 用于取消&lt;/h2>
&lt;pre>&lt;code>chattr +a file1 只允许以追加方式读写文件
chattr +c file1 允许这个文件能被内核自动压缩/解压
chattr +d file1 在进行文件系统备份时，dump程序将忽略这个文件
chattr +i file1 设置成不可变的文件，不能被删除、修改、重命名或者链接
chattr +s file1 允许一个文件被安全地删除
chattr +S file1 一旦应用程序对这个文件执行了写操作，使系统立刻把修改的结果写到磁盘
chattr +u file1 若文件被删除，系统会允许你在以后恢复这个被删除的文件
lsattr 显示特殊的属性
&lt;/code>&lt;/pre>
&lt;h2 id="打包和压缩文件">打包和压缩文件&lt;/h2>
&lt;pre>&lt;code>bunzip2 file1.bz2 解压一个叫做 'file1.bz2'的文件
bzip2 file1 压缩一个叫做 'file1' 的文件
gunzip file1.gz 解压一个叫做 'file1.gz'的文件
gzip file1 压缩一个叫做 'file1'的文件
gzip -9 file1 最大程度压缩
rar a file1.rar test_file 创建一个叫做 'file1.rar' 的包
rar a file1.rar file1 file2 dir1 同时压缩 'file1', 'file2' 以及目录 'dir1'
rar x file1.rar 解压rar包
unrar x file1.rar 解压rar包
tar -cvf archive.tar file1 创建一个非压缩的 tarball
tar -cvf archive.tar file1 file2 dir1 创建一个包含了 'file1', 'file2' 以及 'dir1'的档案文件
tar -tf archive.tar 显示一个包中的内容
tar -xvf archive.tar 释放一个包
tar -xvf archive.tar -C /tmp 将压缩包释放到 /tmp目录下
tar -cvfj archive.tar.bz2 dir1 创建一个bzip2格式的压缩包
tar -xvfj archive.tar.bz2 解压一个bzip2格式的压缩包
tar -cvfz archive.tar.gz dir1 创建一个gzip格式的压缩包
tar -xvfz archive.tar.gz 解压一个gzip格式的压缩包
zip file1.zip file1 创建一个zip格式的压缩包
zip -r file1.zip file1 file2 dir1 将几个文件和目录同时压缩成一个zip格式的压缩包
unzip file1.zip 解压一个zip格式压缩包
&lt;/code>&lt;/pre>
&lt;h2 id="rpm-包">RPM 包&lt;/h2>
&lt;pre>&lt;code>rpm -ivh package.rpm 安装一个rpm包
rpm -ivh --nodeeps package.rpm 安装一个rpm包而忽略依赖关系警告
rpm -U package.rpm 更新一个rpm包但不改变其配置文件
rpm -F package.rpm 更新一个确定已经安装的rpm包
rpm -e package_name.rpm 删除一个rpm包
rpm -qa 显示系统中所有已经安装的rpm包
rpm -qa | grep httpd 显示所有名称中包含 &amp;quot;httpd&amp;quot; 字样的rpm包
rpm -qi package_name 获取一个已安装包的特殊信息
rpm -qg &amp;quot;System Environment/Daemons&amp;quot; 显示一个组件的rpm包
rpm -ql package_name 显示一个已经安装的rpm包提供的文件列表
rpm -qc package_name 显示一个已经安装的rpm包提供的配置文件列表
rpm -q package_name --whatrequires 显示与一个rpm包存在依赖关系的列表
rpm -q package_name --whatprovides 显示一个rpm包所占的体积
rpm -q package_name --scripts 显示在安装/删除期间所执行的脚本l
rpm -q package_name --changelog 显示一个rpm包的修改历史
rpm -qf /etc/httpd/conf/httpd.conf 确认所给的文件由哪个rpm包所提供
rpm -qp package.rpm -l 显示由一个尚未安装的rpm包提供的文件列表
rpm --import /media/cdrom/RPM-GPG-KEY 导入公钥数字证书
rpm --checksig package.rpm 确认一个rpm包的完整性
rpm -qa gpg-pubkey 确认已安装的所有rpm包的完整性
rpm -V package_name 检查文件尺寸、 许可、类型、所有者、群组、MD5检查以及最后修改时间
rpm -Va 检查系统中所有已安装的rpm包- 小心使用
rpm -Vp package.rpm 确认一个rpm包还未安装
rpm2cpio package.rpm | cpio --extract --make-directories *bin* 从一个rpm包运行可执行文件
rpm -ivh /usr/src/redhat/RPMS/`arch`/package.rpm 从一个rpm源码安装一个构建好的包
rpmbuild --rebuild package_name.src.rpm 从一个rpm源码构建一个 rpm 包
&lt;/code>&lt;/pre>
&lt;h2 id="yum-软件包升级器">YUM 软件包升级器&lt;/h2>
&lt;pre>&lt;code>yum install package_name 下载并安装一个rpm包
yum localinstall package_name.rpm 将安装一个rpm包，使用你自己的软件仓库为你解决所有依赖关系
yum update package_name.rpm 更新当前系统中所有安装的rpm包
yum update package_name 更新一个rpm包
yum remove package_name 删除一个rpm包
yum list 列出当前系统中安装的所有包
yum search package_name 在rpm仓库中搜寻软件包
yum clean packages 清理rpm缓存删除下载的包
yum clean headers 删除所有头文件
yum clean all 删除所有缓存的包和头文件
&lt;/code>&lt;/pre>
&lt;h2 id="deb-包">deb 包&lt;/h2>
&lt;pre>&lt;code>dpkg -i package.deb 安装/更新一个 deb 包
dpkg -r package_name 从系统删除一个 deb 包
dpkg -l 显示系统中所有已经安装的 deb 包
dpkg -l | grep httpd 显示所有名称中包含 &amp;quot;httpd&amp;quot; 字样的deb包
dpkg -s package_name 获得已经安装在系统中一个特殊包的信息
dpkg -L package_name 显示系统中已经安装的一个deb包所提供的文件列表
dpkg --contents package.deb 显示尚未安装的一个包所提供的文件列表
dpkg -S /bin/ping 确认所给的文件由哪个deb包提供
APT 软件工具 (Debian, Ubuntu 以及类似系统)
apt-get install package_name 安装/更新一个 deb 包
apt-cdrom install package_name 从光盘安装/更新一个 deb 包
apt-get update 升级列表中的软件包
apt-get upgrade 升级所有已安装的软件
apt-get remove package_name 从系统删除一个deb包
apt-get check 确认依赖的软件仓库正确
apt-get clean 从下载的软件包中清理缓存
apt-cache search searched-package 返回包含所要搜索字符串的软件包名称
&lt;/code>&lt;/pre>
&lt;h2 id="查看文件内容">查看文件内容&lt;/h2>
&lt;pre>&lt;code>cat file1 从第一个字节开始正向查看文件的内容
tac file1 从最后一行开始反向查看一个文件的内容
more file1 查看一个长文件的内容
less file1 类似于 'more' 命令，但是它允许在文件中和正向操作一样的反向操作
head -2 file1 查看一个文件的前两行
tail -2 file1 查看一个文件的最后两行
tail -f /var/log/messages 实时查看被添加到一个文件中的内容
&lt;/code>&lt;/pre>
&lt;h2 id="文本处理">文本处理&lt;/h2>
&lt;pre>&lt;code>cat file1 file2 ... | command &amp;lt;&amp;gt; file1_in.txt_or_file1_out.txt general syntax for text manipulation using PIPE, STDIN and STDOUT
cat file1 | command( sed, grep, awk, grep, etc...) &amp;gt; result.txt 合并一个文件的详细说明文本，并将简介写入一个新文件中
cat file1 | command( sed, grep, awk, grep, etc...) &amp;gt;&amp;gt; result.txt 合并一个文件的详细说明文本，并将简介写入一个已有的文件中
grep Aug /var/log/messages 在文件 '/var/log/messages'中查找关键词&amp;quot;Aug&amp;quot;
grep ^Aug /var/log/messages 在文件 '/var/log/messages'中查找以&amp;quot;Aug&amp;quot;开始的词汇
grep [0-9] /var/log/messages 选择 '/var/log/messages' 文件中所有包含数字的行
grep Aug -R /var/log/* 在目录 '/var/log' 及随后的目录中搜索字符串&amp;quot;Aug&amp;quot;
sed 's/stringa1/stringa2/g' example.txt 将example.txt文件中的 &amp;quot;string1&amp;quot; 替换成 &amp;quot;string2&amp;quot;
sed '/^$/d' example.txt 从example.txt文件中删除所有空白行
sed '/ *#/d; /^$/d' example.txt 从example.txt文件中删除所有注释和空白行
echo 'esempio' | tr '[:lower:]' '[:upper:]' 合并上下单元格内容
sed -e '1d' result.txt 从文件example.txt 中排除第一行
sed -n '/stringa1/p' 查看只包含词汇 &amp;quot;string1&amp;quot;的行
sed -e 's/ *$//' example.txt 删除每一行最后的空白字符
sed -e 's/stringa1//g' example.txt 从文档中只删除词汇 &amp;quot;string1&amp;quot; 并保留剩余全部
sed -n '1,5p;5q' example.txt 查看从第一行到第5行内容
sed -n '5p;5q' example.txt 查看第5行
sed -e 's/00*/0/g' example.txt 用单个零替换多个零
cat -n file1 标示文件的行数
cat example.txt | awk 'NR%2==1' 删除example.txt文件中的所有偶数行
echo a b c | awk '{print $1}' 查看一行第一栏
echo a b c | awk '{print $1,$3}' 查看一行的第一和第三栏
paste file1 file2 合并两个文件或两栏的内容
paste -d '+' file1 file2 合并两个文件或两栏的内容，中间用&amp;quot;+&amp;quot;区分
sort file1 file2 排序两个文件的内容
sort file1 file2 | uniq 取出两个文件的并集(重复的行只保留一份)
sort file1 file2 | uniq -u 删除交集，留下其他的行
sort file1 file2 | uniq -d 取出两个文件的交集(只留下同时存在于两个文件中的文件)
comm -1 file1 file2 比较两个文件的内容只删除 'file1' 所包含的内容
comm -2 file1 file2 比较两个文件的内容只删除 'file2' 所包含的内容
comm -3 file1 file2 比较两个文件的内容只删除两个文件共有的部分
&lt;/code>&lt;/pre>
&lt;h2 id="字符设置和文件格式转换">字符设置和文件格式转换&lt;/h2>
&lt;pre>&lt;code>dos2unix filedos.txt fileunix.txt 将一个文本文件的格式从MSDOS转换成UNIX
unix2dos fileunix.txt filedos.txt 将一个文本文件的格式从UNIX转换成MSDOS
recode ..HTML &amp;lt; page.txt &amp;gt; page.html 将一个文本文件转换成html
recode -l | more 显示所有允许的转换格式
&lt;/code>&lt;/pre>
&lt;h2 id="文件系统分析">文件系统分析&lt;/h2>
&lt;pre>&lt;code>badblocks -v /dev/hda1 检查磁盘hda1上的坏磁块
fsck /dev/hda1 修复/检查hda1磁盘上linux文件系统的完整性
fsck.ext2 /dev/hda1 修复/检查hda1磁盘上ext2文件系统的完整性
e2fsck /dev/hda1 修复/检查hda1磁盘上ext2文件系统的完整性
e2fsck -j /dev/hda1 修复/检查hda1磁盘上ext3文件系统的完整性
fsck.ext3 /dev/hda1 修复/检查hda1磁盘上ext3文件系统的完整性
fsck.vfat /dev/hda1 修复/检查hda1磁盘上fat文件系统的完整性
fsck.msdos /dev/hda1 修复/检查hda1磁盘上dos文件系统的完整性
dosfsck /dev/hda1 修复/检查hda1磁盘上dos文件系统的完整性
&lt;/code>&lt;/pre>
&lt;h2 id="初始化一个文件系统">初始化一个文件系统&lt;/h2>
&lt;pre>&lt;code>mkfs /dev/hda1 在hda1分区创建一个文件系统
mke2fs /dev/hda1 在hda1分区创建一个linux ext2的文件系统
mke2fs -j /dev/hda1 在hda1分区创建一个linux ext3(日志型)的文件系统
mkfs -t vfat 32 -F /dev/hda1 创建一个 FAT32 文件系统
fdformat -n /dev/fd0 格式化一个软盘
mkswap /dev/hda3 创建一个swap文件系统
&lt;/code>&lt;/pre>
&lt;h2 id="swap文件系统">SWAP文件系统&lt;/h2>
&lt;pre>&lt;code>mkswap /dev/hda3 创建一个swap文件系统
swapon /dev/hda3 启用一个新的swap文件系统
swapon /dev/hda2 /dev/hdb3 启用两个swap分区
&lt;/code>&lt;/pre>
&lt;h2 id="备份">备份&lt;/h2>
&lt;pre>&lt;code>dump -0aj -f /tmp/home0.bak /home 制作一个 '/home' 目录的完整备份
dump -1aj -f /tmp/home0.bak /home 制作一个 '/home' 目录的交互式备份
restore -if /tmp/home0.bak 还原一个交互式备份
rsync -rogpav --delete /home /tmp 同步两边的目录
rsync -rogpav -e ssh --delete /home ip_address:/tmp 通过SSH通道rsync
rsync -az -e ssh --delete ip_addr:/home/public /home/local 通过ssh和压缩将一个远程目录同步到本地目录
rsync -az -e ssh --delete /home/local ip_addr:/home/public 通过ssh和压缩将本地目录同步到远程目录
dd bs=1M if=/dev/hda | gzip | ssh user@ip_addr 'dd of=hda.gz' 通过ssh在远程主机上执行一次备份本地磁盘的操作
dd if=/dev/sda of=/tmp/file1 备份磁盘内容到一个文件
tar -Puf backup.tar /home/user 执行一次对 '/home/user' 目录的交互式备份操作
( cd /tmp/local/ &amp;amp;&amp;amp; tar c . ) | ssh -C user@ip_addr 'cd /home/share/ &amp;amp;&amp;amp; tar x -p' 通过ssh在远程目录中复制一个目录内容
( tar c /home ) | ssh -C user@ip_addr 'cd /home/backup-home &amp;amp;&amp;amp; tar x -p' 通过ssh在远程目录中复制一个本地目录
tar cf - . | (cd /tmp/backup ; tar xf - ) 本地将一个目录复制到另一个地方，保留原有权限及链接
find /home/user1 -name '*.txt' | xargs cp -av --target-directory=/home/backup/ --parents 从一个目录查找并复制所有以 '.txt' 结尾的文件到另一个目录
find /var/log -name '*.log' | tar cv --files-from=- | bzip2 &amp;gt; log.tar.bz2 查找所有以 '.log' 结尾的文件并做成一个bzip包
dd if=/dev/hda of=/dev/fd0 bs=512 count=1 做一个将 MBR (Master Boot Record)内容复制到软盘的动作
dd if=/dev/fd0 of=/dev/hda bs=512 count=1 从已经保存到软盘的备份中恢复MBR内容
&lt;/code>&lt;/pre>
&lt;h2 id="光盘">光盘&lt;/h2>
&lt;pre>&lt;code>cdrecord -v gracetime=2 dev=/dev/cdrom -eject blank=fast -force 清空一个可复写的光盘内容
mkisofs /dev/cdrom &amp;gt; cd.iso 在磁盘上创建一个光盘的iso镜像文件
mkisofs /dev/cdrom | gzip &amp;gt; cd_iso.gz 在磁盘上创建一个压缩了的光盘iso镜像文件
mkisofs -J -allow-leading-dots -R -V &amp;quot;Label CD&amp;quot; -iso-level 4 -o ./cd.iso data_cd 创建一个目录的iso镜像文件
cdrecord -v dev=/dev/cdrom cd.iso 刻录一个ISO镜像文件
gzip -dc cd_iso.gz | cdrecord dev=/dev/cdrom - 刻录一个压缩了的ISO镜像文件
mount -o loop cd.iso /mnt/iso 挂载一个ISO镜像文件
cd-paranoia -B 从一个CD光盘转录音轨到 wav 文件中
cd-paranoia -- &amp;quot;-3&amp;quot; 从一个CD光盘转录音轨到 wav 文件中（参数-3）
cdrecord --scanbus 扫描总线以识别scsi通道
dd if=/dev/hdc | md5sum 校验一个设备的md5sum编码，例如一张 CD
&lt;/code>&lt;/pre>
&lt;h2 id="网络以太网和wifi无线">网络（以太网和WIFI无线）&lt;/h2>
&lt;pre>&lt;code>ifconfig eth0 显示一个以太网卡的配置
ifup eth0 启用一个 'eth0' 网络设备
ifdown eth0 禁用一个 'eth0' 网络设备
ifconfig eth0 192.168.1.1 netmask 255.255.255.0 控制IP地址
ifconfig eth0 promisc 设置 'eth0' 成混杂模式以嗅探数据包 (sniffing)
dhclient eth0 以dhcp模式启用 'eth0'
route -n show routing table
route add -net 0/0 gw IP_Gateway configura default gateway
route add -net 192.168.0.0 netmask 255.255.0.0 gw 192.168.1.1 configure static route to reach network '192.168.0.0/16'
route del 0/0 gw IP_gateway remove static route
echo &amp;quot;1&amp;quot; &amp;gt; /proc/sys/net/ipv4/ip_forward activate ip routing
hostname show hostname of system
host www.example.com lookup hostname to resolve name to ip address and viceversa(1)
nslookup www.example.com lookup hostname to resolve name to ip address and viceversa(2)
ip link show show link status of all interfaces
mii-tool eth0 show link status of 'eth0'
ethtool eth0 show statistics of network card 'eth0'
netstat -tup show all active network connections and their PID
netstat -tupl show all network services listening on the system and their PID
tcpdump tcp port 80 show all HTTP traffic
iwlist scan show wireless networks
iwconfig eth1 show configuration of a wireless network card
hostname show hostname
host www.example.com lookup hostname to resolve name to ip address and viceversa
nslookup www.example.com lookup hostname to resolve name to ip address and viceversa
whois www.example.com lookup on Whois database
&lt;/code>&lt;/pre>
&lt;h2 id="列出目录内容">列出目录内容&lt;/h2>
&lt;pre>&lt;code>ls -a：显示所有文件（包括隐藏文件）；
ls -l：显示详细信息；
ls -R：递归显示子目录结构；
ls -ld：显示目录和链接信息；
ctrl+r：历史记录中所搜命令（输入命令中的任意一个字符）；
Linux中以.开头的文件是隐藏文件；
pwd:显示当前目录
&lt;/code>&lt;/pre>
&lt;h2 id="查看文件的类型">查看文件的类型&lt;/h2>
&lt;pre>&lt;code>file:查看文件的类型
&lt;/code>&lt;/pre>
&lt;h2 id="复制文件目录">复制文件目录&lt;/h2>
&lt;pre>&lt;code>1、cp：复制文件和目录 cp源文件（文件夹）目标文件（文件夹）。
常用参数：-r:递归复制整个目录树；-v：显示详细信息；
复制文件夹时要在cp命令后面加一个-r参数：
如：cp -r 源文件夹 目标文件夹。
2、touch+文件名：当文件不存在的时候，创建相应的文件；当文件存在的时候，修改文件的创建时间。
功能：生成一个空文件或修改文件的存取/修改的时间记录值；
touch * ：将当前下的文件时间修改为系统的当前时间；
touch –d 20040210 test：将test文件的日期改为20040210；
touch abc：若abc文件存在，则修改为系统的当前时间；若不存在，则生成一个为当前时间的空文件。
3、mv 文件 目标目录：移动或重命名文件或目录（如果指定文件名，则可以重命名文件）。可以将文件及目录移到另一目录下，或更改文件及目录的名称。
格式为：mv [参数]&amp;lt;源文件或目录&amp;gt; &amp;lt;目标文件或目录&amp;gt;
mva.txt ../：将a.txt文件移动上层目录
mv a.txt b.txt：将a.txt改名为b.txt
mvdir2 ../：将dir2目录上移一层
4、rm：删除文件
常用参数：-i：交互式 -r：递归的删除包括目录中的所有内容。
5、mkdir +文件夹名称：创建文件夹
6、rm -r +文件夹名称：删除文件夹（空文件夹和非空文件夹都可删除）；
rmdir 文件夹名称：删除文件夹（只能删除空文件夹）。
7、mkdir -p dir1/dir2 ：在当前目录下创建dir1目录，并在dir1目录下创建dir2目录， 也就是连续创建两个目录（dir1/和dir1/dir2）。
8、rmdir –p dir1/dir2：删除dir1下的dir2目录，若dir1目录为空也删除它。
9、rm * ：删除当前目录下的所有文件
10、-f参数：强迫删除文件 rm –f *.txt：强迫删除所有以后缀名为txt文件。
11、-i参数：删除文件时询问
rm　–i * ：删除当前目录下的所有文件会有如下提示：
rm:backup:is a directory　　　 遇到目录会略过
rm: remove ‘myfiles.txt’ ? Y
删除文件时会询问，可按Y或N键表示允许或拒绝删除文件。
12、-r参数：递归删除（连子目录一同删除，这是一个相当常用的参数）。
rm -r test ：删除test目录（含test目录下所有文件和子目录）；
rm -r *：删除所有文件（含当前目录所有文件、所有子目录和子目录下的文件） 一般在删除目录时r和f一起用，避免麻烦；
rm -rf test ：强行删除、不加询问。
13、grep：功能：在文件中搜索匹配的字符并进行输出。
格式：grep[参数] &amp;lt;要找的字串&amp;gt; &amp;lt;要寻找字 串的源文件&amp;gt;
greplinux test.txt：搜索test.txt文件中字符串linux并输出。
14、ln命令
功能：在文件和目录之间建立链接
格式：ln [参数] &amp;lt;源文件或目录&amp;gt; &amp;lt;目标文件或目录&amp;gt;
链接分“软链接”和“硬链接”
1.软链接:
ln–s /usr/share/do doc ：创建一个链接文件doc，并指向目录/usr/share/do
2.硬链接:
ln /usr/share/test hard：创建一个硬链接文件hard，这时对于test文件对应 的存储区域来说，又多了一个文件指向它。
&lt;/code>&lt;/pre>
&lt;h2 id="系统常用命令">系统常用命令&lt;/h2>
&lt;pre>&lt;code>1、显示命令
date:查看或设置当前系统的时间：格式化显示时间：+%Y--%m--%d；
date -s:设置当前系统的时间；
hwclock(clock)：显示硬件时钟时间(需要管理员权限)；
cal：查看日历；
格式cal [参数] 月年；
cal：显示当月的日历 cal4 2004 ：显示2004年4月的日历；
cal- y 2003：显示2003年的日历；
uptime：查看系统运行时间
2、输出查看命令
2、输出查看命令
echo：显示输入的内容 追加文件echo &amp;quot;liuyazhuang&amp;quot; &amp;gt;&amp;gt; liuyazhuang.txt
cat：显示文件内容,也可以将数个文件合并成一个文件；
格式：格式：cat[参数]&amp;lt;文件名&amp;gt;
cat test.txt：显示test.txt文件内容；
cat test.txt | more ：逐页显示test.txt文件中的内容；
cat test.txt &amp;gt;&amp;gt; test1.txt ：将test.txt的内容附加到test1.txt文件之后；
cat test.txt test2.txt &amp;gt;readme.txt　: 将test.txt和test2.txt文件合并成readme.txt 文件；
head:显示文件的头几行（默认10行） -n:指定显示的行数格式：head -n 文件名；
tail：显示文件的末尾几行（默认10行）-n：指定显示的行数 -f：追踪显示文件更新 （一般用于查看日志，命令不会退出，而是持续显示新加入的内容）；
格式：格式：tail[参数]&amp;lt;文件名&amp;gt;
tail-10 /etc/passwd ：显示/etc/passwd/文件的倒数10行内容；
tail+10 /etc/passwd ：显示/etc/passwd/文件从第10行开始到末尾的内容；
more：用于翻页显示文件内容（只能向下翻页）；
more命令是一般用于要显示的内容会超过一个画面长度的情况。为了避免画 面显示时瞬间就闪过去，用户可以使用more命令，让画面在显示满一页时暂停，此时可按空格健继续显示下一个画面，或按Q键停止显示；
ls -al |more：以长格形式显示etc目录下的文件列表，显示满一个画面便暂停，可 按空格键继续显示下一画面，或按Q键跳离；
less：翻页显示文件内容（带上下翻页）按下上键分页，按q退出；
less命令的用法与more命令类似，也可以用来浏览超过一页的文件。所不同 的是less 命令除了可以按空格键向下显示文件外，还可以利用上下键来卷动文件。当要结束浏览时，只要在less命令的提示符“：”下按Q键即可；
ls -al | less：以长格形式列出/etc目录中所有的内容。用户可按上下键浏览或按Q键跳离。
3、查看硬件信息
3、查看硬件信息
Ispci：查看PCI设备 -v：查看详细信息
Isusb：查看USB设备 -v：查看详细信息
Ismod：查看加载的模块(驱动)
4、关机、重启
4、关机、重启
shutdown关闭、重启计算机
shutdown[关机、重启]时间 -h关闭计算机 -r：重启计算机
如：立即关机：shutdown -h now
10分钟后关机：shutdown -h +10
23:30分关机：shutdown -h 23:30
立即重启：shutdown -r now
poweroff：立即关闭计算机
reboot：立即重启计算机
5、归档、压缩
5、归档、压缩
zip:压缩文件 zip liuyazhuang.zip myfile 格式为：“zip 压缩后的zip文件文件名”
unzip：解压文件 unzip liuyazhuang.zip
gzip：压缩文件 gzip 文件名
tar：归档文件
tar -cvf out.tar liuyazhuang 打包一个归档（将文件&amp;quot;liuyazhuang&amp;quot;打包成一个归档）
tar -xvf liuyazhuang.tar 释放一个归档（释放liuyazhuang.tar归档）
tar -cvzf backup.tar.gz/etc
-z参数将归档后的归档文件进行gzip压缩以减少大小。
-c：创建一个新tar文件
-v：显示运行过程的信息
-f：指定文件名
-z：调用gzip压缩命令进行压缩
-t：查看压缩文件的内容
-x：解开tar文件
tar -cvf test.tar *：将所有文件打包成test.tar,扩展名.tar需自行加上
tar -zcvf test.tar.gz *：将所有文件打包成test.tar,再用gzip命令压缩
tar -tf test.tar ：查看test.tar文件中包括了哪些文件
tar -xvf test.tar 将test.tar解开
tar -zxvf foo.tar.gz 解压缩
gzip各gunzip命令
gziptest.txt ：压缩文件时，不需要任何参数
gizp–l test.txt.gz：显示压缩率
6、查找
6、查找
locate：快速查找文件、文件夹：locate keyword
此命令需要预先建立数据库，数据库默认每天更新一次，可用updatedb命令手工建立、更新数据库。
find查找位置查找参数
如：
find . -name *liuyazhuang* 查找当前目录下名称中含有&amp;quot;liuyazhuang&amp;quot;的文件
find / -name *.conf 查找根目录下（整个硬盘）下后缀为.conf的文件
find / -perm 777 查找所有权限是777的文件
find / -type d 返回根目录下所有的目录
find . -name &amp;quot;a*&amp;quot;-exec ls -l {} \;
find功能：用来寻找文件或目录
格式：find [&amp;lt;路径&amp;gt;] [匹配条件]
find / -name httpd.conf 搜索系统根目录下名为httpd.conf的文件
7、ctrl+c :终止当前的命令
8、who或w命令
8、who或w命令
功能：查看当前系统中有哪些用户登录
格式：who/w[参数]
9、dmesg命令
9、dmesg命令
功能：显示系统诊断信息、操作系统版本号、物理内存的大小以及其它信息。
10、df命令
10、df命令
功能：用于查看文件系统的各个分区的占用情况。
11、du命令
11、du命令
功能：查看某个目录中各级子目录所使用的硬盘空间数。
格式：du [参数] &amp;lt;目录名&amp;gt;
12、free命令
12、free命令
功能：用于查看系统内存，虚拟内存（交换空间）的大小占用情况。
&lt;/code>&lt;/pre>
&lt;h2 id="vim">VIM&lt;/h2>
&lt;pre>&lt;code>VIM是一款功能强大的命令行文本编辑器，在Linux中通过vim命令可以启动vim编辑器。
一般使用vim + 目标文件路径 的形式使用vim
如果目标文件存在，则vim打开目标文件，如果目标文件不存在，则vim新建并打开该文件。
:q：退出vim编辑器
VIM模式
vim拥有三种模式：
（1）命令模式（常规模式）
vim启动后，默认进入命令模式，任何模式都可以通过esc键回到命令模式（可以多按几次），命令模式下可以键入不同的命令完成选择、复制、粘贴、撤销等操作。
命名模式常用命令如下：
i : 在光标前插入文本
o:在当前行的下面插入新行
dd:删除整行
yy：将当前行的内容放入缓冲区（复制当前行）
n+yy :将n行的内容放入缓冲区（复制n行）
p:将缓冲区中的文本放入光标后（粘贴）
u：撤销上一个操作
r:替换当前字符
/ 查找关键字
（2）插入模式
在命令模式下按 &amp;quot; i &amp;quot;键，即可进入插入模式，在插入模式可以输入编辑文本内容，使用esc键可以返回命令模式。
（3）ex模式
在命令模式中按&amp;quot; : &amp;quot;键可以进入ex模式，光标会移动到底部，在这里可以保存修改或退出vim.
ext模式常用命令如下：
:w ：保存当前的修改
:q ：退出
:q! ：强制退出，保存修改
:x :保存并退出，相当于:wq
:set number 显示行号
:! 系统命令 执行一个系统命令并显示结果
:sh ：切换到命令行，使用ctrl+d切换回vim
&lt;/code>&lt;/pre>
&lt;h2 id="软件包管理命令rpm">软件包管理命令(RPM)&lt;/h2>
&lt;pre>&lt;code>1、软件包的安装
1、软件包的安装
使用RPM命令的安装模式可以将软件包内所有的组件放到系统中的正确路径，安装软件包的命令是:rpm –ivh wu-ftpd-2.6.2-8.i386.rpm
i：作用rpm的安装模式 v: 校验文件信息h: 以＃号显示安装进度
2、软件包的删除
2、软件包的删除
删除模式会将指定软件包的内容全部删除，但并不包括已更改过的配置文件，删除RPM软件包的命令如下：rpm –e wu-ftpd
注意：这里必须使用软件名“wu-ftpd”或”wu-ftpd-2.6.2-8而不是使用当初安装时的软件包名.wu-ftpd-2.6.2-8.i386.rpm
3、软件包升级
3、软件包升级
升级模式会安装用户所指定的更新版本，并删除已安装在系统中的相同软件包，升级软件包命令如下：rpm –Uvh wu-ftpd-2.6.2-8.i386.rpm –Uvh：升级参数。
4、软件包更新
4、软件包更新
更新模式下，rpm命令会检查在命令行中所指定的软件包是否比系统中原有的软件 包更新。如果情况属实，rpm命令会自动更新指定的软件包；反之，若系统中并没有指定软件包的较旧版本，rpm命令并不会安装此软件包。而在升级模式下，不管系统中是否有较旧的版本，rpm命令都会安装指定的软件包。
rpm –Fvhwu-ftpd-2.6.2-8.i386.rpm -Fvh：更新参数
5、软件包查询
5、软件包查询
若要获取RPM软件包的相关信息，可以使用查询模式。使用-q参数可查询一个已 安装的软件包的内容。
rpm –q wu-ftpd
查询软件包所安装的位置：rpm –ql package-name
rpm –ql xv (l参数：显示文件列表)
&lt;/code>&lt;/pre></description></item><item><title>Mac 常用命令</title><link>https://blog.baicai.me/article/2023/mac_cmd/</link><pubDate>Fri, 31 Mar 2023 22:54:41 +0800</pubDate><author>admin@baicai.me (白菜)</author><guid>https://blog.baicai.me/article/2023/mac_cmd/</guid><description>&lt;h2 id="查看指定端口的进程">查看指定端口的进程&lt;/h2>
&lt;p>sudo lsof -i :5353&lt;/p>
&lt;p>COMMAND PID USER FD TYPE DEVICE SIZE/OFF NODE NAME
mDNSRespo 185 _mdnsresponder 6u IPv4 0x1111111111111 0t0 UDP *:mdns
mDNSRespo 185 _mdnsresponder 7u IPv6 0x1111111111111 0t0 UDP *:mdns&lt;/p>
&lt;h2 id="根据进程名称">根据进程名称&lt;/h2>
&lt;p>ps -ef | grep mDNSRespo&lt;/p>
&lt;p>65 185 1 0 8:08上午 ?? 0:26.69 /usr/sbin/mDNSResponder
0 223 1 0 8:08上午 ?? 0:02.16 /usr/sbin/mDNSResponderHelper
501 66848 66623 0 11:00下午 ttys000 0:00.00 grep mDNSRespo&lt;/p>
&lt;h2 id="根据pid杀进程">根据PID杀进程：&lt;/h2>
&lt;p>sudo kill -9 185&lt;/p></description></item><item><title>设置Telegram机器人的webhook</title><link>https://blog.baicai.me/article/2023/setting-telegram-webhook/</link><pubDate>Fri, 10 Feb 2023 23:04:02 +0800</pubDate><author>admin@baicai.me (白菜)</author><guid>https://blog.baicai.me/article/2023/setting-telegram-webhook/</guid><description>&lt;p>设置Webhook&lt;/p>
&lt;pre tabindex="0">&lt;code>https://api.telegram.org/bot{my_bot_token}/setWebhook?url={url_to_send_updates_to}
&lt;/code>&lt;/pre>&lt;p>例如：&lt;/p>
&lt;pre tabindex="0">&lt;code>https://api.telegram.org/bot123456:ABC-DEF1234ghIkl-zyx57W2v1u123ew11/setWebhook?url=https://baicai.me
&lt;/code>&lt;/pre>&lt;p>获取Webhook&lt;/p>
&lt;pre tabindex="0">&lt;code>https://api.telegram.org/bot{my_bot_token}/getWebhookInfo
&lt;/code>&lt;/pre></description></item><item><title>安装 debian 后，中文环境下将home目录下文件夹更改为对应的英文</title><link>https://blog.baicai.me/article/2023/home_dirs_update/</link><pubDate>Mon, 02 Jan 2023 12:41:04 +0800</pubDate><author>admin@baicai.me (白菜)</author><guid>https://blog.baicai.me/article/2023/home_dirs_update/</guid><description>&lt;p>操作环境:&lt;/p>
&lt;pre tabindex="0">&lt;code> Distributor ID: Debian
Description: Debian GNU/Linux 11 (bullseye)
Release: 11
Codename: bullseye
&lt;/code>&lt;/pre>&lt;p>安装 debian 后，中文环境下home目录下文件夹显示的是中文，不方便使用cd命令，用到的软件xdg-user-dirs-gtk(Gnome 环境已默认安装),可以方便更改为英文.&lt;/p>
&lt;div class="highlight">&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;">&lt;code class="language-bash" data-lang="bash">&lt;span style="display:flex;">&lt;span> &lt;span style="color:#75715e">#临时转换系统语言为英文，重启后会自动恢复原值的&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> export LANG&lt;span style="color:#f92672">=&lt;/span>en_US
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#75715e">#执行转换命令，弹出的窗口中会询问是否将目录转化为英文路径，同意并关闭&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> xdg-user-dirs-gtk-update
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#75715e">#转换回系统语言为中文，也可以不执行下面的命令，直接重启也一样的&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> export LANG&lt;span style="color:#f92672">=&lt;/span>zh_CN
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>&lt;p>下次进入系统后，会提示是否把目录转化为中文，选择不，并选择不再提示，并取消修改。&lt;/p></description></item><item><title>在 Debian 11 为 nginx 配置 Let's Encrypt SSL证书</title><link>https://blog.baicai.me/article/2022/debian_install_certbot-debian_install_certbot/</link><pubDate>Tue, 01 Nov 2022 22:18:02 +0800</pubDate><author>admin@baicai.me (白菜)</author><guid>https://blog.baicai.me/article/2022/debian_install_certbot-debian_install_certbot/</guid><description>&lt;p>在Debian 11 Nginx配置Let&amp;rsquo;s Encrypt SSL证书&lt;/p>
&lt;h3 id="安装-certbot-及-certbot-nginx-插件">安装 Certbot 及 certbot nginx 插件&lt;/h3>
&lt;div class="highlight">&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;">&lt;code class="language-bash" data-lang="bash">&lt;span style="display:flex;">&lt;span>sudo apt update &lt;span style="color:#f92672">&amp;amp;&amp;amp;&lt;/span> sudo apt -y install certbot python3-certbot-nginx
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>&lt;h3 id="为-nginx-网站生成证书并配置">为 nginx 网站生成证书并配置&lt;/h3>
&lt;div class="highlight">&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;">&lt;code class="language-bash" data-lang="bash">&lt;span style="display:flex;">&lt;span>certbot --nginx
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>&lt;p>如果是首次运行CertBot获取SSL证书，它将会询问你的电子邮件，输入一个你常用的邮件地址，它会在到期之前通知你。&lt;/p>
&lt;p>也可以为特定域名获取证书配置&lt;/p>
&lt;div class="highlight">&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;">&lt;code class="language-bash" data-lang="bash">&lt;span style="display:flex;">&lt;span>certbot --nginx -d baicai.me
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>&lt;h3 id="使用certbot自动更新ssl证书">使用Certbot自动更新SSL证书&lt;/h3>
&lt;p>Let&amp;rsquo;s Encrypt的SSL证书会在3个月到期即90天，因此你可能需要手动续订，但Certbot软件包附带了一个cron任务和systemd计时器，它将在证书过期之前进行自动续订。
除非你更改配置，否则无需再次手动运行Certbot。
您可以通过运行以下命令来测试证书的自动续订。&lt;/p>
&lt;div class="highlight">&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;">&lt;code class="language-bash" data-lang="bash">&lt;span style="display:flex;">&lt;span>certbot renew --dry-run
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div></description></item><item><title>在 Mac 系统中制作 Debian U盘启动盘</title><link>https://blog.baicai.me/article/2022/mac_create_debian_bootable_usb_flash_drive/</link><pubDate>Thu, 20 Oct 2022 13:18:50 +0800</pubDate><author>admin@baicai.me (白菜)</author><guid>https://blog.baicai.me/article/2022/mac_create_debian_bootable_usb_flash_drive/</guid><description>&lt;p>在Mac系统中制作U盘启动盘
Create a Bootable USB Flash Drive&lt;/p>
&lt;p>在Mac系统中，制作Linux启动盘不需要额外下载任何的工具，办法如下&lt;/p>
&lt;h3 id="下载-debian-dvd-镜像文件">下载 Debian DVD 镜像文件&lt;/h3>
&lt;p>通过 HTTP/FTP 下载 Debian CD/DVD 映像 &lt;a href="https://www.debian.org/CD/http-ftp/">https://www.debian.org/CD/http-ftp/&lt;/a>&lt;/p>
&lt;p>amd64 DVD版 &lt;a href="https://cdimage.debian.org/debian-cd/current/amd64/iso-dvd/">https://cdimage.debian.org/debian-cd/current/amd64/iso-dvd/&lt;/a>&lt;/p>
&lt;h3 id="格式化usb盘">格式化USB盘&lt;/h3>
&lt;p>打开系统自带的磁盘管理工具，插上U盘，格式化U盘，选择格式如下：
格式：Mac OS 扩展（日志式）
方案：GUID 分区图&lt;/p>
&lt;h3 id="取消usb磁盘挂载">取消Usb磁盘挂载&lt;/h3>
&lt;div class="highlight">&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;">&lt;code class="language-bash" data-lang="bash">&lt;span style="display:flex;">&lt;span>&lt;span style="color:#75715e"># 终端执行以下命令&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#75715e"># 列出磁盘，找到你usb硬盘的盘符&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>diskutil list
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#75715e"># 输出如下：可以看到usb硬盘为/dev/disk2&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>/dev/disk2 &lt;span style="color:#f92672">(&lt;/span>external, physical&lt;span style="color:#f92672">)&lt;/span>:
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#75715e">#: TYPE NAME SIZE IDENTIFIER&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> 0: FDisk_partition_scheme *32.0 GB disk2
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> 1: 0xEF 6.4 MB disk2s2
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#75715e"># 取消usb硬盘的挂载&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>diskutil unmountDisk /dev/disk2
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>&lt;h3 id="导入镜像">导入镜像&lt;/h3>
&lt;div class="highlight">&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;">&lt;code class="language-bash" data-lang="bash">&lt;span style="display:flex;">&lt;span>&lt;span style="color:#75715e"># 执行如下命令&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#75715e"># if是镜像文件路径&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#75715e"># of是导入的目的磁盘&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#75715e"># bs是读写快的大小，太小会增大io，降低效率，一般1m～2m即可。&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>sudo dd &lt;span style="color:#66d9ef">if&lt;/span>&lt;span style="color:#f92672">=&lt;/span>~/Downloads/debian-11.5.0-amd64-DVD-1.iso of&lt;span style="color:#f92672">=&lt;/span>/dev/disk2 bs&lt;span style="color:#f92672">=&lt;/span>2m
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#75715e"># 或 这里的U盘注意是rdisk2&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>sudo dd &lt;span style="color:#66d9ef">if&lt;/span>&lt;span style="color:#f92672">=&lt;/span>~/Downloads/debian-11.5.0-amd64-DVD-1.iso of&lt;span style="color:#f92672">=&lt;/span>/dev/rdisk2 bs&lt;span style="color:#f92672">=&lt;/span>2m
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>&lt;ul>
&lt;li>if是输入文件。&lt;/li>
&lt;li>of是输出文件&lt;/li>
&lt;li>bs是传输文件速度&lt;/li>
&lt;/ul>
&lt;h3 id="等待导入完成">等待导入完成&lt;/h3>
&lt;p>此导入需要等待一段时间，可能会比较久。耐心等待。
直到出现records in，records out，即成功了。&lt;/p>
&lt;h3 id="弹出u盘">弹出U盘&lt;/h3>
&lt;p>在快要完成的时候，系统会出现“磁盘无法识别”的提示，先不要做任何操作，等待终端dd命令执行完成后，执行下面命令弹出U盘。&lt;/p>
&lt;div class="highlight">&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;">&lt;code class="language-bash" data-lang="bash">&lt;span style="display:flex;">&lt;span>diskutil eject /dev/disk2
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>&lt;p>弹出后再选择“忽略”系统提示。&lt;/p>
&lt;h3 id="快速操作">快速操作&lt;/h3>
&lt;pre tabindex="0">&lt;code># 列出所有设备
diskutil list
# 卸载设备
diskutil unmountDisk force /dev/disk4
# 写入镜像
sudo dd if=debian-13.2.0-amd64-DVD-1.iso of=/dev/disk4 bs=4M status=progress
### 弹出U盘
diskutil eject /dev/disk4
&lt;/code>&lt;/pre></description></item><item><title>Debian 安装 Transmission 并实现远程访问</title><link>https://blog.baicai.me/article/2022/debian-install-transmission-daemon-debian-install-transmission-daemon/</link><pubDate>Tue, 18 Oct 2022 17:05:07 +0800</pubDate><author>admin@baicai.me (白菜)</author><guid>https://blog.baicai.me/article/2022/debian-install-transmission-daemon-debian-install-transmission-daemon/</guid><description>&lt;p>Debian 安装完成后的桌面环境带有 transmission-gtk
这个gui版关闭界面后，无后台服务，导致不能方便使用远程访问。&lt;/p>
&lt;p>那么安装Transmission后台守护程序&lt;/p>
&lt;div class="highlight">&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;">&lt;code class="language-bash" data-lang="bash">&lt;span style="display:flex;">&lt;span>$ sudo apt install -y transmission-daemon
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#75715e">#停止Transmisson后台服务&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>systemctl stop transmission-daemon.service
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#75715e">#修改配置文件&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>nano /etc/transmission-daemon/settings.json
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>&lt;h3 id="启动transmission后台服务">启动Transmission后台服务&lt;/h3>
&lt;div class="highlight">&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;">&lt;code class="language-bash" data-lang="bash">&lt;span style="display:flex;">&lt;span>&lt;span style="color:#75715e">#启动transmission服务&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>systemctl start transmission-daemon.service
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#75715e">#停止transmission服务&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>systemctl stop transmission-daemon.service
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#75715e">#查询transmission运行状态&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>systemctl status transmission-daemon.service
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#75715e">#将transmission设置为开机自启动&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>systemctl enable transmission-daemon.service
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#75715e">#关闭transmission开机自启&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>systemctl disable transmission-daemon.service
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div></description></item><item><title>Debian 安装慢的解决方案</title><link>https://blog.baicai.me/article/2022/debian_install/</link><pubDate>Tue, 18 Oct 2022 14:37:40 +0800</pubDate><author>admin@baicai.me (白菜)</author><guid>https://blog.baicai.me/article/2022/debian_install/</guid><description>&lt;h3 id="解决-debian-安装过程慢的可行方案">解决 Debian 安装过程慢的可行方案：&lt;/h3>
&lt;ul>
&lt;li>如果使用的是Dvd版的iso镜像，可以在安装前拔掉网线，通过离线安装，会非常快。&lt;/li>
&lt;li>安装时选择 expert，不要选择 安全更新。&lt;/li>
&lt;li>安装过程修改软件源。&lt;/li>
&lt;/ul>
&lt;h3 id="debian-dvd-1-镜像下载地址">Debian DVD-1 镜像下载地址&lt;/h3>
&lt;p>通过 HTTP/FTP 下载 Debian CD/DVD 映像 &lt;a href="https://www.debian.org/CD/http-ftp/">https://www.debian.org/CD/http-ftp/&lt;/a>&lt;/p>
&lt;p>amd64 DVD版 &lt;a href="https://cdimage.debian.org/debian-cd/current/amd64/iso-dvd/">https://cdimage.debian.org/debian-cd/current/amd64/iso-dvd/&lt;/a>&lt;/p>
&lt;h3 id="debian-安装过程中-修改软件源中的安全源地址">Debian 安装过程中 修改软件源中的安全源地址&lt;/h3>
&lt;p>在Debian安装步骤进入到选择安装的桌面环境和软件时, 键入 &lt;strong>Ctrl+Alt+F2&lt;/strong> 可以看到从图形界面转到了tty命令终端, 键入 &lt;strong>Enter&lt;/strong>
这里修改软件源配置文件&lt;/p>
&lt;div class="highlight">&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;">&lt;code class="language-bash" data-lang="bash">&lt;span style="display:flex;">&lt;span>nano /target/etc/apt/sources.list
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>&lt;p>修改debian-security源地址 &lt;a href="http://mirrors.ustc.edu.cn">http://mirrors.ustc.edu.cn&lt;/a> 目测最快&lt;/p>
&lt;pre tabindex="0">&lt;code>#deb http://security.debian.org/debian-security bullseye-security main
deb http://mirrors.ustc.edu.cn/debian-security bullseye-security main
&lt;/code>&lt;/pre>&lt;p>修改后 &lt;strong>Ctrl+X&lt;/strong> 退出保存&lt;/p>
&lt;p>然后退出终端重新进入界面继续安装，键入 &lt;strong>Ctrl+Alt+F5&lt;/strong>&lt;/p>
&lt;h3 id="debian-安装完成后更新硬件驱动">Debian 安装完成后更新硬件驱动&lt;/h3>
&lt;p>在设置——》关于——〉更新——》软件源，去掉cdrome的源，勾选合适的源
然后通过 dmesg 查看启动日志。
查找哪些固件加载异常，根据情况安装驱动（比如我的缺失显卡驱动和无线网卡驱动）。&lt;/p>
&lt;div class="highlight">&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;">&lt;code class="language-bash" data-lang="bash">&lt;span style="display:flex;">&lt;span>&lt;span style="color:#75715e"># 更新源&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>sudo apt-get update
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>dmesg
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#75715e"># demsg查看到 缺失显卡驱动&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>sudo apt-get install firmware-amd-graphics
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#75715e"># demsg查看到 缺失 rtl8168e-3.fw 固件程序&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#75715e"># 搜索固件信息&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>sudo apt search rtl8168e-3.fw
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#75715e"># 正在排序... 完成&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#75715e"># 全文搜索... 完成 &lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#75715e"># firmware-realtek/stable,now 20210315-3 all [已安装]&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#75715e"># Binary firmware for Realtek wired/wifi/BT adapters&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#75715e"># 根据上面查到的信息 安装驱动包 firmware-realtek&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>sudo apt-get install firmware-realtek
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div></description></item><item><title>安装docker</title><link>https://blog.baicai.me/article/2022/debian_install_docker/</link><pubDate>Fri, 30 Sep 2022 00:38:13 +0800</pubDate><author>admin@baicai.me (白菜)</author><guid>https://blog.baicai.me/article/2022/debian_install_docker/</guid><description>&lt;p>运行环境&lt;/p>
&lt;pre tabindex="0">&lt;code> Operating System: Debian GNU/Linux 11 (bullseye)
Kernel: Linux 5.10.0-18-amd64
Architecture: x86-64
&lt;/code>&lt;/pre>&lt;h3 id="通过debian官方软件仓库安装">通过Debian官方软件仓库安装&lt;/h3>
&lt;div class="highlight">&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;">&lt;code class="language-bash" data-lang="bash">&lt;span style="display:flex;">&lt;span>&lt;span style="color:#75715e"># 更新软件源 并 安装 docker及相关应用&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> sudo apt update &lt;span style="color:#f92672">&amp;amp;&amp;amp;&lt;/span> sudo apt install -y docker docker.io docker-compose
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>&lt;div class="highlight">&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;">&lt;code class="language-bash" data-lang="bash">&lt;span style="display:flex;">&lt;span>&lt;span style="color:#75715e"># 查看docker运行状态&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> sudo systemctl status docker
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#75715e"># 查看docker信息&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> sudo docker info
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#75715e"># 验证是否安装成功 &lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> sudo docker run hello-world
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>&lt;h3 id="镜像加速器">镜像加速器&lt;/h3>
&lt;p>访问 &lt;a href="https://cr.console.aliyun.com/cn-hangzhou/instances/mirrors">https://cr.console.aliyun.com/cn-hangzhou/instances/mirrors&lt;/a> 获取自己的阿里云镜像加速器地址&lt;/p>
&lt;p>修改 /etc/docker/daemon.json&lt;/p>
&lt;div class="highlight">&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;">&lt;code class="language-bash" data-lang="bash">&lt;span style="display:flex;">&lt;span>sudo mkdir -p /etc/docker
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>sudo tee /etc/docker/daemon.json &lt;span style="color:#e6db74">&amp;lt;&amp;lt;-&amp;#39;EOF&amp;#39;
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#e6db74">{
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#e6db74"> &amp;#34;max-concurrent-downloads&amp;#34;: 3,
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#e6db74"> &amp;#34;max-concurrent-uploads&amp;#34;: 3,
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#e6db74"> &amp;#34;max-download-attempts&amp;#34;: 3,
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#e6db74"> &amp;#34;registry-mirrors&amp;#34;: [&amp;#34;https://修改为自己的.mirror.aliyuncs.com&amp;#34;,&amp;#34;https://hub-mirror.c.163.com&amp;#34;,&amp;#34;https://registry.aliyuncs.com&amp;#34;]
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#e6db74">}
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#e6db74">EOF&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>sudo systemctl daemon-reload
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>sudo systemctl restart docker
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>&lt;h3 id="清理docker对象">清理docker对象&lt;/h3>
&lt;p>prune 命令用来删除不再使用的 docker 对象。&lt;/p>
&lt;div class="highlight">&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;">&lt;code class="language-bash" data-lang="bash">&lt;span style="display:flex;">&lt;span>&lt;span style="color:#75715e"># 删除所有未被 tag 标记和未被容器使用的镜像:&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>$ docker image prune
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#75715e"># 删除所有未被容器使用的镜像:&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>$ docker image prune -af
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#75715e"># 删除所有停止运行的容器:&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>$ docker container prune
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#75715e"># 删除所有未被挂载的卷:&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>$ docker volume prune
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#75715e"># 删除所有网络:&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>$ docker network prune
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#75715e"># 删除 docker 所有资源:&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>$ docker system prune
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>&lt;h3 id="查看容器ip">查看容器ip&lt;/h3>
&lt;div class="highlight">&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;">&lt;code class="language-bash" data-lang="bash">&lt;span style="display:flex;">&lt;span>&lt;span style="color:#75715e"># 查看所有容器的ip&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>$ docker inspect --format&lt;span style="color:#f92672">=&lt;/span>&lt;span style="color:#e6db74">&amp;#39;{{.Name}} - {{range .NetworkSettings.Networks}}{{.IPAddress}}{{end}}&amp;#39;&lt;/span> &lt;span style="color:#66d9ef">$(&lt;/span>docker ps -aq&lt;span style="color:#66d9ef">)&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#75715e"># 查看指定容器的ip网络配置包含网络，ip等&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>$ docker inspect containerId
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#75715e"># 查看容器的ip&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>$ docker exec -it containerId ip addr
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>&lt;h3 id="修改docker启动目录">修改docker启动目录&lt;/h3>
&lt;p>因为装系统时 /var 分区小，需要把docker 启动后的路径改成 /home/docker , /etc/docker/daemon.json 是 docker 的配置文件，默认是没有的，需要手动创建。&lt;/p>
&lt;p>具体的操作是：&lt;/p>
&lt;p>1: 设置 /etc/docker/daemon.json 文件.
内容参考：&lt;/p>
&lt;div class="highlight">&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;">&lt;code class="language-json" data-lang="json">&lt;span style="display:flex;">&lt;span>{
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#f92672">&amp;#34;data-root&amp;#34;&lt;/span>:&lt;span style="color:#e6db74">&amp;#34;/home/docker&amp;#34;&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>}
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>&lt;p>2.创建并修改完daemon.json文件后，需要让这个文件生效&lt;/p>
&lt;div class="highlight">&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;">&lt;code class="language-bash" data-lang="bash">&lt;span style="display:flex;">&lt;span>&lt;span style="color:#75715e"># a.修改完成后reload配置文件&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>sudo systemctl daemon-reload
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#75715e"># b.重启docker服务&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>sudo systemctl restart docker.service
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#75715e"># c.查看状态&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>sudo systemctl status docker -l
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#75715e"># d.查看服务&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>sudo docker info
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>&lt;h3 id="调试镜像">调试镜像&lt;/h3>
&lt;div class="highlight">&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;">&lt;code class="language-bash" data-lang="bash">&lt;span style="display:flex;">&lt;span>&lt;span style="color:#75715e"># 使用--entrypoint设置（额外增加-it选项可直接进入容器），进入容器成功。&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>docker run -it --entrypoint /bin/bash --name 容器名 镜像:v30.2.9
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>&lt;h3 id="查看程序动态库依赖关系">查看程序动态库依赖关系&lt;/h3>
&lt;div class="highlight">&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;">&lt;code class="language-bash" data-lang="bash">&lt;span style="display:flex;">&lt;span>&lt;span style="color:#75715e"># ldd (Debian GLIBC 2.36-9+deb12u1) 2.36&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#75715e"># Copyright (C) 2022 Free Software Foundation, Inc.&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#75715e"># This is free software; see the source for copying conditions. There is NO&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#75715e"># warranty; not even for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#75715e"># Written by Roland McGrath and Ulrich Drepper.&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>ldd --version
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#75715e"># 判断某条命令需要哪些共享库文件的支持，以确保指定的命令在独立的系统内可以可靠的运行&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>ldd /bin/bash
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>&lt;h3 id="参考">参考&lt;/h3>
&lt;p>Docker官方安装文档：
&lt;a href="https://docs.docker.com/engine/install/debian/">https://docs.docker.com/engine/install/debian/&lt;/a>&lt;/p>
&lt;h3 id="docker-daemonjson各配置详解">docker-daemon.json各配置详解&lt;/h3>
&lt;div class="highlight">&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;">&lt;code class="language-json" data-lang="json">&lt;span style="display:flex;">&lt;span>{
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#f92672">&amp;#34;api-cors-header&amp;#34;&lt;/span>:&lt;span style="color:#e6db74">&amp;#34;&amp;#34;&lt;/span>, &lt;span style="color:#75715e">//——————在引擎API中设置CORS标头
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#75715e">&lt;/span>&lt;span style="color:#f92672">&amp;#34;authorization-plugins&amp;#34;&lt;/span>:[], &lt;span style="color:#75715e">//——————要加载的授权插件
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#75715e">&lt;/span>&lt;span style="color:#f92672">&amp;#34;bridge&amp;#34;&lt;/span>:&lt;span style="color:#e6db74">&amp;#34;&amp;#34;&lt;/span>, &lt;span style="color:#75715e">//————将容器附加到网桥
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#75715e">&lt;/span>&lt;span style="color:#f92672">&amp;#34;cgroup-parent&amp;#34;&lt;/span>:&lt;span style="color:#e6db74">&amp;#34;&amp;#34;&lt;/span>, &lt;span style="color:#75715e">//——————为所有容器设置父cgroup
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#75715e">&lt;/span>&lt;span style="color:#f92672">&amp;#34;cluster-store&amp;#34;&lt;/span>:&lt;span style="color:#e6db74">&amp;#34;&amp;#34;&lt;/span>, &lt;span style="color:#75715e">//——————分布式存储后端的URL
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#75715e">&lt;/span>&lt;span style="color:#f92672">&amp;#34;cluster-store-opts&amp;#34;&lt;/span>:{}, &lt;span style="color:#75715e">//————————设置集群存储选项（默认map []）
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#75715e">&lt;/span>&lt;span style="color:#f92672">&amp;#34;cluster-advertise&amp;#34;&lt;/span>:&lt;span style="color:#e6db74">&amp;#34;&amp;#34;&lt;/span>, &lt;span style="color:#75715e">//————————要通告的地址或接口名称
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#75715e">&lt;/span>&lt;span style="color:#f92672">&amp;#34;debug&amp;#34;&lt;/span>: &lt;span style="color:#66d9ef">true&lt;/span>, &lt;span style="color:#75715e">//————————启用调试模式，启用后，可以看到很多的启动信息。默认false
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#75715e">&lt;/span>&lt;span style="color:#f92672">&amp;#34;default-gateway&amp;#34;&lt;/span>:&lt;span style="color:#e6db74">&amp;#34;&amp;#34;&lt;/span>, &lt;span style="color:#75715e">//——————容器默认网关IPv4地址
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#75715e">&lt;/span>&lt;span style="color:#f92672">&amp;#34;default-gateway-v6&amp;#34;&lt;/span>:&lt;span style="color:#e6db74">&amp;#34;&amp;#34;&lt;/span>, &lt;span style="color:#75715e">//——————容器默认网关IPv6地址
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#75715e">&lt;/span>&lt;span style="color:#f92672">&amp;#34;default-runtime&amp;#34;&lt;/span>:&lt;span style="color:#e6db74">&amp;#34;runc&amp;#34;&lt;/span>, &lt;span style="color:#75715e">//————————容器的默认OCI运行时（默认为&amp;#34; runc&amp;#34;）
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#75715e">&lt;/span>&lt;span style="color:#f92672">&amp;#34;default-ulimits&amp;#34;&lt;/span>:{}, &lt;span style="color:#75715e">//——————容器的默认ulimit（默认[]）
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#75715e">&lt;/span>&lt;span style="color:#f92672">&amp;#34;dns&amp;#34;&lt;/span>: [&lt;span style="color:#e6db74">&amp;#34;192.168.1.1&amp;#34;&lt;/span>], &lt;span style="color:#75715e">//——————设定容器DNS的地址，在容器的 /etc/resolv.conf文件中可查看。
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#75715e">&lt;/span>&lt;span style="color:#f92672">&amp;#34;dns-opts&amp;#34;&lt;/span>: [], &lt;span style="color:#75715e">//————————容器 /etc/resolv.conf 文件，其他设置
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#75715e">&lt;/span>&lt;span style="color:#f92672">&amp;#34;dns-search&amp;#34;&lt;/span>: [], &lt;span style="color:#75715e">//————————设定容器的搜索域，当设定搜索域为 .example.com 时，在搜索一个名为 host 的 主机时，DNS不仅搜索host，还会搜
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#75715e">//索host.example.com 。 注意：如果不设置， Docker 会默认用主机上的 /etc/resolv.conf 来配置容器。
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#75715e">&lt;/span>&lt;span style="color:#f92672">&amp;#34;exec-opts&amp;#34;&lt;/span>: [], &lt;span style="color:#75715e">//————————运行时执行选项
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#75715e">&lt;/span>&lt;span style="color:#f92672">&amp;#34;exec-root&amp;#34;&lt;/span>:&lt;span style="color:#e6db74">&amp;#34;&amp;#34;&lt;/span>, &lt;span style="color:#75715e">//————————执行状态文件的根目录（默认为’/var/run/docker‘）
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#75715e">&lt;/span>&lt;span style="color:#f92672">&amp;#34;fixed-cidr&amp;#34;&lt;/span>:&lt;span style="color:#e6db74">&amp;#34;&amp;#34;&lt;/span>, &lt;span style="color:#75715e">//————————固定IP的IPv4子网
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#75715e">&lt;/span>&lt;span style="color:#f92672">&amp;#34;fixed-cidr-v6&amp;#34;&lt;/span>:&lt;span style="color:#e6db74">&amp;#34;&amp;#34;&lt;/span>, &lt;span style="color:#75715e">//————————固定IP的IPv6子网
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#75715e">&lt;/span>&lt;span style="color:#f92672">&amp;#34;data-root&amp;#34;&lt;/span>:&lt;span style="color:#e6db74">&amp;#34;/var/lib/docker&amp;#34;&lt;/span>, &lt;span style="color:#75715e">//————-Docker运行时使用的根路径，默认/var/lib/docker
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#75715e">&lt;/span>&lt;span style="color:#f92672">&amp;#34;group&amp;#34;&lt;/span>: &lt;span style="color:#e6db74">&amp;#34;&amp;#34;&lt;/span>, &lt;span style="color:#75715e">//——————UNIX套接字的组（默认为&amp;#34;docker&amp;#34;）
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#75715e">&lt;/span>&lt;span style="color:#f92672">&amp;#34;hosts&amp;#34;&lt;/span>: [], &lt;span style="color:#75715e">//——————设置容器hosts
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#75715e">&lt;/span>&lt;span style="color:#f92672">&amp;#34;icc&amp;#34;&lt;/span>: &lt;span style="color:#66d9ef">false&lt;/span>, &lt;span style="color:#75715e">//——————启用容器间通信（默认为true）
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#75715e">&lt;/span>&lt;span style="color:#f92672">&amp;#34;ip&amp;#34;&lt;/span>:&lt;span style="color:#e6db74">&amp;#34;0.0.0.0&amp;#34;&lt;/span>, &lt;span style="color:#75715e">//————————绑定容器端口时的默认IP（默认0.0.0.0）
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#75715e">&lt;/span>&lt;span style="color:#f92672">&amp;#34;iptables&amp;#34;&lt;/span>: &lt;span style="color:#66d9ef">false&lt;/span>, &lt;span style="color:#75715e">//———————启用iptables规则添加（默认为true）
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#75715e">&lt;/span>&lt;span style="color:#f92672">&amp;#34;ipv6&amp;#34;&lt;/span>: &lt;span style="color:#66d9ef">false&lt;/span>, &lt;span style="color:#75715e">//——————启用IPv6网络
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#75715e">&lt;/span>&lt;span style="color:#f92672">&amp;#34;ip-forward&amp;#34;&lt;/span>: &lt;span style="color:#66d9ef">false&lt;/span>, &lt;span style="color:#75715e">//————————默认true, 启用 net.ipv4.ip_forward ,进入容器后使用 sysctl -a | grepnet.ipv4.ip_forward 查看
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#75715e">&lt;/span>&lt;span style="color:#f92672">&amp;#34;ip-masq&amp;#34;&lt;/span>:&lt;span style="color:#66d9ef">false&lt;/span>, &lt;span style="color:#75715e">//——————启用IP伪装（默认为true）
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#75715e">&lt;/span>&lt;span style="color:#f92672">&amp;#34;labels&amp;#34;&lt;/span>:[&lt;span style="color:#e6db74">&amp;#34;nodeName=node-121&amp;#34;&lt;/span>], &lt;span style="color:#75715e">//————————docker主机的标签，很实用的功能,例如定义：–label nodeName=host-121
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#75715e">&lt;/span>&lt;span style="color:#f92672">&amp;#34;live-restore&amp;#34;&lt;/span>: &lt;span style="color:#66d9ef">true&lt;/span>, &lt;span style="color:#75715e">//——————在容器仍在运行时启用docker的实时还原
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#75715e">&lt;/span>&lt;span style="color:#f92672">&amp;#34;log-driver&amp;#34;&lt;/span>:&lt;span style="color:#e6db74">&amp;#34;&amp;#34;&lt;/span>, &lt;span style="color:#75715e">//——————容器日志的默认驱动程序（默认为&amp;#34; json-file&amp;#34;）
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#75715e">&lt;/span>&lt;span style="color:#f92672">&amp;#34;log-level&amp;#34;&lt;/span>:&lt;span style="color:#e6db74">&amp;#34;&amp;#34;&lt;/span>, &lt;span style="color:#75715e">//——————设置日志记录级别（&amp;#34;调试&amp;#34;，&amp;#34;信息&amp;#34;，&amp;#34;警告&amp;#34;，&amp;#34;错误&amp;#34;，&amp;#34;致命&amp;#34;）（默认为&amp;#34;信息&amp;#34;）
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#75715e">&lt;/span>&lt;span style="color:#f92672">&amp;#34;max-concurrent-downloads&amp;#34;&lt;/span>:&lt;span style="color:#ae81ff">3&lt;/span>, &lt;span style="color:#75715e">//——————设置每个请求的最大并发下载量（默认为3）
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#75715e">&lt;/span>&lt;span style="color:#f92672">&amp;#34;max-concurrent-uploads&amp;#34;&lt;/span>:&lt;span style="color:#ae81ff">5&lt;/span>, &lt;span style="color:#75715e">//——————设置每次推送的最大同时上传数（默认为5）
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#75715e">&lt;/span>&lt;span style="color:#f92672">&amp;#34;mtu&amp;#34;&lt;/span>: &lt;span style="color:#ae81ff">0&lt;/span>, &lt;span style="color:#75715e">//——————设置容器网络MTU
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#75715e">&lt;/span>&lt;span style="color:#f92672">&amp;#34;oom-score-adjust&amp;#34;&lt;/span>:&lt;span style="color:#ae81ff">-500&lt;/span>, &lt;span style="color:#75715e">//——————设置守护程序的oom_score_adj（默认值为-500）
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#75715e">&lt;/span>&lt;span style="color:#f92672">&amp;#34;pidfile&amp;#34;&lt;/span>: &lt;span style="color:#e6db74">&amp;#34;&amp;#34;&lt;/span>, &lt;span style="color:#75715e">//——————Docker守护进程的PID文件
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#75715e">&lt;/span>&lt;span style="color:#f92672">&amp;#34;raw-logs&amp;#34;&lt;/span>: &lt;span style="color:#66d9ef">false&lt;/span>, &lt;span style="color:#75715e">//——————全时间戳机制
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#75715e">&lt;/span>&lt;span style="color:#f92672">&amp;#34;selinux-enabled&amp;#34;&lt;/span>: &lt;span style="color:#66d9ef">false&lt;/span>, &lt;span style="color:#75715e">//——————默认 false，启用selinux支持
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#75715e">&lt;/span>&lt;span style="color:#f92672">&amp;#34;storage-driver&amp;#34;&lt;/span>:&lt;span style="color:#e6db74">&amp;#34;&amp;#34;&lt;/span>, &lt;span style="color:#75715e">//——————要使用的存储驱动程序
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#75715e">&lt;/span>&lt;span style="color:#f92672">&amp;#34;swarm-default-advertise-addr&amp;#34;&lt;/span>:&lt;span style="color:#e6db74">&amp;#34;&amp;#34;&lt;/span>, &lt;span style="color:#75715e">//——————设置默认地址或群集广告地址的接口
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#75715e">&lt;/span>&lt;span style="color:#f92672">&amp;#34;tls&amp;#34;&lt;/span>: &lt;span style="color:#66d9ef">true&lt;/span>, &lt;span style="color:#75715e">//————————默认 false, 启动TLS认证开关
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#75715e">&lt;/span>&lt;span style="color:#f92672">&amp;#34;tlscacert&amp;#34;&lt;/span>: &lt;span style="color:#e6db74">&amp;#34;&amp;#34;&lt;/span>, &lt;span style="color:#75715e">//——————默认 ~/.docker/ca.pem，通过CA认证过的的certificate文件路径
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#75715e">&lt;/span>&lt;span style="color:#f92672">&amp;#34;tlscert&amp;#34;&lt;/span>: &lt;span style="color:#e6db74">&amp;#34;&amp;#34;&lt;/span>, &lt;span style="color:#75715e">//————————默认 ~/.docker/cert.pem ，TLS的certificate文件路径
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#75715e">&lt;/span>&lt;span style="color:#f92672">&amp;#34;tlskey&amp;#34;&lt;/span>: &lt;span style="color:#e6db74">&amp;#34;&amp;#34;&lt;/span>, &lt;span style="color:#75715e">//————————默认~/.docker/key.pem，TLS的key文件路径
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#75715e">&lt;/span>&lt;span style="color:#f92672">&amp;#34;tlsverify&amp;#34;&lt;/span>: &lt;span style="color:#66d9ef">true&lt;/span>, &lt;span style="color:#75715e">//————————默认false，使用TLS并做后台进程与客户端通讯的验证
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#75715e">&lt;/span>&lt;span style="color:#f92672">&amp;#34;userland-proxy&amp;#34;&lt;/span>:&lt;span style="color:#66d9ef">false&lt;/span>, &lt;span style="color:#75715e">//——————使用userland代理进行环回流量（默认为true）
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#75715e">&lt;/span>&lt;span style="color:#f92672">&amp;#34;userns-remap&amp;#34;&lt;/span>:&lt;span style="color:#e6db74">&amp;#34;&amp;#34;&lt;/span>, &lt;span style="color:#75715e">//————————用户名称空间的用户/组设置
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#75715e">&lt;/span>&lt;span style="color:#f92672">&amp;#34;bip&amp;#34;&lt;/span>:&lt;span style="color:#e6db74">&amp;#34;192.168.88.0/22&amp;#34;&lt;/span>, &lt;span style="color:#75715e">//——————————指定网桥IP
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#75715e">&lt;/span>&lt;span style="color:#f92672">&amp;#34;registry-mirrors&amp;#34;&lt;/span>: [&lt;span style="color:#e6db74">&amp;#34;https://192.498.89.232:89&amp;#34;&lt;/span>], &lt;span style="color:#75715e">//————————设置镜像加速
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#75715e">&lt;/span>&lt;span style="color:#f92672">&amp;#34;insecure-registries&amp;#34;&lt;/span>: [&lt;span style="color:#e6db74">&amp;#34;192.168.0.123:12312&amp;#34;&lt;/span>], &lt;span style="color:#75715e">//———————设置私有仓库地址可以设为http
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#75715e">&lt;/span>&lt;span style="color:#f92672">&amp;#34;storage-opts&amp;#34;&lt;/span>: [
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#e6db74">&amp;#34;overlay2.override_kernel_check=true&amp;#34;&lt;/span>,
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#e6db74">&amp;#34;overlay2.size=15G&amp;#34;&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>], &lt;span style="color:#75715e">//————————存储驱动程序选项
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#75715e">&lt;/span>&lt;span style="color:#f92672">&amp;#34;log-opts&amp;#34;&lt;/span>: {
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#f92672">&amp;#34;max-file&amp;#34;&lt;/span>: &lt;span style="color:#e6db74">&amp;#34;3&amp;#34;&lt;/span>,
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#f92672">&amp;#34;max-size&amp;#34;&lt;/span>: &lt;span style="color:#e6db74">&amp;#34;10m&amp;#34;&lt;/span>,
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>}, &lt;span style="color:#75715e">//————————容器默认日志驱动程序选项
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#75715e">&lt;/span>&lt;span style="color:#f92672">&amp;#34;iptables&amp;#34;&lt;/span>: &lt;span style="color:#66d9ef">false&lt;/span> &lt;span style="color:#75715e">//————————启用iptables规则添加（默认为true）
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#75715e">&lt;/span>}
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div></description></item><item><title>nginx 启用目录索引，显示文件列表</title><link>https://blog.baicai.me/article/2022/nginx_autoindex_conf/</link><pubDate>Sat, 23 Jul 2022 23:52:39 +0800</pubDate><author>admin@baicai.me (白菜)</author><guid>https://blog.baicai.me/article/2022/nginx_autoindex_conf/</guid><description>&lt;p>在nginx中，如果特定目录中没有index.html 文件，则默认会返回 404 Not Found 的错误。&lt;/p>
&lt;p>但是，Nginx 自动索引模块—— ngx_http_autoindex_module 模块，提供了一种自动生成列表的方法，添加自动索引非常容易，使用 autoindex on 即可。下面的配置，将在访问特定请求时返回目录结构。&lt;/p>
&lt;pre>&lt;code>官方参考： http://nginx.org/en/docs/http/ngx_http_autoindex_module.html
&lt;/code>&lt;/pre>
&lt;pre tabindex="0">&lt;code> server {
listen 80;
... ...
location /index_dir {
autoindex on;
}
}
&lt;/code>&lt;/pre>&lt;p>除了简单地使用自动索引打开或关闭之外，还可以对其做其他的配置，包括：&lt;/p>
&lt;pre tabindex="0">&lt;code> autoindex_exact_size; 显示输出的确切文件大小，还是最接近的KB，MB或GB。默认为on，显示出文件的确切大小，单位是bytes。改为off后，显示出文件的大概大小，单位是kB或者MB或者GB。
autoindex_format; 该指令指定Nginx索引列表应以什么格式输出。该指令有4个选项：html/xml/json/jsonp。
autoindex_localtime; 显示的文件时间为GMT时间。 注意:改为on后，显示的文件时间为文件的服务器时间。
&lt;/code>&lt;/pre>&lt;p>使用这几个配置后配置内容类似于如下内容：&lt;/p>
&lt;pre tabindex="0">&lt;code>location /index_dir/ {
root /data/index_dir/;
autoindex on;
autoindex_exact_size off;
autoindex_format html;
autoindex_localtime on;
}
&lt;/code>&lt;/pre>&lt;p>如果有中文目录的话会出现乱码问题，所以还需要在下面添加这一句：&lt;/p>
&lt;pre tabindex="0">&lt;code>charset utf-8;
&lt;/code>&lt;/pre>&lt;p>或&lt;/p>
&lt;pre tabindex="0">&lt;code>charset utf-8,gbk;
&lt;/code>&lt;/pre></description></item><item><title>PostgresSQL 基本用法：新建数据库、用户、连接、备份/恢复数据库</title><link>https://blog.baicai.me/article/2022/create_use1/</link><pubDate>Fri, 22 Jul 2022 14:26:40 +0800</pubDate><author>admin@baicai.me (白菜)</author><guid>https://blog.baicai.me/article/2022/create_use1/</guid><description>&lt;p>系统环境：
Debian 11&lt;/p>
&lt;h3 id="切换到超级用户">切换到超级用户：&lt;/h3>
&lt;pre tabindex="0">&lt;code> sudo su postgres
&lt;/code>&lt;/pre>&lt;h3 id="进入psql">进入psql：&lt;/h3>
&lt;pre tabindex="0">&lt;code> psql
&lt;/code>&lt;/pre>&lt;h3 id="创建一个用户">创建一个用户：&lt;/h3>
&lt;pre tabindex="0">&lt;code> CREATE USER username WITH PASSWORD &amp;#39;password&amp;#39;;
&lt;/code>&lt;/pre>&lt;h3 id="查看角色列表">查看角色列表：&lt;/h3>
&lt;pre tabindex="0">&lt;code> \du
&lt;/code>&lt;/pre>&lt;h3 id="创建数据库并制定所有者和编码">创建数据库并制定所有者和编码：&lt;/h3>
&lt;pre tabindex="0">&lt;code> CREATE DATABASE dbname WITH OWNER username ENCODING UTF8;
&lt;/code>&lt;/pre>&lt;h4 id="创建一个数据库">创建一个数据库：&lt;/h4>
&lt;pre tabindex="0">&lt;code> CREATE DATABASE dbname;
&lt;/code>&lt;/pre>&lt;h4 id="查看数据库列表">查看数据库列表：&lt;/h4>
&lt;pre tabindex="0">&lt;code> \l
&lt;/code>&lt;/pre>&lt;h4 id="更改刚创建的数据库所有权">更改刚创建的数据库所有权：&lt;/h4>
&lt;pre tabindex="0">&lt;code> ALTER DATABASE dbname OWNER TO username;
&lt;/code>&lt;/pre>&lt;h4 id="删除表字段">删除表字段&lt;/h4>
&lt;p>要删除一个字段，使用下面这样的命令：&lt;/p>
&lt;pre tabindex="0">&lt;code> ALTER TABLE products DROP COLUMN description;
&lt;/code>&lt;/pre>&lt;p>不管字段里有啥数据，都会消失，和这个字段相关的约束也会被删除。不过， 如果这个字段被另一个表的外键约束所引用，PostgreSQL 则不会隐含地删除该约束。你可以通过使用CASCADE指明删除任何依赖该字段的东西：&lt;/p>
&lt;pre tabindex="0">&lt;code> ALTER TABLE products DROP COLUMN description CASCADE;
&lt;/code>&lt;/pre>&lt;h3 id="通过psql连接数据库">通过psql连接数据库&lt;/h3>
&lt;pre tabindex="0">&lt;code> psql -h 127.0.0.1 -p 5432 -U username -d dbname
&lt;/code>&lt;/pre>&lt;h3 id="备份数据库">备份数据库&lt;/h3>
&lt;pre tabindex="0">&lt;code> pg_dump dbname &amp;gt; dbname.dump
&lt;/code>&lt;/pre>&lt;h3 id="恢复数据库">恢复数据库&lt;/h3>
&lt;pre tabindex="0">&lt;code> psql -f dbname.dump -d dbname
&lt;/code>&lt;/pre></description></item><item><title>查看 Debian 系统版本的方式</title><link>https://blog.baicai.me/article/2022/debian_version_check/</link><pubDate>Fri, 22 Jul 2022 11:04:30 +0800</pubDate><author>admin@baicai.me (白菜)</author><guid>https://blog.baicai.me/article/2022/debian_version_check/</guid><description>&lt;p>查看 Dibian 系统发行版本号的方式&lt;/p>
&lt;h3 id="1-使用-lsb_release-命令">1. 使用 lsb_release 命令&lt;/h3>
&lt;p>lsb_release 命令可用于查看 Linux 发行版操作系统的具体版本。它可能尚未安装在你的操作系统中，因此你需要先安装它。运行以下命令来安装 lsb_release：&lt;/p>
&lt;pre tabindex="0">&lt;code> apt-get install lsb-release
&lt;/code>&lt;/pre>&lt;p>安装完成之后，只需要输入下面的命令就可以查看到你当前系统的版本信息：&lt;/p>
&lt;pre tabindex="0">&lt;code> lsb_release -a
&lt;/code>&lt;/pre>&lt;p>你将看到类似下面的结果：&lt;/p>
&lt;pre tabindex="0">&lt;code> No LSB modules are available.
Distributor ID: Debian
Description: Debian GNU/Linux 11 (bullseye)
Release: 11
Codename: bullseye
&lt;/code>&lt;/pre>&lt;p>以上运行结果说明当前使用的操作系统版本是 Debian 11.&lt;/p>
&lt;h3 id="2-查看-etcissue-文件">2. 查看 /etc/issue 文件&lt;/h3>
&lt;p>第二种查看当前 Debian 版本的方法是查看位于 /etc 目录中的 issue 文件。你可以使用 cat 命令查看文件的内容，输入下面的命令：&lt;/p>
&lt;pre tabindex="0">&lt;code> cat /etc/issue
&lt;/code>&lt;/pre>&lt;p>你将看到类似下面的结果：&lt;/p>
&lt;pre tabindex="0">&lt;code> Debian GNU/Linux 11 \n \l
&lt;/code>&lt;/pre>&lt;h3 id="3-查看-etcos-release-文件">3. 查看 /etc/os-release 文件&lt;/h3>
&lt;p>/etc/os-release 是一个包含操作系统标识数据的文件，它只能在运行 systemd 的最新 Debian 发行版上找到。同样可以使用 cat 命令查看该文件的内容，输入下面的命令：&lt;/p>
&lt;pre tabindex="0">&lt;code>cat /etc/os-release
&lt;/code>&lt;/pre>&lt;p>你将看到类似下面的结果：&lt;/p>
&lt;pre tabindex="0">&lt;code> PRETTY_NAME=&amp;#34;Debian GNU/Linux 11 (bullseye)&amp;#34;
NAME=&amp;#34;Debian GNU/Linux&amp;#34;
VERSION_ID=&amp;#34;11&amp;#34;
VERSION=&amp;#34;11 (bullseye)&amp;#34;
VERSION_CODENAME=bullseye
ID=debian
HOME_URL=&amp;#34;https://www.debian.org/&amp;#34;
SUPPORT_URL=&amp;#34;https://www.debian.org/support&amp;#34;
BUG_REPORT_URL=&amp;#34;https://bugs.debian.org/&amp;#34;
&lt;/code>&lt;/pre>&lt;p>如果想知道更具体的小版本号，可以查看 /etc/debian_version 文件，输入下面的命令：&lt;/p>
&lt;pre tabindex="0">&lt;code> cat /etc/debian_version
&lt;/code>&lt;/pre>&lt;p>你将看到类似下面的结果：&lt;/p>
&lt;pre tabindex="0">&lt;code> 11.4
&lt;/code>&lt;/pre>&lt;h3 id="4-使用-uname-命令">4. 使用 uname 命令&lt;/h3>
&lt;p>uname 命令可以显示电脑以及操作系统的相关信息，输入下面的命令：&lt;/p>
&lt;pre tabindex="0">&lt;code> uname -a
&lt;/code>&lt;/pre>&lt;p>你将看到类似下面的结果：&lt;/p>
&lt;pre tabindex="0">&lt;code> Linux baicai-l01 5.10.0-16-amd64 #1 SMP Debian 5.10.127-1 (2022-06-30) x86_64 GNU/Linux
&lt;/code>&lt;/pre>&lt;h3 id="5-使用-hostnamectl-命令">5. 使用 hostnamectl 命令&lt;/h3>
&lt;p>hostnamectl 命令用于配置或修改系统的主机名，不过也使用此命令来获取 Debian 系统的版本，只需要直接输入 hostnamectl 即可：&lt;/p>
&lt;pre tabindex="0">&lt;code> hostnamectl
&lt;/code>&lt;/pre>&lt;p>你将看到类似下面的结果：&lt;/p>
&lt;pre tabindex="0">&lt;code> Static hostname: baicai-l01
Icon name: computer-desktop
Chassis: desktop
Machine ID: xxx
Boot ID: xxx
Operating System: Debian GNU/Linux 11 (bullseye)
Kernel: Linux 5.10.0-16-amd64
Architecture: x86-64
&lt;/code>&lt;/pre></description></item><item><title>删除 Debian Gnome 所有默认安装的游戏</title><link>https://blog.baicai.me/article/2022/debian_gnome_remove_game/</link><pubDate>Fri, 22 Jul 2022 10:35:22 +0800</pubDate><author>admin@baicai.me (白菜)</author><guid>https://blog.baicai.me/article/2022/debian_gnome_remove_game/</guid><description>&lt;p>我用以下命令删除Debian 11.5（带有gnome）中的所有预装游戏：&lt;/p>
&lt;div class="highlight">&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;">&lt;code class="language-bash" data-lang="bash">&lt;span style="display:flex;">&lt;span> sudo apt purge aisleriot gnome-sudoku gnome-nibbles ace-of-penguins gnomine gbrainy gnome-sushi gnome-taquin gnome-tetravex gnome-robots gnome-chess lightsoff swell-foop quadrapassel tali gnome-mahjongg gnome-2048 iagno gnome-klotski five-or-more gnome-mines four-in-a-row hitori &lt;span style="color:#f92672">&amp;amp;&amp;amp;&lt;/span> sudo apt autoremove
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div></description></item><item><title>如何关闭 Ubuntu 中的开放端口？</title><link>https://blog.baicai.me/article/2022/ubuntu_kill_port_porc/</link><pubDate>Sun, 19 Jun 2022 22:53:02 +0800</pubDate><author>admin@baicai.me (白菜)</author><guid>https://blog.baicai.me/article/2022/ubuntu_kill_port_porc/</guid><description>&lt;p>如何关闭 Ubuntu 中的开放端口？&lt;/p>
&lt;h3 id="问题描述">问题描述&lt;/h3>
&lt;p>列出所有打开的端口，以关闭一些应用程序的端口。&lt;/p>
&lt;h3 id="最佳办法">最佳办法&lt;/h3>
&lt;p>如果要关闭端口，则必须终止进程或停止相关服务。
可以使用 netstat -nalp 和 lsof -i:port 工具来识别打开端口后面的进程/二进制文件。&lt;/p>
&lt;p>netstat 可用于查看端口统计信息。
要显示所有开放端口的列表：&lt;/p>
&lt;pre>&lt;code>sudo netstat -lnp
&lt;/code>&lt;/pre>
&lt;p>列出所有侦听端口号以及每个负责的进程。终止或终止进程以关闭端口。 ( kill , pkill …)&lt;/p>
&lt;p>关闭一个打开的端口：&lt;/p>
&lt;pre>&lt;code>sudo fuser -k port_no/tcp
&lt;/code>&lt;/pre>
&lt;p>例子：&lt;/p>
&lt;pre>&lt;code>sudo fuser -k 8080/tcp
&lt;/code>&lt;/pre>
&lt;h3 id="次佳办法">次佳办法&lt;/h3>
&lt;p>要在 ubuntu 中关闭开放端口，可以使用以下命令&lt;/p>
&lt;pre>&lt;code>sudo kill $(sudo lsof -t -i:3000)
&lt;/code>&lt;/pre>
&lt;p>代替 3000 你可以指定你的端口号&lt;/p>
&lt;p>lsof 命令将提供有关进程打开的文件的信息&lt;/p>
&lt;p>-t ：此标志指定 lsof 应仅生成带有进程标识符且没有标头的简洁输出 – 例如，以便可以将输出通过管道传输到 kill(1)。此选项选择 -w 选项。&lt;/p>
&lt;p>-i ：此标志选择任何 Internet 地址与 i 中指定的地址匹配的文件列表。如果未指定地址，此选项将选择所有 Internet 和 x.25 (HP-UX) 网络文件的列表。&lt;/p>
&lt;h3 id="防火墙规则应用">防火墙规则应用&lt;/h3>
&lt;pre>&lt;code>sudo ufw allow 22
sudo ufw deny 22
&lt;/code>&lt;/pre>
&lt;h3 id="附注">附注&lt;/h3>
&lt;p>关闭特定进程&lt;/p>
&lt;pre>&lt;code>kill $(ps -e|grep firefox|awk '{print $1}')
&lt;/code>&lt;/pre></description></item><item><title>解决 Firefox 访问weibo搜索或热搜提示 建立安全连接失败</title><link>https://blog.baicai.me/article/2022/firefox_weibo_alpn/</link><pubDate>Fri, 06 May 2022 20:57:36 +0800</pubDate><author>admin@baicai.me (白菜)</author><guid>https://blog.baicai.me/article/2022/firefox_weibo_alpn/</guid><description>&lt;p>应用版本：firefox 开发者版 v101
问题描述：微博主页可以正常访问，但点击搜索或热搜链接，都提示：&lt;/p>
&lt;pre tabindex="0">&lt;code> 建立安全连接失败
连接到 s.weibo.com 时发生错误。
由于不能验证所收到的数据是否可信，无法显示您想要查看的页面。
建议向此网站的管理员反馈这个问题。
详细了解…
&lt;/code>&lt;/pre>&lt;p>通过curl -v “网址” 反复重试对比发现在访问微博热搜的时候有一个加密协商被“微博账户认证网关服务器”拒绝了。&lt;/p>
&lt;p>具体测试指令：
通过&lt;/p>
&lt;pre tabindex="0">&lt;code> curl -v &amp;#34;https://s.weibo.com/weibo?q=%23%E7%A5%9D%E8%9E%8D%E5%8F%B7%E5%87%86%E5%A4%87%E5%9C%A8%E7%81%AB%E6%98%9F%E8%B6%8A%E5%86%AC%23&amp;amp;topic_ad=&amp;#34;
&lt;/code>&lt;/pre>&lt;p>得到302跳转请求链接
继续&lt;/p>
&lt;pre tabindex="0">&lt;code> curl -v &amp;#34;https://passport.weibo.com/visitor/visitor?entry=miniblog&amp;amp;a=enter&amp;amp;url=https%3A%2F%2Fs.weibo.com%2Fweibo%3Fq%3D%2523%25E7%25A5%259D%25E8%259E%258D%25E5%258F%25B7%25E5%2587%2586%25E5%25A4%2587%25E5%259C%25A8%25E7%2581%25AB%25E6%2598%259F%25E8%25B6%258A%25E5%2586%25AC%2523%26topic_ad%3D&amp;amp;domain=.weibo.com&amp;amp;sudaref=&amp;amp;ua=php-sso_sdk_client-0.6.29&amp;amp;_rand=1651842429.1375&amp;#34;
&lt;/code>&lt;/pre>&lt;p>返回&lt;/p>
&lt;pre tabindex="0">&lt;code> ……
* TLSv1.2 (IN), TLS handshake, Finished (20):
* SSL connection using TLSv1.2 / AES256-GCM-SHA384
* ALPN, server did not agree to a protocol
* Server certificate:
* subject: C=CN; ST=Beijing; O=Sina.com Technology(China)Co.,ltd; CN=sina.com
……
&lt;/code>&lt;/pre>&lt;p>注意这段提示：&lt;/p>
&lt;pre tabindex="0">&lt;code> ALPN, server did not agree to a protocol
&lt;/code>&lt;/pre>&lt;h3 id="alpn">ALPN&lt;/h3>
&lt;p>ALPN(Application-Layer Protocol Negotiation):应用层协议协商是 TLS 的一个扩展，故而应用层协议在协商加密协议的过程中，避免了额外的往返通讯开销。
ALPN支持任意应用层协议的协商，目前应用最多是HTTP2的协商。当前主流浏览器，都只支持基于 HTTPS 部署的 HTTP/2，因为浏览器是基于ALPN协议来判断服务器是否支持HTTP2协议。&lt;/p>
&lt;h3 id="浏览器协商原理">浏览器协商原理&lt;/h3>
&lt;p>可以通过WireShark抓包分析ALPN协商协议交互的过程&lt;/p>
&lt;pre>&lt;code>*浏览器在进行SSL连接，第一次发送Client Hello包时，在扩展字段里携带浏览器支持的版本。
*服务器在返回Server Hello包时，如果服务器支持http 2，则会返回h2，如果不支持，则从客户端支持的协议列表中选取一个它支持的协议，一般为http/1.1。
&lt;/code>&lt;/pre>
&lt;p>浏览器和服务端都支持ALPN 协商，是用上 HTTP/2 的大前提。&lt;/p>
&lt;pre>&lt;code>大部分 Web Server 都依赖 OpenSSL 库提供 https服务，是否支持 ALPN 完全取决于使用的 OpenSSL 版本，OpenSSL 1.0.2 版本才开始支持 ALPN。
&lt;/code>&lt;/pre>
&lt;h3 id="关闭firefox-alpn功能">关闭Firefox ALPN功能&lt;/h3>
&lt;p>地址栏输入&lt;/p>
&lt;pre tabindex="0">&lt;code> about:config
&lt;/code>&lt;/pre>&lt;p>确认风险提示&lt;/p>
&lt;pre>&lt;code>输入“ALPN”
&lt;/code>&lt;/pre>
&lt;p>将&lt;/p>
&lt;pre tabindex="0">&lt;code> security.ssl.enable_alpn
&lt;/code>&lt;/pre>&lt;p>的值切换为false&lt;/p>
&lt;p>参考：
&lt;a href="https://developer.mozilla.org/zh-CN/docs/Glossary/ALPN">ALPN&lt;/a>&lt;/p></description></item><item><title>上传公钥实现ssh登录</title><link>https://blog.baicai.me/article/2022/linux_ssh_copy_id/</link><pubDate>Sat, 12 Mar 2022 20:22:55 +0800</pubDate><author>admin@baicai.me (白菜)</author><guid>https://blog.baicai.me/article/2022/linux_ssh_copy_id/</guid><description>&lt;h3 id="生成密钥和公钥">生成密钥和公钥&lt;/h3>
&lt;p>如果之前已经存在就不用重新生成了&lt;/p>
&lt;div class="highlight">&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;">&lt;code class="language-bash" data-lang="bash">&lt;span style="display:flex;">&lt;span>$ ssh-keygen -t rsa
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>&lt;h3 id="上传公钥">上传公钥&lt;/h3>
&lt;div class="highlight">&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;">&lt;code class="language-bash" data-lang="bash">&lt;span style="display:flex;">&lt;span>$ ssh-copy-id -i ~/.ssh/id_rsa.pub root@192.168.0.1
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>&lt;p>其中root 服务器用户， 192.168.0.1 是服务器ip。之后按照提示输入密码即可&lt;/p>
&lt;h3 id="连接到服务器">连接到服务器&lt;/h3>
&lt;p>直接使用ssh直接连接服务器，无需输入密码&lt;/p>
&lt;div class="highlight">&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;">&lt;code class="language-bash" data-lang="bash">&lt;span style="display:flex;">&lt;span>$ ssh root@192.168.0.1
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div></description></item><item><title>在 Linux 命令行中使用的 6 个元字符</title><link>https://blog.baicai.me/article/2022/linux_metacharacters/</link><pubDate>Mon, 14 Feb 2022 17:37:24 +0800</pubDate><author>admin@baicai.me (白菜)</author><guid>https://blog.baicai.me/article/2022/linux_metacharacters/</guid><description>&lt;pre>&lt;code>在 Linux 命令行上使用元字符是提高生产力的一个好方法。
&lt;/code>&lt;/pre>
&lt;p>许多 Linux 电脑是无头运行的，你可以在命令行上完成所有的管理任务。它使用许多所有人都熟悉的基本命令，如 ls、ls-l、ls-l、cd、pwd、top 等等。&lt;/p>
&lt;pre>&lt;code>Linux 上的 Shell 元字符
&lt;/code>&lt;/pre>
&lt;p>你可以通过使用元字符来扩展这些命令。&lt;/p>
&lt;h3 id="管道符-">管道符 |&lt;/h3>
&lt;p>假设我想知道我的系统上运行的 Firefox 的所有实例。我可以使用带有 -ef 参数的 ps 命令来列出我系统上运行的所有程序实例。现在我想只看那些涉及 Firefox 的实例。我使用了我最喜欢的元字符之一，管道符 |，将其结果送到 grep，用它来搜索模式：&lt;/p>
&lt;div class="highlight">&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;">&lt;code class="language-bash" data-lang="bash">&lt;span style="display:flex;">&lt;span>$ ps -ef | grep firefox
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>&lt;h3 id="输出重定向-">输出重定向 &amp;gt;&lt;/h3>
&lt;p>另一个我最喜欢的元字符是输出重定向 &amp;gt;。我用它来打印 dmesg 命令结果中所有 AMD 相关的结果。你可能会发现这在硬件故障排除中很有帮助：&lt;/p>
&lt;div class="highlight">&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;">&lt;code class="language-bash" data-lang="bash">&lt;span style="display:flex;">&lt;span>$ dmesg | grep amd &amp;gt; amd.txt
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>$ cat amd.txt
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#f92672">[&lt;/span> 0.897&lt;span style="color:#f92672">]&lt;/span> amd_uncore: &lt;span style="color:#ae81ff">4&lt;/span> amd_df counters detected
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#f92672">[&lt;/span> 0.897&lt;span style="color:#f92672">]&lt;/span> amd_uncore: &lt;span style="color:#ae81ff">6&lt;/span> amd_l3 counters detected
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#f92672">[&lt;/span> 0.898&lt;span style="color:#f92672">]&lt;/span> perf/amd_iommu: Detected AMD IOMMU &lt;span style="color:#75715e">#0 (2 banks, 4 counters/bank).&lt;/span>
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>&lt;h3 id="星号-">星号 *&lt;/h3>
&lt;p>星号 *（通配符）是寻找具有相同扩展名的文件时我的最爱，如 .jpg 或 .png。我首先进入我的系统中的 Picture 目录，并使用类似以下的命令：&lt;/p>
&lt;div class="highlight">&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;">&lt;code class="language-bash" data-lang="bash">&lt;span style="display:flex;">&lt;span>$ ls *.png
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>BlountScreenPicture.png
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>DisplaySettings.png
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>EbookStats.png
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>StrategicPlanMenu.png
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>Screenshot from 01-24 19-35-05.png
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>&lt;h3 id="波浪号-">波浪号 ~&lt;/h3>
&lt;p>波浪号 ~ 是在 Linux 系统上通过输入以下命令快速返回你的家目录的一种方法：&lt;/p>
&lt;div class="highlight">&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;">&lt;code class="language-bash" data-lang="bash">&lt;span style="display:flex;">&lt;span>$ cd ~
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>$ pwd
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>/home/don
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>&lt;h3 id="美元符号-">美元符号 $&lt;/h3>
&lt;p>$ 符号作为一个元字符有不同的含义。当用于匹配模式时，它意味着任何以给定字符串结尾的字符串。例如，当同时使用元字符 | 和 $ 时：&lt;/p>
&lt;div class="highlight">&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;">&lt;code class="language-bash" data-lang="bash">&lt;span style="display:flex;">&lt;span>$ ls | grep png$
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>BlountScreenPicture.png
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>DisplaySettings.png
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>EbookStats.png
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>StrategicPlanMenu.png
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>Screenshot from 01-24 19-35-05.png
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>&lt;h3 id="上尖号-">上尖号 ^&lt;/h3>
&lt;p>符号 ^ 将结果限制在以给定字符串开始的项目上。例如，当同时使用元字符 | 和 ^ 时：&lt;/p>
&lt;div class="highlight">&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;">&lt;code class="language-bash" data-lang="bash">&lt;span style="display:flex;">&lt;span>$ ls | grep ^Screen
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>Screenshot from 01-24 19-35-05.png
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>&lt;p>这些元字符中有许多是通往 正则表达式 的大门，所以还有很多东西可以探索。你最喜欢的 Linux 元字符是什么，它们是如何节省你的工作的？&lt;/p>
&lt;p>via:
&lt;a href="https://opensource.com/article/22/2/metacharacters-linux">1&lt;/a>
&lt;a href="https://linux.cn/article-14270-1.html">2&lt;/a>&lt;/p></description></item><item><title>ubuntu上安装微信(wechat)</title><link>https://blog.baicai.me/article/2022/ubuntu_wechat-install/</link><pubDate>Sun, 30 Jan 2022 15:19:12 +0800</pubDate><author>admin@baicai.me (白菜)</author><guid>https://blog.baicai.me/article/2022/ubuntu_wechat-install/</guid><description>&lt;h2 id="介绍">介绍&lt;/h2>
&lt;p>由于微信官网 &lt;a href="https://weixin.qq.com/">https://weixin.qq.com/&lt;/a> 没有linux版本的下载和安装方法，但微信确实提供了优麒麟发行版的官方版本，所以就有了下面的安装方法。&lt;/p>
&lt;h2 id="安装方法">安装方法&lt;/h2>
&lt;p>打开优麒麟应用商店官网，然后下载应用，就看到微信了
&lt;a href="https://www.ubuntukylin.com/applications/106-cn.html">https://www.ubuntukylin.com/applications/106-cn.html&lt;/a>
下载deb包，用命令sudo dpkg -i ，就能安装上了，而且可以用。
这是linux原生的，功能少点，但比wine的要轻巧不少。&lt;/p>
&lt;h2 id="安装方法2">安装方法2&lt;/h2>
&lt;p>下载链接在方法1中，优麒麟应用商店微信应用页面右键 “64位下载” ——&amp;gt; “复制链接”
终端下载Deb安装：&lt;/p>
&lt;div class="highlight">&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;">&lt;code class="language-bash" data-lang="bash">&lt;span style="display:flex;">&lt;span> wget -O ~/weixin.deb &lt;span style="color:#e6db74">&amp;#34;http://archive.ubuntukylin.com/software/pool/partner/weixin_2.1.1_amd64.deb&amp;#34;&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> sudo dpkg -i ~/weixin.deb
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div></description></item><item><title>Docker 运行 postgreSQL</title><link>https://blog.baicai.me/article/2021/docker_postgres/</link><pubDate>Thu, 09 Dec 2021 14:19:08 +0800</pubDate><author>admin@baicai.me (白菜)</author><guid>https://blog.baicai.me/article/2021/docker_postgres/</guid><description>&lt;h3 id="简单步骤">简单步骤&lt;/h3>
&lt;ol>
&lt;li>
&lt;p>安装docker，可参考 &lt;a href="https://blog.baicai.me/article/2021/docker_start/">安装docker及简单的使用&lt;/a> 或 百度解决；&lt;/p>
&lt;/li>
&lt;li>
&lt;p>拉取postgreSQL的docker镜像文件：&lt;/p>
&lt;/li>
&lt;/ol>
&lt;div class="highlight">&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;">&lt;code class="language-bash" data-lang="bash">&lt;span style="display:flex;">&lt;span> docker pull postgres
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>&lt;ol start="3">
&lt;li>创建 docker volume，名字为“dv_pgdata&amp;quot;（其实可以省略手动创建，直接跑下一步，docker也会自动创建的）：&lt;/li>
&lt;/ol>
&lt;div class="highlight">&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;">&lt;code class="language-bash" data-lang="bash">&lt;span style="display:flex;">&lt;span> docker volume create dv_pgdata
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>&lt;ol start="4">
&lt;li>启动容器，用-v来指定把postgres的数据目录映射到上面创建的dv_pgdata里面：&lt;/li>
&lt;/ol>
&lt;div class="highlight">&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;">&lt;code class="language-bash" data-lang="bash">&lt;span style="display:flex;">&lt;span>docker run --name my_postgres -v dv_pgdata:/var/lib/postgresql/data -e POSTGRES_PASSWORD&lt;span style="color:#f92672">=&lt;/span>xxxxxx -p 5432:5432 -d postgres
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>&lt;ol start="5">
&lt;li>这时候查看已存在的docker volume:&lt;/li>
&lt;/ol>
&lt;div class="highlight">&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;">&lt;code class="language-bash" data-lang="bash">&lt;span style="display:flex;">&lt;span>docker volume ls
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>&lt;ol start="6">
&lt;li>查看volume信息：&lt;/li>
&lt;/ol>
&lt;div class="highlight">&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;">&lt;code class="language-bash" data-lang="bash">&lt;span style="display:flex;">&lt;span>cn2d6@navxin-desktop:~$ docker inspect dv_pgdata
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>&lt;ol start="7">
&lt;li>在宿主机，也可以直接查看volume里的内容：&lt;/li>
&lt;/ol>
&lt;div class="highlight">&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;">&lt;code class="language-bash" data-lang="bash">&lt;span style="display:flex;">&lt;span>cn2d6@navxin-desktop:~$ cd /var/lib/docker/volumes/dv_pgdata/_data
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>cn2d6@navxin-desktop:~$ ll
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>&lt;ol start="8">
&lt;li>查看postgresql：&lt;/li>
&lt;/ol>
&lt;div class="highlight">&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;">&lt;code class="language-bash" data-lang="bash">&lt;span style="display:flex;">&lt;span>cn2d6@navxin-desktop:~$docker exec -it &lt;span style="color:#ae81ff">618&lt;/span> bash
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>root@618f1a4128ee:/# psql -U postgres -d postgres -p &lt;span style="color:#ae81ff">5432&lt;/span> -h 127.0.0.1
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>&lt;ol start="9">
&lt;li>更多的时候，我们希望能用图形界面来管理和操作数据库，可以部署pgadmin工具（例如下面），然后在浏览器中访问宿主机的5080端口，便能打开pgadmin。&lt;/li>
&lt;/ol>
&lt;div class="highlight">&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;">&lt;code class="language-bash" data-lang="bash">&lt;span style="display:flex;">&lt;span>docker pull dpage/pgadmin4
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>docker run --name pgadmin -p 5080:80 &lt;span style="color:#ae81ff">\
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#ae81ff">&lt;/span> -e &lt;span style="color:#e6db74">&amp;#39;PGADMIN_DEFAULT_EMAIL=hi@nav.xin&amp;#39;&lt;/span> &lt;span style="color:#ae81ff">\
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#ae81ff">&lt;/span> -e &lt;span style="color:#e6db74">&amp;#39;PGADMIN_DEFAULT_PASSWORD=xxxxxx&amp;#39;&lt;/span> &lt;span style="color:#ae81ff">\
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#ae81ff">&lt;/span> -e &lt;span style="color:#e6db74">&amp;#39;PGADMIN_CONFIG_ENHANCED_COOKIE_PROTECTION=True&amp;#39;&lt;/span> &lt;span style="color:#ae81ff">\
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#ae81ff">&lt;/span> -e &lt;span style="color:#e6db74">&amp;#39;PGADMIN_CONFIG_LOGIN_BANNER=&amp;#34;Authorised users only!&amp;#34;&amp;#39;&lt;/span> &lt;span style="color:#ae81ff">\
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#ae81ff">&lt;/span> -e &lt;span style="color:#e6db74">&amp;#39;PGADMIN_CONFIG_CONSOLE_LOG_LEVEL=10&amp;#39;&lt;/span> &lt;span style="color:#ae81ff">\
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#ae81ff">&lt;/span> -d dpage/pgadmin4
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>&lt;h3 id="用docker-compose部署postgresql和pgadmin4">用docker-compose部署postgresql和pgAdmin4&lt;/h3>
&lt;h4 id="准备步骤">准备步骤&lt;/h4>
&lt;p>安装docker-compose&lt;/p>
&lt;div class="highlight">&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;">&lt;code class="language-bash" data-lang="bash">&lt;span style="display:flex;">&lt;span> apt install docker-compose
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>&lt;p>确定已经pull好postgres和pgAdmin4镜像,若未完成：&lt;/p>
&lt;div class="highlight">&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;">&lt;code class="language-bash" data-lang="bash">&lt;span style="display:flex;">&lt;span> docker pull postgres
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> docker pull dpage/pgadmin4
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>&lt;h4 id="配置内容">配置内容&lt;/h4>
&lt;p>然后在任意目录下新建文件docker-compose.yml:&lt;/p>
&lt;div class="highlight">&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;">&lt;code class="language-bash" data-lang="bash">&lt;span style="display:flex;">&lt;span> touch ./docker-compose.yml
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>&lt;p>内容如下：&lt;/p>
&lt;div class="highlight">&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;">&lt;code class="language-yaml" data-lang="yaml">&lt;span style="display:flex;">&lt;span> &lt;span style="color:#75715e"># Use postgres/example user/password credentials &lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#75715e"># https://hub.docker.com/_/postgres?tab=description&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#75715e"># 在当前目录下运行：sudo docker-compose up -d&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#75715e"># 若需停止运行，在当前目录运行：sudo docker-compose down&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#75715e"># docker路由地址查看： sudo docker inspect postgres_baicai&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#75715e"># sudo docker kill $(sudo docker ps -aq)&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#75715e"># sudo docker rm $(sudo docker ps -aq)&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#f92672">version&lt;/span>: &lt;span style="color:#e6db74">&amp;#39;3.1&amp;#39;&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#f92672">services&lt;/span>:
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#f92672">db&lt;/span>:
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#f92672">image&lt;/span>: &lt;span style="color:#ae81ff">postgres&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#f92672">restart&lt;/span>: &lt;span style="color:#ae81ff">always&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#f92672">privileged&lt;/span>: &lt;span style="color:#66d9ef">true&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#f92672">container_name&lt;/span>: &lt;span style="color:#ae81ff">postgres_baicai&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#f92672">ports&lt;/span>:
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> - &lt;span style="color:#ae81ff">5432&lt;/span>:&lt;span style="color:#ae81ff">5432&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#f92672">environment&lt;/span>:
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#f92672">POSTGRES_PASSWORD&lt;/span>: &lt;span style="color:#ae81ff">你的密码&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#f92672">PGDATA&lt;/span>: &lt;span style="color:#ae81ff">/var/lib/postgresql/data/pgdata&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#f92672">volumes&lt;/span>:
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> - &lt;span style="color:#ae81ff">/navxin/kn1/baicai_docker/baicai_postgres/pg_data:/var/lib/postgresql/data&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#75715e"># - pgdata:/var/lib/postgresql/data&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#f92672">pgadmin4&lt;/span>:
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#f92672">image&lt;/span>: &lt;span style="color:#ae81ff">dpage/pgadmin4&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#f92672">restart&lt;/span>: &lt;span style="color:#ae81ff">always&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#f92672">container_name&lt;/span>: &lt;span style="color:#ae81ff">pgadmin_baicai&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#f92672">ports&lt;/span>:
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> - &lt;span style="color:#ae81ff">5080&lt;/span>:&lt;span style="color:#ae81ff">80&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#f92672">environment&lt;/span>:
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#f92672">PGADMIN_DEFAULT_EMAIL&lt;/span>: &lt;span style="color:#e6db74">&amp;#34;hi@nav.xin&amp;#34;&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#f92672">PGADMIN_DEFAULT_PASSWORD&lt;/span>: &lt;span style="color:#ae81ff">你的密码&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#75715e"># volumes:&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#75715e"># pgdata:&lt;/span>
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>&lt;h4 id="部署">部署&lt;/h4>
&lt;p>在当前目录下运行：&lt;/p>
&lt;div class="highlight">&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;">&lt;code class="language-bash" data-lang="bash">&lt;span style="display:flex;">&lt;span> docker-compose up -d
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>&lt;p>若需停止运行，在当前目录运行：&lt;/p>
&lt;div class="highlight">&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;">&lt;code class="language-bash" data-lang="bash">&lt;span style="display:flex;">&lt;span> docker-compose down
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>&lt;p>连接步骤&lt;/p>
&lt;p>打开浏览器，输入localhost:5080，登录pgAdmin4之后，点击添加新服务器，特别注意，在连接地址IP里应该填写docker路由地址，端口填写5432。
docker路由地址查看方法&lt;/p>
&lt;div class="highlight">&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;">&lt;code class="language-bash" data-lang="bash">&lt;span style="display:flex;">&lt;span> docker inspect postgres_baicai
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>&lt;p>在输出内容中找到Gateway，对应的地址即为docker路由地址。&lt;/p>
&lt;h3 id="更多参考">更多参考：&lt;/h3>
&lt;p>&lt;a href="https://blog.baicai.me/article/2021/docker_start/">安装docker及简单的使用&lt;/a>
&lt;a href="https://hub.docker.com/_/postgres?tab=description">postgres&lt;/a>
&lt;a href="https://hub.docker.com/r/dpage/pgadmin4">dpage/pgadmin4&lt;/a>&lt;/p></description></item><item><title>Ubuntu使用systemd配置开机运行service</title><link>https://blog.baicai.me/article/2021/ubuntu_systemd_service/</link><pubDate>Wed, 01 Dec 2021 22:44:28 +0800</pubDate><author>admin@baicai.me (白菜)</author><guid>https://blog.baicai.me/article/2021/ubuntu_systemd_service/</guid><description>&lt;h2 id="systemd">systemd&lt;/h2>
&lt;p>Systemd 是 Linux 系统工具，用来启动守护进程，已成为大多数发行版的标准配置。&lt;/p>
&lt;h2 id="由来">由来&lt;/h2>
&lt;p>历史上，Linux 的启动一直采用init进程。&lt;/p>
&lt;p>下面的命令用来启动服务。&lt;/p>
&lt;div class="highlight">&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;">&lt;code class="language-bash" data-lang="bash">&lt;span style="display:flex;">&lt;span> $ sudo /etc/init.d/apache2 start
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#75715e"># 或者&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> $ service apache2 start
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>&lt;p>这种方法有两个缺点。&lt;/p>
&lt;p>一是启动时间长。init进程是串行启动，只有前一个进程启动完，才会启动下一个进程。&lt;/p>
&lt;p>二是启动脚本复杂。init进程只是执行启动脚本，不管其他事情。脚本需要自己处理各种情况，这往往使得脚本变得很长。&lt;/p>
&lt;h2 id="systemd-概述">Systemd 概述&lt;/h2>
&lt;p>Systemd 就是为了解决这些问题而诞生的。它的设计目标是，为系统的启动和管理提供一套完整的解决方案。&lt;/p>
&lt;p>根据 Linux 惯例，字母d是守护进程（daemon）的缩写。 Systemd 这个名字的含义，就是它要守护整个系统。&lt;/p>
&lt;p>使用了 Systemd，就不需要再用init了。Systemd 取代了initd，成为系统的第一个进程（PID 等于 1），其他进程都是它的子进程。&lt;/p>
&lt;div class="highlight">&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;">&lt;code class="language-bash" data-lang="bash">&lt;span style="display:flex;">&lt;span> $ systemctl --version
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>&lt;p>上面的命令查看 Systemd 的版本。&lt;/p>
&lt;h2 id="使用-systemd-实现开机执行-shell-脚本">使用 systemd 实现开机执行 Shell 脚本&lt;/h2>
&lt;h3 id="通用操作步骤">通用操作步骤&lt;/h3>
&lt;p>创建希望开机马上执行的脚本，本文举例脚本存放位置为 /home/navxin/Example/startup.sh，脚本内容如下：&lt;/p>
&lt;div class="highlight">&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;">&lt;code class="language-bash" data-lang="bash">&lt;span style="display:flex;">&lt;span>&lt;span style="color:#75715e">#!/bin/bash
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#75715e">&lt;/span>&lt;span style="color:#75715e"># 开机时在脚本的同级目录下创建一个名为 StartupTouch.txt 的文件&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>touch /home/navxin/Example/startup.sh.txt
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>&lt;h3 id="开机执行的脚本需增加可执行权限才能被-systemd-运行使用如下命令">开机执行的脚本需增加可执行权限才能被 systemd 运行，使用如下命令&lt;/h3>
&lt;div class="highlight">&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;">&lt;code class="language-bash" data-lang="bash">&lt;span style="display:flex;">&lt;span>chmod u+x /home/navxin/Example/startup.sh
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>chmod g+x /home/navxin/Example/startup.sh
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>&lt;h3 id="进入-systemd-放置-service-的目录在该目录下可看到大量服务配置文件命令如下">进入 systemd 放置 service 的目录，在该目录下可看到大量服务配置文件，命令如下&lt;/h3>
&lt;div class="highlight">&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;">&lt;code class="language-bash" data-lang="bash">&lt;span style="display:flex;">&lt;span>&lt;span style="color:#75715e"># 进入 systemd 的 service 目录&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>cd /usr/lib/systemd/system
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#75715e"># 查看文件列表&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>ls -al
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>&lt;pre>&lt;code>在该目录创建一个新的 .service 文件用于配置开机启动脚本，本例中的文件名为 StartupExample.service，所执行命令和文件中的配置内容如下：
&lt;/code>&lt;/pre>
&lt;h3 id="创建服务配置文件">创建服务配置文件&lt;/h3>
&lt;div class="highlight">&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;">&lt;code class="language-bash" data-lang="bash">&lt;span style="display:flex;">&lt;span>sudo touch /usr/lib/systemd/system/StartupExample.service
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>&lt;p>以下为 StartupExample.service 配置文件的内容&lt;/p>
&lt;pre tabindex="0">&lt;code>[Unit]
Description=Startup Example
[Service]
ExecStart=/home/navxin/Example/startup.sh
[Install]
WantedBy=multi-user.target
&lt;/code>&lt;/pre>&lt;h3 id="尝试手动运行新创建的-service使用如下命令">尝试手动运行新创建的 service，使用如下命令：&lt;/h3>
&lt;div class="highlight">&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;">&lt;code class="language-bash" data-lang="bash">&lt;span style="display:flex;">&lt;span>&lt;span style="color:#75715e"># 手动运行 StartupExample.service&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>sudo systemctl start StartupExample.service
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#75715e"># 查看运行日志&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>systemctl status StartupExample.service
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>&lt;div class="highlight">&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;">&lt;code class="language-bash" data-lang="bash">&lt;span style="display:flex;">&lt;span> &lt;span style="color:#75715e"># 删除刚测试服务时创建的文件&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> rm -f /home/navxin/Example/startup.sh.txt
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#75715e"># 设置服务为 enable 状态，使之能开机运行&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> sudo systemctl enable StartupExample.service
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#75715e"># 重启机器&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> systemctl reboot
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>&lt;h2 id="附注unit">附注：Unit&lt;/h2>
&lt;p>Systemd 可以管理所有系统资源。不同的资源统称为 Unit（单位）。&lt;/p>
&lt;p>Unit 一共分成12种。&lt;/p>
&lt;pre>&lt;code> Service unit：系统服务
Target unit：多个 Unit 构成的一个组
Device Unit：硬件设备
Mount Unit：文件系统的挂载点
Automount Unit：自动挂载点
Path Unit：文件或路径
Scope Unit：不是由 Systemd 启动的外部进程
Slice Unit：进程组
Snapshot Unit：Systemd 快照，可以切回某个快照
Socket Unit：进程间通信的 socket
Swap Unit：swap 文件
Timer Unit：定时器
&lt;/code>&lt;/pre>
&lt;p>systemctl list-units命令可以查看当前系统的所有 Unit 。&lt;/p>
&lt;div class="highlight">&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;">&lt;code class="language-bash" data-lang="bash">&lt;span style="display:flex;">&lt;span> &lt;span style="color:#75715e"># 列出正在运行的 Unit&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> $ systemctl list-units
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#75715e"># 列出所有Unit，包括没有找到配置文件的或者启动失败的&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> $ systemctl list-units --all
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#75715e"># 列出所有没有运行的 Unit&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> $ systemctl list-units --all --state&lt;span style="color:#f92672">=&lt;/span>inactive
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#75715e"># 列出所有加载失败的 Unit&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> $ systemctl list-units --failed
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#75715e"># 列出所有正在运行的、类型为 service 的 Unit&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> $ systemctl list-units --type&lt;span style="color:#f92672">=&lt;/span>service
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#75715e"># 列出所有正在运行的、类型为 mount 的 Unit&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> $systemctl list-units --type&lt;span style="color:#f92672">=&lt;/span>mount
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#75715e"># 命令用于列出所有配置文件。&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> $systemctl list-unit-files
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>&lt;div class="highlight">&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;">&lt;code class="language-bash" data-lang="bash">&lt;span style="display:flex;">&lt;span> $systemctl list-unit-files --type&lt;span style="color:#f92672">=&lt;/span>mount
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>&lt;p>修改 myadmin.service文件，增加语句&lt;/p>
&lt;pre tabindex="0">&lt;code> After=network-online.target remote-fs.target nss-lookup.target navxin-kn1.mount
Wants=network-online.target
&lt;/code>&lt;/pre>&lt;p>全部文件内容如下(部分内容参考nginx.service)：&lt;/p>
&lt;pre tabindex="0">&lt;code class="language-conf" data-lang="conf"> # /lib/systemd/system/myadmin.service
[Unit]
Description=Start myAdmin web server
Documentation=https://www.lyhuilin.com/
After=network-online.target remote-fs.target nss-lookup.target navxin-kn1.mount
Wants=network-online.target
[Service]
Environment=&amp;#34;WELCOME=Baicai myAdmin Base Environment.&amp;#34;
ExecStartPre=/bin/echo ${WELCOME}
ExecStart=/baicai/systemdStart/my_admin/my_admin -c /baicai/systemdStart/my_admin/conf/config.yaml
ExecStop=/bin/kill -s TERM ${MAINPID}
[Install]
WantedBy=multi-user.target
&lt;/code>&lt;/pre></description></item><item><title>安装docker及简单的使用</title><link>https://blog.baicai.me/article/2021/docker_start/</link><pubDate>Tue, 05 Oct 2021 17:21:06 +0800</pubDate><author>admin@baicai.me (白菜)</author><guid>https://blog.baicai.me/article/2021/docker_start/</guid><description>&lt;h2 id="docker的介绍里面包括了3个基本概念">docker的介绍，里面包括了3个基本概念&lt;/h2>
&lt;h3 id="11-docker主要由镜像和容器构成">1.1 docker主要由镜像和容器构成&lt;/h3>
&lt;p>镜像（Image）:docker镜像好比一个模板，相当于一个文件系统&lt;/p>
&lt;p>容器（Container）:容器需要通过镜像来创建。镜像和容器就像是面向对象中的类和实例一样。容器可以被创建/启动/停止/删除等&lt;/p>
&lt;p>仓库（Repository）:仓库就是存放镜像的地方，分为私有仓库和公有仓库。类似git&lt;/p>
&lt;h3 id="12-docker的运行原理">1.2 docker的运行原理&lt;/h3>
&lt;p>docker是一个Client-Server结构的系统，docker的守护进程运行在主机上，通过socket从客户端访问。dockerServer接收到docker-Client的指令，就会执行这个命令。&lt;/p>
&lt;h2 id="一-mac-系统-docker-的安装">一. Mac 系统 docker 的安装&lt;/h2>
&lt;p>1.1 homebrew的cask应支持Docker for Mac,所以可以直接安装 brew cask install docker&lt;/p>
&lt;p>1.2 也可以直接到官网下载，https://download.docker.com/mac/stable/Docker.dmg&lt;/p>
&lt;p>1.3 docker的参考文档：https://docs.docker.com&lt;/p>
&lt;p>1.4 dockerhub查找镜像源地址：https://hub.docker.com&lt;/p>
&lt;h2 id="二-docker的使用">二. docker的使用&lt;/h2>
&lt;h3 id="11-查看版本">1.1 查看版本&lt;/h3>
&lt;div class="highlight">&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;">&lt;code class="language-bash" data-lang="bash">&lt;span style="display:flex;">&lt;span>docker --version
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>docker-compose --version
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>docker-machine --version
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>&lt;h3 id="12-查看docker系统信息包括镜像和容器的数量等">1.2 查看docker系统信息（包括镜像和容器的数量等）&lt;/h3>
&lt;div class="highlight">&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;">&lt;code class="language-bash" data-lang="bash">&lt;span style="display:flex;">&lt;span>docker info
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>&lt;h3 id="13-帮助命令">1.3 帮助命令&lt;/h3>
&lt;div class="highlight">&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;">&lt;code class="language-bash" data-lang="bash">&lt;span style="display:flex;">&lt;span>docker help
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>&lt;h3 id="14-查看-cpu的状况">1.4 查看 cpu的状况&lt;/h3>
&lt;div class="highlight">&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;">&lt;code class="language-bash" data-lang="bash">&lt;span style="display:flex;">&lt;span>docker stats
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>&lt;h2 id="三-docker的基本命令">三. docker的基本命令&lt;/h2>
&lt;p>镜像相关命令：&lt;/p>
&lt;h3 id="11-查看镜像可用版本nginx为例">1.1 查看镜像可用版本（nginx为例）&lt;/h3>
&lt;div class="highlight">&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;">&lt;code class="language-bash" data-lang="bash">&lt;span style="display:flex;">&lt;span>docker search nginx
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>&lt;h3 id="12-下载一个镜像">1.2 下载一个镜像&lt;/h3>
&lt;div class="highlight">&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;">&lt;code class="language-bash" data-lang="bash">&lt;span style="display:flex;">&lt;span>docker pull nginx:latest &lt;span style="color:#75715e">#（：后面跟镜像版本）&lt;/span>
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>&lt;h3 id="13-运行一个nginx服务器">1.3 运行一个nginx服务器&lt;/h3>
&lt;div class="highlight">&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;">&lt;code class="language-bash" data-lang="bash">&lt;span style="display:flex;">&lt;span>docker run -d -p 81:80 --name webserver nginx
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>&lt;p>可选项：&lt;/p>
&lt;div class="highlight">&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;">&lt;code class="language-bash" data-lang="bash">&lt;span style="display:flex;">&lt;span>&lt;span style="color:#75715e">#--name webserver ：容器名称，用来区分容器&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#75715e">#-p 81:80 ：端口进行映射，将本地的81端口映射到容器内部的80端口&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#75715e">#-v ～/nginx/html:/usr/share/nginx/html 数据卷挂载ro/rw，将主机项目中的目录挂载到容器的目录下，默认rw只能在宿主机外改变，容器内部不能改变&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#75715e">#-d：设置容器中在后台一直运行&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#75715e">#-it：使用交互方式运行，进入容器查看内容&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#75715e">#-P：随机端口&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#75715e">#-e：环境配置设置&lt;/span>
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>&lt;p>注意：后台启动运行，必须要有一个前台进程，docker发现没有应用，就会自动停止&lt;/p>
&lt;p>重点：数据卷挂载分为具名/匿名/指定路径挂载，容器数据卷挂载可以实现数据共享，容器的持久化和同步操作，可以使用docker volume 查看卷的情况，可以使用volumes-from实现多个容器之间的数据共享。&lt;/p>
&lt;h3 id="14-停止nginx服务">1.4 停止nginx服务&lt;/h3>
&lt;div class="highlight">&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;">&lt;code class="language-bash" data-lang="bash">&lt;span style="display:flex;">&lt;span>docker stop webserver&lt;span style="color:#f92672">(&lt;/span>容器ID&lt;span style="color:#f92672">)&lt;/span>
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>&lt;h3 id="15-删除nginx服务">1.5 删除nginx服务&lt;/h3>
&lt;div class="highlight">&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;">&lt;code class="language-bash" data-lang="bash">&lt;span style="display:flex;">&lt;span>docker rm webserver
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>&lt;h3 id="16-启动重启nginx服务">1.6 启动/重启nginx服务&lt;/h3>
&lt;div class="highlight">&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;">&lt;code class="language-bash" data-lang="bash">&lt;span style="display:flex;">&lt;span>docker start/restart webserver
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>&lt;h3 id="17-列出所有镜像列表包含了-仓库名标签镜像-id创建时间-以及-所占用的空间">1.7 列出所有镜像(列表包含了 仓库名、标签、镜像 ID、创建时间 以及 所占用的空间)&lt;/h3>
&lt;div class="highlight">&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;">&lt;code class="language-bash" data-lang="bash">&lt;span style="display:flex;">&lt;span>docker images ls
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>&lt;p>说明：&lt;/p>
&lt;pre>&lt;code>REPOSITORY 镜像的仓库源
TAG 镜像的标签
IMAGE ID 镜像的id
CREATED 镜像的创建时间
SIZE 镜像的大小
&lt;/code>&lt;/pre>
&lt;p>可选项：&lt;/p>
&lt;div class="highlight">&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;">&lt;code class="language-bash" data-lang="bash">&lt;span style="display:flex;">&lt;span>-a：列出所有的镜像
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>-q：只显示镜像的id
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>&lt;p>注意：镜像ID是唯一标识，一个镜像可以对应多个标签&lt;/p>
&lt;h3 id="18-查看镜像容器数据卷所占用的空间">1.8 查看镜像、容器、数据卷所占用的空间&lt;/h3>
&lt;div class="highlight">&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;">&lt;code class="language-bash" data-lang="bash">&lt;span style="display:flex;">&lt;span>docker system df
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>&lt;h3 id="19-删除镜像">1.9 删除镜像&lt;/h3>
&lt;p>指定镜像：&lt;/p>
&lt;div class="highlight">&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;">&lt;code class="language-bash" data-lang="bash">&lt;span style="display:flex;">&lt;span>docker rmi &lt;span style="color:#f92672">[&lt;/span>镜像名称/镜像短ID/镜像长ID/镜像摘要&lt;span style="color:#f92672">]&lt;/span>
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>&lt;p>多个镜像：&lt;/p>
&lt;div class="highlight">&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;">&lt;code class="language-bash" data-lang="bash">&lt;span style="display:flex;">&lt;span>docker rmi 镜像ID 镜像ID 镜像ID
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>&lt;p>全部镜像：&lt;/p>
&lt;div class="highlight">&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;">&lt;code class="language-bash" data-lang="bash">&lt;span style="display:flex;">&lt;span>docker rmi &lt;span style="color:#66d9ef">$(&lt;/span>docker images -aq&lt;span style="color:#66d9ef">)&lt;/span>
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>&lt;h3 id="20-删除docker-images-ls-命令配合-删除所有仓库名为redis的镜像">2.0 删除docker images ls 命令配合 删除所有仓库名为redis的镜像&lt;/h3>
&lt;div class="highlight">&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;">&lt;code class="language-bash" data-lang="bash">&lt;span style="display:flex;">&lt;span>docker rmi &lt;span style="color:#66d9ef">$(&lt;/span>docker images ls -q redis&lt;span style="color:#66d9ef">)&lt;/span>
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>&lt;h3 id="21-查看镜像运行记录">2.1 查看镜像运行记录&lt;/h3>
&lt;div class="highlight">&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;">&lt;code class="language-bash" data-lang="bash">&lt;span style="display:flex;">&lt;span>docker history 镜像id
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>&lt;p>容器相关命令&lt;/p>
&lt;h3 id="11-列出容器">1.1 列出容器&lt;/h3>
&lt;div class="highlight">&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;">&lt;code class="language-bash" data-lang="bash">&lt;span style="display:flex;">&lt;span>docker ps
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>&lt;p>可选项：&lt;/p>
&lt;div class="highlight">&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;">&lt;code class="language-bash" data-lang="bash">&lt;span style="display:flex;">&lt;span>&lt;span style="color:#75715e">#-a：显示所有的容器，包括未运行的&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#75715e">#-l：显示最近创建的容器&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#75715e">#-n：列出最近创建的n个容器&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#75715e">#-q：只显示容器的编号&lt;/span>
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>&lt;h3 id="12-进入容器">1.2 进入容器&lt;/h3>
&lt;div class="highlight">&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;">&lt;code class="language-bash" data-lang="bash">&lt;span style="display:flex;">&lt;span>docker exec -it &lt;span style="color:#f92672">[&lt;/span>容器名称&lt;span style="color:#f92672">]&lt;/span> /bin/bash
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>docker atthch 容器id
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>&lt;p>区别：docker exec 进入容器后开启一个新的终端，可以在里面操作；docker attach 进入容器正在执行的终端，不会启动新的进程&lt;/p>
&lt;h3 id="13-退出容器">1.3 退出容器&lt;/h3>
&lt;p>容器停止退回主机&lt;/p>
&lt;div class="highlight">&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;">&lt;code class="language-bash" data-lang="bash">&lt;span style="display:flex;">&lt;span>exit
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>&lt;p>容器不停止推出&lt;/p>
&lt;pre>&lt;code>ctrl+p+q
&lt;/code>&lt;/pre>
&lt;h3 id="14-删除容器">1.4 删除容器&lt;/h3>
&lt;p>指定容器：&lt;/p>
&lt;div class="highlight">&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;">&lt;code class="language-bash" data-lang="bash">&lt;span style="display:flex;">&lt;span>docker rm &lt;span style="color:#f92672">[&lt;/span>容器id&lt;span style="color:#f92672">]&lt;/span>
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>&lt;p>多个容器：&lt;/p>
&lt;div class="highlight">&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;">&lt;code class="language-bash" data-lang="bash">&lt;span style="display:flex;">&lt;span>docker rm 容器id 容器id 容器id
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>&lt;p>所有容器：&lt;/p>
&lt;div class="highlight">&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;">&lt;code class="language-bash" data-lang="bash">&lt;span style="display:flex;">&lt;span>docker rm &lt;span style="color:#66d9ef">$(&lt;/span>docker ps -aq&lt;span style="color:#66d9ef">)&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>docker ps -a -q|xargs docker rm
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>&lt;p>注意：不能删除正在运行的容器，要删除正在运行的容器需要加 -f 参数，docker rm -f 容器id&lt;/p>
&lt;h3 id="15-启动重启容器">1.5 启动/重启容器&lt;/h3>
&lt;div class="highlight">&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;">&lt;code class="language-bash" data-lang="bash">&lt;span style="display:flex;">&lt;span>docker start/restart 容器id
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>&lt;h3 id="16-停止强制停止容器">1.6 停止/强制停止容器&lt;/h3>
&lt;div class="highlight">&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;">&lt;code class="language-bash" data-lang="bash">&lt;span style="display:flex;">&lt;span>docker stop/kill 容器id
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>&lt;h3 id="17-查看容器日志">1.7 查看容器日志&lt;/h3>
&lt;div class="highlight">&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;">&lt;code class="language-bash" data-lang="bash">&lt;span style="display:flex;">&lt;span>docker logs -f -t --tail &lt;span style="color:#ae81ff">100&lt;/span> 容器id
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#75715e">#--tail后面必须加参数条数&lt;/span>
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>&lt;h3 id="18-查看容器中的进程信息">1.8 查看容器中的进程信息&lt;/h3>
&lt;div class="highlight">&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;">&lt;code class="language-bash" data-lang="bash">&lt;span style="display:flex;">&lt;span>docker top 容器id
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>&lt;h3 id="19-查看容器的元数据重要命令">1.9 查看容器的元数据（重要命令）&lt;/h3>
&lt;div class="highlight">&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;">&lt;code class="language-bash" data-lang="bash">&lt;span style="display:flex;">&lt;span>docker inspect 容器id
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>&lt;h3 id="20-从容器上拷贝数据到主机上">2.0 从容器上拷贝数据到主机上&lt;/h3>
&lt;div class="highlight">&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;">&lt;code class="language-bash" data-lang="bash">&lt;span style="display:flex;">&lt;span>docker cp 容器id:容器内路径 主机路径
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>&lt;h2 id="四-dockerfile的指令">四. Dockerfile的指令&lt;/h2>
&lt;pre>&lt;code>FROM 基础镜像，一切从这里开始
MAINTAINER 镜像的作者 姓名&amp;lt;邮箱&amp;gt;
RUN 镜像构建需要运行的命令
ADD 步骤，添加内容
WORKDIR 镜像的工作目录
VOLUME 挂载的目录
EXPOST 端口配置
CMD 指定容器启动要运行的命令，只有最后一个会生效，可被替代
ENTRYPOINT 指定这个容器启动要运行的命令，可以追加命令
ONBUILD 当构建一个被继承的Dockerfile时会运行
COPY 类似ADD将我们文件拷贝到镜像中
ENV 构建的时候设置环境变量
&lt;/code>&lt;/pre></description></item><item><title>ubuntu上安装firefox</title><link>https://blog.baicai.me/article/2021/ubuntu_firefox-install/</link><pubDate>Wed, 29 Sep 2021 16:19:42 +0800</pubDate><author>admin@baicai.me (白菜)</author><guid>https://blog.baicai.me/article/2021/ubuntu_firefox-install/</guid><description>&lt;h2 id="卸载原来firefox">卸载原来Firefox&lt;/h2>
&lt;pre>&lt;code>sudo apt-get purge firefox
&lt;/code>&lt;/pre>
&lt;p>或
sudo apt-get remove firefox&lt;/p>
&lt;h2 id="下载最新firefox二进制压缩包">下载最新Firefox二进制压缩包&lt;/h2>
&lt;pre>&lt;code>wget -O ~/firefox.tar.bz2 &amp;quot;https://download.mozilla.org/?product=firefox-latest&amp;amp;os=linux64&amp;quot;
&lt;/code>&lt;/pre>
&lt;h2 id="解压并移动到opt目录">解压并移动到/opt目录&lt;/h2>
&lt;pre>&lt;code>sudo tar xjf ~/firefox.tar.bz2 -C /opt/
&lt;/code>&lt;/pre>
&lt;h2 id="创建软链接">创建软链接&lt;/h2>
&lt;pre>&lt;code>sudo ln -s /opt/firefox/firefox /usr/lib/firefox/firefox
&lt;/code>&lt;/pre>
&lt;p>在/usr/lib/中创建一个firefox可执行链接文件，该文件指向/opt中firefox可执行主程序位置。&lt;/p>
&lt;h2 id="启动firefox">启动firefox&lt;/h2>
&lt;p>终端启动Firefox&lt;/p>
&lt;pre>&lt;code>firefox
&lt;/code>&lt;/pre>
&lt;h2 id="创建桌面快捷方式">创建桌面快捷方式&lt;/h2>
&lt;p>进入/usr/share/applications目录&lt;/p>
&lt;pre>&lt;code>touch firefox.desktop
nano firefox.desktop
&lt;/code>&lt;/pre>
&lt;p>添加内容：&lt;/p>
&lt;pre>&lt;code>[Desktop Entry]
Name=firefox
Comment=firefox
Exec=/opt/firefox/firefox
Icon=/opt/firefox/browser/chrome/icons/default/default128.png
Terminal=false
Type=Application
Categories=Application;
Encoding=UTF-8
StartupNotify=true
&lt;/code>&lt;/pre>
&lt;h2 id="卸载firefox">卸载Firefox&lt;/h2>
&lt;p>通过上面方法安装的Firefox，如果想删除，可以在终端种输入以下命令：&lt;/p>
&lt;pre>&lt;code>sudo rm -rf /opt/firefox
sudo rm /usr/share/applications/firefox.desktop
&lt;/code>&lt;/pre></description></item><item><title>友情链接</title><link>https://blog.baicai.me/links/</link><pubDate>Wed, 29 Sep 2021 11:48:42 +0800</pubDate><author>admin@baicai.me (白菜)</author><guid>https://blog.baicai.me/links/</guid><description>&lt;p>1.申请链接请先在贵站的首页做好本站的友情链接（本站名称：白菜林，本站地址：https://baicai.me/）。&lt;/p>
&lt;p>2.优先交换电脑网络和学习类的网站以及博客的友情链接。&lt;/p>
&lt;p>3.做好链接后可&lt;a href="https://blog.baicai.me/about/">与我联系&lt;/a>，本站将在7个工作日内回复。&lt;/p>
&lt;h2 id="heading">&amp;mdash;&amp;mdash;&amp;mdash;&amp;mdash;&amp;mdash;&amp;mdash;&amp;mdash;&amp;mdash;&amp;mdash;&amp;mdash;&amp;mdash;&amp;mdash;&amp;mdash;&amp;mdash;&amp;mdash;&amp;mdash;&amp;mdash;&amp;mdash;&amp;mdash;&amp;mdash;&lt;/h2>
&lt;pre>&lt;code>以上为本站的友情链接，排各不分先后 (每周检测一次)
&lt;/code>&lt;/pre></description></item><item><title>如何知道谁在ping我？</title><link>https://blog.baicai.me/article/2021/tcpdump_icmp-echo/</link><pubDate>Sat, 28 Aug 2021 21:14:41 +0800</pubDate><author>admin@baicai.me (白菜)</author><guid>https://blog.baicai.me/article/2021/tcpdump_icmp-echo/</guid><description>&lt;blockquote>
&lt;p>tcpdump 是 Linux 上可用的最强大和使用最广泛的 命令行 数据包嗅探器(包分析器)工具。&lt;/p>&lt;/blockquote>
&lt;p>在您要监控的计算机的终端应用程序中：&lt;/p>
&lt;div class="highlight">&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;">&lt;code class="language-bash" data-lang="bash">&lt;span style="display:flex;">&lt;span>sudo tcpdump -i ethX icmp and icmp&lt;span style="color:#f92672">[&lt;/span>icmptype&lt;span style="color:#f92672">]=&lt;/span>icmp-echo
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>&lt;p>选项：&lt;/p>
&lt;div class="highlight">&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;">&lt;code class="language-bash" data-lang="bash">&lt;span style="display:flex;">&lt;span>-n avoid a &lt;span style="color:#f92672">(&lt;/span>potentially slow&lt;span style="color:#f92672">)&lt;/span> reverse DNS query
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>−i interface
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>icmp&lt;span style="color:#f92672">[&lt;/span>icmptype&lt;span style="color:#f92672">]=&lt;/span>icmp-echo To print all ICMP packets that are echo requests/replies
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>&lt;p>它将开始侦听 ethX 并等待到达的数据包。&lt;/p>
&lt;p>示例：我有 2 台 pc win7 192.168.0.8 , Ubuntu 192.168.0.57 它将监控到达的数据包：
在Win上：&lt;/p>
&lt;div class="highlight">&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;">&lt;code class="language-bash" data-lang="bash">&lt;span style="display:flex;">&lt;span>ping 192.168.0.57
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>&lt;p>在 Ubuntu 上：&lt;/p>
&lt;div class="highlight">&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;">&lt;code class="language-bash" data-lang="bash">&lt;span style="display:flex;">&lt;span>tcpdump -i eth0 icmp and icmp&lt;span style="color:#f92672">[&lt;/span>icmptype&lt;span style="color:#f92672">]=&lt;/span>icmp-echo -n
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>&lt;p>参考：nixCraft&lt;a href="http://www.cyberciti.biz/howto/question/man/tcpdump-man-page-with-examples.php">[1]&lt;/a>&lt;/p></description></item><item><title>使用 df 命令查看 Linux 上的可用磁盘空间</title><link>https://blog.baicai.me/article/2021/check-disk-space-linux-df/</link><pubDate>Wed, 04 Aug 2021 16:12:56 +0800</pubDate><author>admin@baicai.me (白菜)</author><guid>https://blog.baicai.me/article/2021/check-disk-space-linux-df/</guid><description>&lt;p>磁盘空间已经不像计算机早期那样珍贵，但无论你有多少磁盘空间，总有耗尽的可能。计算机需要一些磁盘空间才能启动运行，所以为了确保你没有在无意间用尽了所有的硬盘空间，偶尔检查一下是非常必要的。在 Linux 终端，你可以用 df 命令来做这件事。&lt;/p>
&lt;p>df 命令可以显示文件系统中可用的磁盘空间。&lt;/p>
&lt;p>要想使输出结果易于阅读，你可以加上 &amp;ndash;human-readable（或其简写 -h）选项：&lt;/p>
&lt;div class="highlight">&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;">&lt;code class="language-bash" data-lang="bash">&lt;span style="display:flex;">&lt;span>$ df --human-readable
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>Filesystem Size Used Avail Use% Mounted on
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>/dev/sda1 1.0T 525G 500G 52% /
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>&lt;p>在这个例子中，计算机的磁盘已经用了 52%，还有 500 GB 可用空间。&lt;/p>
&lt;p>由于 Linux 从整体上看待所有挂载设备的文件系统，df 命令会展示出连接到计算机上的每个存储设备的详细信息。如果你有很多磁盘，那么输出结果将会反映出来：&lt;/p>
&lt;div class="highlight">&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;">&lt;code class="language-bash" data-lang="bash">&lt;span style="display:flex;">&lt;span>$ df --human-readable
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>Filesystem Size Used Avail Use% Mounted on
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>/dev/root 110G 45G 61G 43% /
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>devtmpfs 12G &lt;span style="color:#ae81ff">0&lt;/span> 12G 0% /dev
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>tmpfs 12G 848K 12G 1% /run
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>/dev/sda1 1.6T 1.3T 191G 87% /home
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>/dev/sdb1 917G 184G 687G 22% /penguin
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>/dev/sdc1 57G 50G 4.5G 92% /sneaker
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>/dev/sdd1 3.7T 2.4T 1.3T 65% /tux
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>&lt;p>在这个例子中，计算机的 /home 目录已经用了 87%，剩下 191 GB 的可用空间。&lt;/p>
&lt;h3 id="查看总的可用磁盘空间">查看总的可用磁盘空间&lt;/h3>
&lt;p>如果你的文件系统确实很复杂，而你希望看到所有磁盘的总空间，可以使用 &amp;ndash;total 选项：&lt;/p>
&lt;div class="highlight">&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;">&lt;code class="language-bash" data-lang="bash">&lt;span style="display:flex;">&lt;span>$ df --human-readable --total
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>Filesystem Size Used Avail Use% Mounted on
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>/dev/root 110G 45G 61G 43% /
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>devtmpfs 12G &lt;span style="color:#ae81ff">0&lt;/span> 12G 0% /dev
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>tmpfs 12G 848K 12G 1% /run
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>/dev/sda1 1.6T 1.3T 191G 87% /home
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>/dev/sdb1 917G 184G 687G 22% /penguin
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>/dev/sdc1 57G 50G 4.5G 92% /sneaker
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>/dev/sdd1 3.7T 2.4T 1.3T 65% /tux
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>total 6.6T 4.0T 2.5T 62% -
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>&lt;p>输出的最后一行展示了文件系统的总空间、已用总空间、可用总空间。&lt;/p>
&lt;h3 id="查看磁盘空间使用情况">查看磁盘空间使用情况&lt;/h3>
&lt;p>如果你想大概了解哪些文件占用了磁盘空间，请阅读我们关于 du 命令[1] 的文章。&lt;/p>
&lt;p>via:
&lt;a href="https://opensource.com/article/21/7/check-disk-space-linux-df">https://opensource.com/article/21/7/check-disk-space-linux-df&lt;/a>
&lt;a href="https://linux.cn/article-13646-1.html">https://linux.cn/article-13646-1.html&lt;/a>&lt;/p></description></item><item><title>Ubuntu安装 Zlib</title><link>https://blog.baicai.me/article/2021/zlib/</link><pubDate>Mon, 12 Jul 2021 21:01:31 +0800</pubDate><author>admin@baicai.me (白菜)</author><guid>https://blog.baicai.me/article/2021/zlib/</guid><description>&lt;blockquote>
&lt;p>如果你尝试在 Ubuntu 上安装 zlib，它会抛出 “unable to locate package zlib” 错误。&lt;/p>&lt;/blockquote>
&lt;p>Zlib 是一个用于数据压缩的开源库。&lt;/p>
&lt;p>作为使用者，你可能会遇到需要安装 zlib（或 zlib-devel 包）作为另一个应用程序的依赖项的情况。&lt;/p>
&lt;p>但问题来了，如果你尝试在 Ubuntu 上安装 zlib，它会抛出 “unable to locate package zlib” 错误。&lt;/p>
&lt;div class="highlight">&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;">&lt;code class="language-bash" data-lang="bash">&lt;span style="display:flex;">&lt;span> sudo apt install zlib
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> Reading package lists... Done
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> Building dependency tree
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> Reading state information... Done
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> E: Unable to locate package zlib
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>&lt;p>为什么会看到这个 Ubable to locate package 错误呢？因为没有名为 zlib 的包。&lt;/p>
&lt;p>如果你 使用 apt search 命令，你会发现有几个包可以让你安装：zlib 1g 和 zlib 1g-dev。当你知道这些后，只需一个 apt 命令就可以安装它们。&lt;/p>
&lt;h2 id="在基于-ubuntu-的-linux-发行版上安装-zlib">在基于 Ubuntu 的 Linux 发行版上安装 Zlib&lt;/h2>
&lt;p>打开终端，使用以下命令：&lt;/p>
&lt;div class="highlight">&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;">&lt;code class="language-bash" data-lang="bash">&lt;span style="display:flex;">&lt;span> sudo apt install zlib1g
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>&lt;p>请记住 g 前面的字母是数字 1，而不是小写的字母 L。很多人在输入命令时都会犯这个错误。&lt;/p>
&lt;p>另一个包，zlib 1g-dev 是开发包。只有在你需要时才安装它，否则你应该使用 zlib 1g 包。&lt;/p>
&lt;div class="highlight">&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;">&lt;code class="language-bash" data-lang="bash">&lt;span style="display:flex;">&lt;span> sudo apt install zlib1g-dev
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>&lt;p>你也可以 Zlib 网站 下载源代码并安装它。但是，除非你有充分的理由，否则我不推荐使用源代码方式来安装 zlib。例如，如果你需要最新或特定版本的 zlib，但该版本在发行版的仓库中不可用。&lt;/p>
&lt;p>有趣的是，像安装 zlib 这样看似很小的东西可能会变得很麻烦，有两个原因：一个是不同的包名；另一个是包含“隐藏”数字 1，它与小写 L 混淆了。&lt;/p>
&lt;h2 id="参考">参考&lt;/h2>
&lt;p>Zlib &lt;a href="https://zlib.net/">[1]&lt;/a>&lt;/p></description></item><item><title>免费CDN：jsDelivr+Github 使用方法</title><link>https://blog.baicai.me/article/2021/jsdelivr_github/</link><pubDate>Fri, 02 Jul 2021 23:50:06 +0800</pubDate><author>admin@baicai.me (白菜)</author><guid>https://blog.baicai.me/article/2021/jsdelivr_github/</guid><description>&lt;p>CDN的全称是Content Delivery Network，即内容分发网络。CDN是构建在网络之上的内容分发网络，依靠部署在各地的边缘服务器，通过中心平台的负载均衡、内容分发、调度等功能模块，使用户就近获取所需内容，降低网络拥塞，提高用户访问响应速度和命中率。CDN的关键技术主要有内容存储和分发技术。&lt;/p>
&lt;h3 id="用-jsdelivr-免费cdn托管静态资源">用 jsDelivr 免费CDN托管静态资源&lt;/h3>
&lt;p>国内的免费 CDN 不少，但需要备案
国外的免费 CDN 也不少，但在国内速度慢
但 jsDelivr 是一个特殊的存在，虽然是一家国外 CDN 但是有国内节点&lt;/p>
&lt;p>jsDelivr官网： &lt;a href="https://www.jsdelivr.com">https://www.jsdelivr.com&lt;/a>&lt;/p>
&lt;blockquote>
&lt;p>放在Github的资源在国内加载速度比较慢，因此需要使用CDN加速来优化网站打开速度，jsDelivr + Github便是免费且好用的CDN，非常适合博客网站使用。&lt;/p>&lt;/blockquote>
&lt;h3 id="使用步骤">使用步骤&lt;/h3>
&lt;p>1、新建Github仓库&lt;/p>
&lt;p>2、克隆Github仓库到本地&lt;/p>
&lt;p>执行以下命令：&lt;/p>
&lt;div class="highlight">&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;">&lt;code class="language-bash" data-lang="bash">&lt;span style="display:flex;">&lt;span>git clone 一键复制的仓库地址
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>&lt;p>3、上传资源&lt;/p>
&lt;p>复制需要上传的资源到本地git仓库（注：jsDelivr不支持加载超过20M的资源），在本地git仓库目录下，执行以下命令：&lt;/p>
&lt;div class="highlight">&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;">&lt;code class="language-bash" data-lang="bash">&lt;span style="display:flex;">&lt;span>git status &lt;span style="color:#75715e">#查看状态&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>git add . &lt;span style="color:#75715e">#添加所有文件到暂存区&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>git commit -m &lt;span style="color:#e6db74">&amp;#39;第一次提交&amp;#39;&lt;/span> &lt;span style="color:#75715e">#把文件提交到仓库&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>git push &lt;span style="color:#75715e">#推送至远程仓库&lt;/span>
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>&lt;p>4、发布仓库&lt;/p>
&lt;p>点击release发布&lt;/p>
&lt;p>自定义发布版本号
5、通过jsDelivr引用资源&lt;/p>
&lt;p>使用方法：&lt;code>https://cdn.jsdelivr.net/gh/你的用户名/你的仓库名@发布的版本号/文件路径&lt;/code>
例如：&lt;/p>
&lt;pre>&lt;code>https://cdn.jsdelivr.net/gh/baicaime/meBlog/index.html
https://cdn.jsdelivr.net/gh/baicaime/meBlog/favicon-16x16.png
https://cdn.jsdelivr.net/gh/clin003/cdn/v@3.1.3/css.css
&lt;/code>&lt;/pre>
&lt;p>注意：版本号不是必需的，是为了区分新旧资源，如果不使用版本号，将会直接引用最新资源，除此之外还可以使用某个范围内的版本，查看所有资源等，具体使用方法如下：&lt;/p>
&lt;pre>&lt;code>// 加载任何Github发布、提交或分支
https://cdn.jsdelivr.net/gh/user/repo@version/file
// 加载 jQuery v3.2.1
https://cdn.jsdelivr.net/gh/jquery/jquery@3.2.1/dist/jquery.min.js
// 使用版本范围而不是特定版本
https://cdn.jsdelivr.net/gh/jquery/jquery@3.2/dist/jquery.min.js
https://cdn.jsdelivr.net/gh/jquery/jquery@3/dist/jquery.min.js
// 完全省略该版本以获取最新版本
https://cdn.jsdelivr.net/gh/jquery/jquery/dist/jquery.min.js
// 将“.min”添加到任何JS/CSS文件中以获取缩小版本，如果不存在，将为会自动生成
https://cdn.jsdelivr.net/gh/jquery/jquery@3.2.1/src/core.min.js
// 在末尾添加 / 以获取资源目录列表
https://cdn.jsdelivr.net/gh/jquery/jquery/
// 刷新cnd资源 将域名中的 cdn 改为 purge 即可
https://purge.jsdelivr.net/gh/baicaime/meBlog/index.html
// 使用最新版本资源
https://purge.jsdelivr.net/gh/baicaime/meBlog@latest/index.html
&lt;/code>&lt;/pre></description></item><item><title>Ubuntu安装 qbittorrent-nox并启动</title><link>https://blog.baicai.me/article/2021/qbittorrent/</link><pubDate>Fri, 02 Jul 2021 21:01:31 +0800</pubDate><author>admin@baicai.me (白菜)</author><guid>https://blog.baicai.me/article/2021/qbittorrent/</guid><description>&lt;h3 id="qbittorrent-nox">Qbittorrent-Nox&lt;/h3>
&lt;p>要在Linux上使用Qbittorrent Web UI，你无需安装完整的Qbittorent桌面应用程序，有一个基于终端的Qbittorrent应用程序可用，它被称为Qbittorrent-Nox。&lt;/p>
&lt;p>注意：Web UI功能不仅限于Qbittorrent-Nox应用程序，此功能还可以与传统的Qbittorent Linux桌面应用程序一起使用&lt;/p>
&lt;h3 id="安装qbittorrent">安装qbittorrent&lt;/h3>
&lt;h4 id="安装add-apt-repository命令">安装add-apt-repository命令&lt;/h4>
&lt;div class="highlight">&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;">&lt;code class="language-bash" data-lang="bash">&lt;span style="display:flex;">&lt;span>sudo apt-get update &lt;span style="color:#f92672">&amp;amp;&amp;amp;&lt;/span> sudo apt-get install software-properties-common -y
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>&lt;h4 id="添加qbittorrent-nox的ppa软件源">添加qbittorrent-nox的PPA软件源&lt;/h4>
&lt;div class="highlight">&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;">&lt;code class="language-bash" data-lang="bash">&lt;span style="display:flex;">&lt;span>sudo add-apt-repository ppa:qbittorrent-team/qbittorrent-stable
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>&lt;h4 id="安装qbittorrent-noxwebui版">安装qbittorrent-nox（webui版）&lt;/h4>
&lt;div class="highlight">&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;">&lt;code class="language-bash" data-lang="bash">&lt;span style="display:flex;">&lt;span>sudo apt-get update &lt;span style="color:#f92672">&amp;amp;&amp;amp;&lt;/span> sudo apt-get install qbittorrent-nox
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>&lt;h3 id="设置开机启动">设置开机启动&lt;/h3>
&lt;h4 id="通过rclocal完成">通过rc.local完成&lt;/h4>
&lt;p>如果是Ubuntu-16.10及其之后的版本需要先按下面的文章完成设置后，开机启动才会生效&lt;/p>
&lt;p>Ubuntu-18.04设置开机启动脚本
起因Ubuntu-16.10（不包括）之前的版本使用的是update-rc.d以及rc.local等方法设置开机启&amp;hellip;&lt;/p>
&lt;p>编辑rc.local脚本&lt;/p>
&lt;div class="highlight">&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;">&lt;code class="language-bash" data-lang="bash">&lt;span style="display:flex;">&lt;span>nano /etc/rc.local
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>&lt;p>在exit 0前面（前一行）添加以下内容并保存&lt;/p>
&lt;div class="highlight">&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;">&lt;code class="language-bash" data-lang="bash">&lt;span style="display:flex;">&lt;span>qbittorrent-nox -d
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>&lt;h4 id="通过创建自定义服务实现">通过创建自定义服务实现&lt;/h4>
&lt;p>创建系统服务&lt;/p>
&lt;div class="highlight">&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;">&lt;code class="language-bash" data-lang="bash">&lt;span style="display:flex;">&lt;span>sudo apt-get install nano -y &lt;span style="color:#f92672">&amp;amp;&amp;amp;&lt;/span> nano /etc/systemd/system/qbittorrent-nox.service
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>&lt;p>粘贴以下内容，并保存。&lt;/p>
&lt;pre tabindex="0">&lt;code>[Unit]
Description=qBittorrent-nox
After=network.target
[Service]
User=root
Type=simple
RemainAfterExit=yes
ExecStart=/usr/bin/qbittorrent-nox -d
[Install]
WantedBy=multi-user.target
&lt;/code>&lt;/pre>&lt;p>启动qbittorrent-nox并创建服务配置&lt;/p>
&lt;div class="highlight">&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;">&lt;code class="language-bash" data-lang="bash">&lt;span style="display:flex;">&lt;span>systemctl start qbittorrent-nox
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>&lt;p>设置开机自动启动qbittorrent-nox&lt;/p>
&lt;div class="highlight">&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;">&lt;code class="language-bash" data-lang="bash">&lt;span style="display:flex;">&lt;span>systemctl enable qbittorrent-nox
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>&lt;p>查看qbittorrent-nox状态&lt;/p>
&lt;div class="highlight">&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;">&lt;code class="language-bash" data-lang="bash">&lt;span style="display:flex;">&lt;span>sudo systemctl status qbittorrent-nox
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>&lt;p>默认账号：admin 密码： adminadmin
默认登陆网址：ip:8080&lt;/p></description></item><item><title>跨域方案Nginx配置</title><link>https://blog.baicai.me/article/2021/nginx_cors_server_conf/</link><pubDate>Thu, 01 Jul 2021 18:58:23 +0800</pubDate><author>admin@baicai.me (白菜)</author><guid>https://blog.baicai.me/article/2021/nginx_cors_server_conf/</guid><description>&lt;h3 id="什么是浏览器同源策略">什么是浏览器同源策略？&lt;/h3>
&lt;p>同源策略限制了从同一个源加载的文档或脚本如何与来自另一个源的资源进行交互。这是一个用于隔离潜在恶意文件的重要安全机制。&lt;/p>
&lt;p>同源是指&amp;quot;协议+域名+端口&amp;quot;三者相同，即便两个不同的域名指向同一个ip地址，也非同源。&lt;/p>
&lt;h3 id="如何实现跨域">如何实现跨域？&lt;/h3>
&lt;p>跨域是个比较古老的命题了，历史上跨域的实现手段有很多，我们现在主要介绍Nginx的跨域方案，其余的方案我们就不深入讨论了。&lt;/p>
&lt;h3 id="方便的跨域方案nginx">方便的跨域方案Nginx&lt;/h3>
&lt;p>nginx是一款极其强大的web服务器，其优点就是轻量级、启动快、高并发。&lt;/p>
&lt;p>现在的新项目中nginx几乎是首选，我们用node或者go开发的服务通常都需要经过nginx的反向代理。&lt;/p>
&lt;p>反向代理的原理很简单，即所有客户端的请求都必须先经过nginx的处理，nginx作为代理服务器再讲请求转发给node或者go服务，这样就规避了同源策略。&lt;/p>
&lt;pre tabindex="0">&lt;code>#进程, 可更具cpu数量调整
worker_processes 1;
events {
#连接数
worker_connections 1024;
}
http {
include mime.types;
default_type application/octet-stream;
sendfile on;
#连接超时时间，服务器会在这个时间过后关闭连接。
keepalive_timeout 10;
# gizp压缩
gzip on;
# 直接请求nginx也是会报跨域错误的这里设置允许跨域
# 如果代理地址已经允许跨域则不需要这些, 否则报错(虽然这样nginx跨域就没意义了)
add_header Access-Control-Allow-Origin *;
add_header Access-Control-Allow-Headers X-Requested-With;
add_header Access-Control-Allow-Methods GET,POST,OPTIONS;
# srever模块配置是http模块中的一个子模块，用来定义一个虚拟访问主机
server {
listen 80;
server_name localhost;
# 根路径指到index.html
location / {
root html;
index index.html index.htm;
}
# localhost/api 的请求会被转发到192.168.0.103:8080
location /api {
rewrite ^/b/(.*)$ /$1 break; # 去除本地接口/api前缀, 否则会出现404
proxy_set_header Host $host;
proxy_set_header X-Real-IP $remote_addr;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
proxy_pass http://192.168.0.103:8080; # 转发地址
}
# 重定向错误页面到/50x.html
error_page 500 502 503 504 /50x.html;
location = /50x.html {
root html;
}
}
}
&lt;/code>&lt;/pre></description></item><item><title>MAC命令快速模糊查找文件</title><link>https://blog.baicai.me/article/2021/mac_find/</link><pubDate>Sun, 27 Jun 2021 10:04:44 +0800</pubDate><author>admin@baicai.me (白菜)</author><guid>https://blog.baicai.me/article/2021/mac_find/</guid><description>&lt;h3 id="find命令">find命令&lt;/h3>
&lt;p>描述：通过 find命令查找
语法：find ~ -iname “文件名*”&lt;/p>
&lt;div class="highlight">&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;">&lt;code class="language-bash" data-lang="bash">&lt;span style="display:flex;">&lt;span>/**
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>* 比如我要查找一个以‘vue-’开头的.zip文件,
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>* 但是你忘了它的全名也忘了在那个文件夹，
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>* 查找范围是‘～’节点以内
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>* 就可以用这种方式进行模糊搜索
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>*/
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> find ~ -iname &lt;span style="color:#e6db74">&amp;#34;vue-*.zip&amp;#34;&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>/**
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>* 然后它就把所有包含符合条件的文件和路径都打印出来了
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>*/
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>&lt;p>find不但能查找文件，还能查找文件夹&lt;/p>
&lt;div class="highlight">&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;">&lt;code class="language-bash" data-lang="bash">&lt;span style="display:flex;">&lt;span>/**
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>* 比如我要查找所有包含‘vue’的文件或文件夹
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>*/
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>find ~ -iname &lt;span style="color:#e6db74">&amp;#34;*vue*&amp;#34;&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>/**
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>* 结果它找到了所有包含‘vue’的文件或文件夹
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>*/
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>&lt;p>find方式很简单但是需要一点专业知识，需要知道一些正则的基本常识，需要指定路径范围，搜索的名字需要加引号等等&lt;/p>
&lt;h3 id="mdfind命令">mdfind命令&lt;/h3>
&lt;p>描述：通过 mdfind命令查找
语法：mdfind -name 文件名&lt;/p>
&lt;div class="highlight">&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;">&lt;code class="language-bash" data-lang="bash">&lt;span style="display:flex;">&lt;span>/**
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>* 比如我要查找所有包含‘vue’的文件或文件夹
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>*/
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>mdfind -name vue
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>/**
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>* 看，我直接输入我要找的关键字‘vue’
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>* 就把所有文件和文件夹都输出出来了，是不是很方便
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>*/
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>&lt;p>mdfind 简单粗暴，没缺点，但有个前提是你mac电脑要支持Spotlight功能，不过也不用担心，一般mac默认是支持的&lt;/p>
&lt;h3 id="在-shell-中执行命令">在 shell 中执行命令&lt;/h3>
&lt;blockquote>
&lt;p>你是找到这个文件或文件夹了，但是你想直接打开它，那么怎么打开呢，看下面&lt;/p>&lt;/blockquote>
&lt;p>若要运行当前用户个人文件夹中的命令，请在前面加上文件夹说明符。例如，若要运行 MyCommandLineProg，请使用以下命令：&lt;/p>
&lt;div class="highlight">&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;">&lt;code class="language-bash" data-lang="bash">&lt;span style="display:flex;">&lt;span>% ~/MyCommandLineProg
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>&lt;p>若要打开一个 App，请使用打开命令：&lt;/p>
&lt;div class="highlight">&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;">&lt;code class="language-bash" data-lang="bash">&lt;span style="display:flex;">&lt;span>% open -a MyProg.app
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>&lt;h3 id="终止命令">终止命令&lt;/h3>
&lt;ul>
&lt;li>
&lt;p>在 Mac 上的“终端” App 中，点按正在运行您想要终止的命令的“终端”窗口。&lt;/p>
&lt;/li>
&lt;li>
&lt;p>按下 Control-C 键。&lt;/p>
&lt;/li>
&lt;li>
&lt;p>这会发出一个让大多数命令终止的信号。&lt;/p>
&lt;/li>
&lt;/ul>
&lt;h3 id="参考">参考&lt;/h3>
&lt;p>在 Mac 上的“终端”中执行命令和运行工具 &lt;a href="https://support.apple.com/zh-cn/guide/terminal/apdb66b5242-0d18-49fc-9c47-a2498b7c91d5/mac">[1]&lt;/a>&lt;/p>
&lt;p>MAC命令快速全局查找文件或文件夹，支持模糊搜索 &lt;a href="https://blog.csdn.net/weixin_34403976/article/details/88844651">[2]&lt;/a>&lt;/p></description></item><item><title>Rust 镜像源</title><link>https://blog.baicai.me/article/2021/rustproxy/</link><pubDate>Fri, 25 Jun 2021 22:53:14 +0800</pubDate><author>admin@baicai.me (白菜)</author><guid>https://blog.baicai.me/article/2021/rustproxy/</guid><description>&lt;p>通常cargo跑得挺顺畅，不怎么需要proxy。但有备无患。&lt;/p>
&lt;h3 id="cratesio-和-rustup-的国内镜像源">crates.io 和 rustup 的国内镜像源&lt;/h3>
&lt;p>字节跳动提供的：https://rsproxy.cn/&lt;/p>
&lt;p>中国科技大学的：https://mirrors.ustc.edu.cn/help/crates.io-index.html&lt;/p>
&lt;p>清华大学的：https://mirrors.tuna.tsinghua.edu.cn/help/rustup/&lt;/p>
&lt;p>上海交通大学的：https://git.sjtu.edu.cn/sjtug/crates.io-index&lt;/p>
&lt;h3 id="更换国内源">更换国内源&lt;/h3>
&lt;p>更换为国内源，否则安装太慢了。
新建文件：~/.cargo/config，内容替换为如下，replace-with 这行可自己 ping 文件中各个国内源头，看哪个源快用哪个：&lt;/p>
&lt;pre tabindex="0">&lt;code class="language-conf" data-lang="conf">[source.crates-io]
registry = &amp;#34;https://github.com/rust-lang/crates.io-index&amp;#34;
# 替换成你偏好的镜像源
replace-with = &amp;#39;sjtu&amp;#39;
# 清华大学
[source.tuna]
registry = &amp;#34;https://mirrors.tuna.tsinghua.edu.cn/git/crates.io-index.git&amp;#34;
# 中国科学技术大学
[source.ustc]
registry = &amp;#34;git://mirrors.ustc.edu.cn/crates.io-index&amp;#34;
# 上海交通大学
[source.sjtu]
registry = &amp;#34;https://mirrors.sjtug.sjtu.edu.cn/git/crates.io-index&amp;#34;
# rustcc社区
[source.rustcc]
registry = &amp;#34;git://crates.rustcc.cn/crates.io-index&amp;#34;
# 字节跳动
[source.rsproxy]
registry = &amp;#34;https://rsproxy.cn/crates.io-index&amp;#34;
&lt;/code>&lt;/pre></description></item><item><title>给我来点酷炫玩意-Sharkle</title><link>https://blog.baicai.me/article/2021/sharkle/</link><pubDate>Wed, 23 Jun 2021 12:23:58 +0800</pubDate><author>admin@baicai.me (白菜)</author><guid>https://blog.baicai.me/article/2021/sharkle/</guid><description>&lt;blockquote>
&lt;p>网页前端是一门技术活！出色的网站除了后台够快够可靠，也非常需要前端吸引眼球。在这个网站里，点击SHOW ME SOMETHING AWESOME就能随机跳转到一个新页面，往往是一些用了平时不太多见的网页设计元素制作出来的页面演示，有时候也会有独到设计的网页游戏，或许还有些别的内容。这个网站收录的内容都挺不错，有些网站的质量完全可以拿出来单独写一篇文章。&lt;/p>&lt;/blockquote>
&lt;p>传送门 &lt;a href="https://sharkle.com/">https://sharkle.com/&lt;/a>&lt;/p>
&lt;h3 id="方法">方法&lt;/h3>
&lt;p>进入网站直接点击SHOW ME SOMETHING AWESOME即可欣赏！&lt;/p></description></item><item><title>Cargo Wix 创建Windows安装程序的cargo子命令</title><link>https://blog.baicai.me/article/2021/cargo-wix/</link><pubDate>Tue, 22 Jun 2021 22:48:53 +0800</pubDate><author>admin@baicai.me (白菜)</author><guid>https://blog.baicai.me/article/2021/cargo-wix/</guid><description>&lt;p>cargo-wix：创建Windows安装程序的cargo子命令
它使用二进制项目的发行版中的构建Windows安装程序（msi）。 如果可以使用提供的应用程序提供代码签名证书，则它还支持对Windows安装程序进行签名。&lt;/p>
&lt;h3 id="快速开始">快速开始&lt;/h3>
&lt;p>启动命令提示符（cmd.exe），然后执行以下命令：&lt;/p>
&lt;pre tabindex="0">&lt;code>C:\&amp;gt;cargo install cargo-wix
C:\&amp;gt;cd Path\To\Project
C:\Path\To\Project\&amp;gt;cargo wix init
C:\Path\To\Project\&amp;gt;cargo wix
&lt;/code>&lt;/pre>&lt;p>该项目的Windows安装程序（msi）将位于C:\Path\To\Project\target\wix文件夹中。&lt;/p>
&lt;h3 id="官方文档">官方文档&lt;/h3>
&lt;p>&lt;a href="https://crates.io/crates/cargo-wix">https://crates.io/crates/cargo-wix&lt;/a>&lt;/p></description></item><item><title>用 Deskreen 将你的 Linux 屏幕镜像或串流到任何设备上</title><link>https://blog.baicai.me/article/2021/linux_deskreen/</link><pubDate>Mon, 21 Jun 2021 19:50:25 +0800</pubDate><author>admin@baicai.me (白菜)</author><guid>https://blog.baicai.me/article/2021/linux_deskreen/</guid><description>&lt;blockquote>
&lt;p>如果你有多显示器设置，你会意识到拥有多个屏幕的好处。而且，有了 Deskreen，你可以把任何设备变成你的副屏。&lt;/p>&lt;/blockquote>
&lt;h3 id="deskreen将任何设备变成你的-linux-系统的副屏">Deskreen：将任何设备变成你的 Linux 系统的副屏&lt;/h3>
&lt;p>Deskreen 是一个自由开源的应用，可以让你使用任何带有 Web 浏览器的设备来作为电脑的副屏。&lt;/p>
&lt;p>如果你愿意，它还支持多个设备连接。&lt;/p>
&lt;p>Deskreen 很容易使用，当你的所有设备都连接到同一个 Wi-Fi 网络时，它可以正常工作。&lt;/p>
&lt;p>让我们来看看它的功能和工作原理。
Deskreen 的功能&lt;/p>
&lt;p>Deskreen 的功能包括以下要点：&lt;/p>
&lt;ul>
&lt;li>分享整个屏幕的能力&lt;/li>
&lt;li>选择一个特定的应用窗口进行串流&lt;/li>
&lt;li>翻转模式，将你的屏幕作为提词器使用&lt;/li>
&lt;li>支持多种设备&lt;/li>
&lt;li>高级视频质量设置&lt;/li>
&lt;li>提供端对端加密&lt;/li>
&lt;li>最小的系统要求&lt;/li>
&lt;li>黑暗模式&lt;/li>
&lt;/ul>
&lt;p>没有一个冗长的功能列表，但对大多数用户来说应该是足够的。&lt;/p>
&lt;h3 id="如何使用-deskreen-应用">如何使用 Deskreen 应用？&lt;/h3>
&lt;p>Deskreen 使用分为三个简单的步骤，让我为你强调一下，以便你开始使用：&lt;/p>
&lt;p>首先，当你启动该应用时，它会显示一个二维码和一个 IP 地址，以帮助你用 Web 浏览器连接其他设备，以串流你的屏幕。&lt;/p>
&lt;p>你可以按你喜欢的方式，在你的辅助设备上的 Web 浏览器的帮助下建立连接。&lt;/p>
&lt;p>当你扫描二维码或在浏览器的地址栏中输入 IP 地址，你会在 Deskreen 应用上得到一个提示，允许或拒绝连接。除非是你不认识它，否则就允许吧。&lt;/p>
&lt;p>接下来，你将被要求选择你想要串流的内容（你的整个屏幕或特定的应用窗口）：&lt;/p>
&lt;p>你可以选择串流整个屏幕或选择你想串流的窗口。然而，并不是每个应用窗口都能被检测到。&lt;/p>
&lt;p>你只需要选择源并确认，就可以了。你应该注意到它在你的副屏（手机/桌面）上开始串流。&lt;/p>
&lt;p>Deskreen 还为你提供了管理连接设备的能力。因此，如果你需要断开任何会话或所有会话的连接，你可以从设置中进行操作。&lt;/p>
&lt;h3 id="在-linux-中安装-deskreen">在 Linux 中安装 Deskreen&lt;/h3>
&lt;p>你会找到一个用于 Linux 机器的 DEB 包和 AppImage 文件。如果你不知道，可以通过我们的 安装 DEB 包 和 使用 AppImage 文件 指南来安装它。&lt;/p>
&lt;p>你可以从 官方网站 下载它，或者从它的 &lt;a href="https://github.com/pavlobu/deskreen">GitHub&lt;/a> 页面探索更多的信息。&lt;/p>
&lt;h3 id="结束语">结束语&lt;/h3>
&lt;p>考虑到它使用 Wi-Fi 网络工作，在串流方面绝对没有问题。这是一种奇妙的方式，可以与别人分享你的屏幕，或者出于任何目的将其串流到第二个设备上。&lt;/p>
&lt;p>当然，它不能取代你的电脑的第二个显示器的优势，但在一些使用情况下，你可能不需要第二个屏幕。&lt;/p>
&lt;h3 id="参考">参考&lt;/h3>
&lt;p>With Deskreen, You Can Mirror or Stream Your Linux Computer Screen to Any Device &lt;a href="https://itsfoss.com/deskreen/">[1]&lt;/a>&lt;/p>
&lt;p>用 Deskreen 将你的 Linux 屏幕镜像或串流到任何设备上 &lt;a href="https://linux.cn/article-13507-1.html">[2]&lt;/a>&lt;/p></description></item><item><title>为你营造专注冥想的时间-The Zen Zone</title><link>https://blog.baicai.me/article/2021/the-zen-zone/</link><pubDate>Mon, 21 Jun 2021 16:57:16 +0800</pubDate><author>admin@baicai.me (白菜)</author><guid>https://blog.baicai.me/article/2021/the-zen-zone/</guid><description>&lt;blockquote>
&lt;p>网站为你营造了专注冥想的时间，通过三个简单的小游戏，你可以进入一个精神集中的状态，从而让大脑思维平静下来！&lt;/p>&lt;/blockquote>
&lt;p>传送门 &lt;a href="https://thezen.zone/">https://thezen.zone/&lt;/a>&lt;/p>
&lt;h3 id="方法">方法&lt;/h3>
&lt;p>进入网站直接开始冥想吧！&lt;/p></description></item><item><title>全球高清实况摄像头-Skylinewebcams</title><link>https://blog.baicai.me/article/2021/skylinewebcams/</link><pubDate>Mon, 14 Jun 2021 20:57:41 +0800</pubDate><author>admin@baicai.me (白菜)</author><guid>https://blog.baicai.me/article/2021/skylinewebcams/</guid><description>&lt;blockquote>
&lt;p>网站收录了全球范围内的公开实况摄像头，你可以看到世界各地的文化遗产、城市风光、人气景点！&lt;/p>&lt;/blockquote>
&lt;p>传送门 &lt;a href="https://www.skylinewebcams.com/">https://www.skylinewebcams.com/&lt;/a>&lt;/p>
&lt;h3 id="方法">方法&lt;/h3>
&lt;p>网站支持中文，进入后直接观看！&lt;/p></description></item><item><title>Linux 常用命令</title><link>https://blog.baicai.me/article/2021/linux_cmd/</link><pubDate>Sat, 05 Jun 2021 10:31:29 +0800</pubDate><author>admin@baicai.me (白菜)</author><guid>https://blog.baicai.me/article/2021/linux_cmd/</guid><description>&lt;p>Linux 常用命令&lt;/p>
&lt;h3 id="日期">日期&lt;/h3>
&lt;div class="highlight">&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;">&lt;code class="language-bash" data-lang="bash">&lt;span style="display:flex;">&lt;span>&lt;span style="color:#66d9ef">$(&lt;/span>date -d &lt;span style="color:#e6db74">&amp;#39;1 day ago&amp;#39;&lt;/span> &lt;span style="color:#e6db74">&amp;#39;+%Y-%m-%d&amp;#39;&lt;/span>&lt;span style="color:#66d9ef">)&lt;/span>
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>&lt;p>常用方法&lt;/p>
&lt;h3 id="数字格式化">数字格式化&lt;/h3>
&lt;div class="highlight">&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;">&lt;code class="language-bash" data-lang="bash">&lt;span style="display:flex;">&lt;span>part&lt;span style="color:#f92672">=&lt;/span>&lt;span style="color:#e6db74">`&lt;/span>printf &lt;span style="color:#e6db74">&amp;#34;%03d&amp;#34;&lt;/span> $i&lt;span style="color:#e6db74">`&lt;/span> &lt;span style="color:#75715e"># 左补0&lt;/span>
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>&lt;h3 id="删除旧文件">删除旧文件&lt;/h3>
&lt;div class="highlight">&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;">&lt;code class="language-bash" data-lang="bash">&lt;span style="display:flex;">&lt;span>&lt;span style="color:#75715e"># 找出5天前修改的文件名以.tar结尾的文件进行删除&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>find /www/backup -mtime +5 -name &lt;span style="color:#e6db74">&amp;#34;*.tar&amp;#34;&lt;/span> |xargs rm
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>&lt;h3 id="for循环">for循环&lt;/h3>
&lt;div class="highlight">&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;">&lt;code class="language-bash" data-lang="bash">&lt;span style="display:flex;">&lt;span>&lt;span style="color:#66d9ef">for&lt;/span> &lt;span style="color:#f92672">((&lt;/span>i&lt;span style="color:#f92672">=&lt;/span>0;i&amp;lt;10;i++&lt;span style="color:#f92672">))&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#66d9ef">do&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>_date&lt;span style="color:#f92672">=&lt;/span>&lt;span style="color:#66d9ef">$(&lt;/span>date +%Y-%m-%d -d &lt;span style="color:#e6db74">&amp;#34;&lt;/span>&lt;span style="color:#e6db74">${&lt;/span>i&lt;span style="color:#e6db74">}&lt;/span>&lt;span style="color:#e6db74"> day&amp;#34;&lt;/span>&lt;span style="color:#66d9ef">)&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>echo $_date
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#66d9ef">done&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#75715e">#&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#66d9ef">for&lt;/span> i in &lt;span style="color:#f92672">{&lt;/span>1..10&lt;span style="color:#f92672">}&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#66d9ef">do&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> echo $i
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#66d9ef">done&lt;/span>
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>&lt;h3 id="文件合并">文件合并&lt;/h3>
&lt;div class="highlight">&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;">&lt;code class="language-bash" data-lang="bash">&lt;span style="display:flex;">&lt;span>find ./ -name &lt;span style="color:#e6db74">&amp;#34;item*&amp;#34;&lt;/span> | xargs sed &lt;span style="color:#e6db74">&amp;#39;a\&amp;#39;&lt;/span> &amp;gt; all.txt
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>find ./ -name &lt;span style="color:#e6db74">&amp;#34;item*&amp;#34;&lt;/span> | xargs cat &amp;gt; all.txt
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>:s/old/new &lt;span style="color:#75715e">#替换当前行的第一个old为new&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>:s/old/new/g &lt;span style="color:#75715e">#替换当前行的所有的old为new&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>:.,$s/old/new &lt;span style="color:#75715e">#替换当前行到最后行的第一个old为new&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>:.,$s/old/new/g &lt;span style="color:#75715e">#替换当前行到最后行的所有old为new&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>:N,Ms/old/new &lt;span style="color:#75715e">#替换第N行到第M行的第一个old为new&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>:N,Ms/old/new/g &lt;span style="color:#75715e">#替换第N行到第M行的所有old为new&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>:N,Ms/old/new/gc &lt;span style="color:#75715e">#替换第N行到第M行的所有old为new，且逐一询问是否删除&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>:%s/old/new &lt;span style="color:#75715e">#替换所有行的第一个old为new&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>:%s/old/new/g &lt;span style="color:#75715e">#替换所有行的所有old为new&lt;/span>
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>&lt;h3 id="文件排序交集并集差集">文件排序、交集、并集、差集&lt;/h3>
&lt;div class="highlight">&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;">&lt;code class="language-bash" data-lang="bash">&lt;span style="display:flex;">&lt;span>&lt;span style="color:#75715e">#排序&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>sort a.txt |uniq -c
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#75715e">#一、交集&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>sort a.txt b.txt | uniq -d
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#75715e">#二、并集&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>sort a.txt b.txt | uniq
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#75715e">#三、差集 a.txt-b.txt:&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>sort a.txt b.txt b.txt | uniq -u
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#75715e">#差集 b.txt - a.txt:&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>sort b.txt a.txt a.txt | uniq -u
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>&lt;h3 id="删除重复行">删除重复行&lt;/h3>
&lt;div class="highlight">&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;">&lt;code class="language-bash" data-lang="bash">&lt;span style="display:flex;">&lt;span>sort -k2n all.txt | uniq &amp;gt; real.out
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>sort -k2n all.txt | awk &lt;span style="color:#e6db74">&amp;#39;{if ($0!=line) print;line=$0}&amp;#39;&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>sort -k2n all.txt | sed &lt;span style="color:#e6db74">&amp;#39;$!N; /^\(.*\)\n\1$/!P; D&amp;#39;&lt;/span>
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>&lt;h3 id="删除空格">删除空格&lt;/h3>
&lt;div class="highlight">&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;">&lt;code class="language-bash" data-lang="bash">&lt;span style="display:flex;">&lt;span>cat all.txt |sed s/&lt;span style="color:#f92672">[[&lt;/span>:space:&lt;span style="color:#f92672">]]&lt;/span>//g
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>&lt;h3 id="awk-去重">awk 去重&lt;/h3>
&lt;div class="highlight">&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;">&lt;code class="language-bash" data-lang="bash">&lt;span style="display:flex;">&lt;span>awk &lt;span style="color:#e6db74">&amp;#39;!($1 in a){a[$1];print $1}&amp;#39;&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#75715e">#或&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>sort $1 | uniq
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#75715e"># awk结果使用逗号间隔拼接&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>awk -F &lt;span style="color:#e6db74">&amp;#39;,&amp;#39;&lt;/span> &lt;span style="color:#e6db74">&amp;#39;{print $1}&amp;#39;&lt;/span> | xargs | tr &lt;span style="color:#e6db74">&amp;#39; &amp;#39;&lt;/span> &lt;span style="color:#e6db74">&amp;#39;,&amp;#39;&lt;/span>
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>&lt;h3 id="常用状态查看">常用状态查看&lt;/h3>
&lt;div class="highlight">&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;">&lt;code class="language-bash" data-lang="bash">&lt;span style="display:flex;">&lt;span>&lt;span style="color:#75715e"># 按CPU和内存倒序前n个进程&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>ps -aux --sort -pcpu,+pmem | head -n &lt;span style="color:#ae81ff">5&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#75715e"># 按进程名查看&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>ps -f -C java
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>&lt;h3 id="文件同步rsync">文件同步rsync&lt;/h3>
&lt;div class="highlight">&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;">&lt;code class="language-bash" data-lang="bash">&lt;span style="display:flex;">&lt;span>rsync -zvrtopgl --progress --delete /fromDist/ root@s1:/toDist/
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>&lt;h3 id="链接状态统计">链接状态统计&lt;/h3>
&lt;div class="highlight">&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;">&lt;code class="language-bash" data-lang="bash">&lt;span style="display:flex;">&lt;span>netstat -n | awk &lt;span style="color:#e6db74">&amp;#39;/^tcp/ {++S[$NF]} END {for(a in S) print a, S[a]}&amp;#39;&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#75715e"># TCP连接状态详解 &lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#75715e"># LISTEN: 服务器在侦听来自远方的TCP端口的连接请求&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#75715e"># SYN-SENT: 在发送连接请求后等待匹配的连接请求&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#75715e"># SYN_RECV: 一个连接请求已经到达，等待确认&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#75715e"># SYN-RECEIVED: 再收到和发送一个连接请求后等待对方对连接请求的确认&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#75715e"># ESTABLISHED: 代表一个打开的连接/正常数据传输状态/当前并发连接数&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#75715e"># FIN_WAIT1: 等待远程TCP连接中断请求，或先前的连接中断请求的确认/应用说它已经完成&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#75715e"># FIN_WAIT2: 从远程TCP等待连接中断请求/另一边已同意释放&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#75715e"># CLOSE-WAIT: 等待从本地用户发来的连接中断请求&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#75715e"># CLOSING: 等待远程TCP对连接中断的确认/两边同时尝试关闭&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#75715e"># LAST-ACK: 等待原来的发向远程TCP的连接中断请求的确认/等待所有分组死掉&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#75715e"># TIME-WAIT: 等待足够的时间以确保远程TCP接收到连接中断请求的确认/另一边已初始化一个释放&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#75715e"># ITMED_WAIT: 等待所有分组死掉&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#75715e"># CLOSED： 没有任何连接状态&lt;/span>
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>&lt;h3 id="cpu内存系统信息查看">CPU/内存/系统信息查看&lt;/h3>
&lt;div class="highlight">&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;">&lt;code class="language-bash" data-lang="bash">&lt;span style="display:flex;">&lt;span>&lt;span style="color:#75715e"># cpu&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>grep &lt;span style="color:#e6db74">&amp;#34;model name&amp;#34;&lt;/span> /proc/cpuinfo
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>cat /proc/cpuinfo | grep name | cut -f2 -d: | uniq -c
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>cat /proc/cpuinfo | grep physical | uniq -c
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#75715e"># cpu位数&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>echo $HOSTTYPE
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#75715e"># 内存&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>grep MemTotal /proc/meminfo
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#75715e"># linux 版本&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>cat /etc/redhat-release
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>cat /etc/os-release
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>cat /etc/lsb-release
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#75715e"># linux 内核版本&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>uname -a
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>uname -r
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>&lt;h3 id="常用监控工具">常用监控工具&lt;/h3>
&lt;div class="highlight">&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;">&lt;code class="language-bash" data-lang="bash">&lt;span style="display:flex;">&lt;span>&lt;span style="color:#75715e"># 网络监控&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>iftop
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#75715e"># IO监控&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>iotop
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#75715e"># 负载监控&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>htop
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>top
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>&lt;h3 id="进程监控">进程监控&lt;/h3>
&lt;div class="highlight">&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;">&lt;code class="language-bash" data-lang="bash">&lt;span style="display:flex;">&lt;span>pidstat -p &lt;span style="color:#ae81ff">843&lt;/span> &lt;span style="color:#ae81ff">1&lt;/span> &lt;span style="color:#ae81ff">3&lt;/span> -u -t
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#75715e"># -u：代表对 CPU 使用率的监控&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#75715e"># 参数 1 3 代表每秒采样一次，一共三次&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#75715e"># -t：将监控级别细化到线程&lt;/span>
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>&lt;h3 id="ssh相关">ssh相关&lt;/h3>
&lt;div class="highlight">&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;">&lt;code class="language-bash" data-lang="bash">&lt;span style="display:flex;">&lt;span>&lt;span style="color:#75715e"># 秘钥生成&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>ssh-keygen -t rsa -b &lt;span style="color:#ae81ff">4096&lt;/span> -C &lt;span style="color:#e6db74">&amp;#34;your_hostname&amp;#34;&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#75715e"># 免密登录&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>cat ~/.ssh/id_rsa.pub | ssh root@ip &lt;span style="color:#e6db74">&amp;#34;cat &amp;gt;&amp;gt; .ssh/authorized_keys&amp;#34;&lt;/span>
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>&lt;h3 id="firewalld防火墙使用">firewalld防火墙使用&lt;/h3>
&lt;div class="highlight">&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;">&lt;code class="language-bash" data-lang="bash">&lt;span style="display:flex;">&lt;span>&lt;span style="color:#75715e"># 禁止ping&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>firewall-cmd --permanent --add-rich-rule&lt;span style="color:#f92672">=&lt;/span>&lt;span style="color:#e6db74">&amp;#39;rule protocol value=icmp drop&amp;#39;&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#75715e"># 允许192.168.1.0/24主机所有连接&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>firewall-cmd --add-rich-rule&lt;span style="color:#f92672">=&lt;/span>&lt;span style="color:#e6db74">&amp;#39;rule family=&amp;#34;ipv4&amp;#34; source address=&amp;#34;192.168.1.0&amp;#34; accept&amp;#39;&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#75715e"># 禁止某IP访问&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>firewall-cmd --permanent --zone&lt;span style="color:#f92672">=&lt;/span>public --add-rich-rule&lt;span style="color:#f92672">=&lt;/span>&lt;span style="color:#e6db74">&amp;#34;rule family=ipv4 source address=&amp;#39;123.56.247.76/24&amp;#39; reject&amp;#34;&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#75715e"># 开放端口&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>firewall-cmd --zone&lt;span style="color:#f92672">=&lt;/span>public --permanent --add-port&lt;span style="color:#f92672">=&lt;/span>8080/tcp
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>firewall-cmd --reload
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>&lt;h3 id="文件统计">文件统计&lt;/h3>
&lt;div class="highlight">&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;">&lt;code class="language-bash" data-lang="bash">&lt;span style="display:flex;">&lt;span>ls -g |awk &lt;span style="color:#e6db74">&amp;#39;BEGIN{sum=0}{sum+=$4}END{print sum/(1024*1024*1024)}&amp;#39;&lt;/span>
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>&lt;h3 id="history格式及数量修改">history格式及数量修改&lt;/h3>
&lt;div class="highlight">&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;">&lt;code class="language-bash" data-lang="bash">&lt;span style="display:flex;">&lt;span>export HISTSIZE&lt;span style="color:#f92672">=&lt;/span>&lt;span style="color:#ae81ff">10000&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>export HISTTIMEFORMAT&lt;span style="color:#f92672">=&lt;/span>&lt;span style="color:#e6db74">&amp;#34; %Y-%m-%d %H:%M:%S - `who am i 2&amp;gt;/dev/null | awk &amp;#39;{print &lt;/span>$NF&lt;span style="color:#e6db74">}&amp;#39;|sed -e &amp;#39;s/[()]//g&amp;#39;` - `who -u am i |awk &amp;#39;{print &lt;/span>$1&lt;span style="color:#e6db74">}&amp;#39;` &amp;#34;&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>export PROMPT_COMMAND&lt;span style="color:#f92672">=&lt;/span>&lt;span style="color:#e6db74">&amp;#34;history 1 &amp;gt;&amp;gt; /var/log/.myhistory&amp;#34;&lt;/span> &lt;span style="color:#75715e">#将命令记录输出到文本中&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>touch /var/log/.myhistory
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>chmod /var/log/.myhistory
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div></description></item><item><title>awk 分析 nginx 运行日志常用指令</title><link>https://blog.baicai.me/article/2021/awk-nginx-access_log/</link><pubDate>Sat, 05 Jun 2021 10:16:16 +0800</pubDate><author>admin@baicai.me (白菜)</author><guid>https://blog.baicai.me/article/2021/awk-nginx-access_log/</guid><description>&lt;p>awk 分析 nginx 运行日志常用指令&lt;/p>
&lt;p>1.独立IP&lt;/p>
&lt;div class="highlight">&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;">&lt;code class="language-bash" data-lang="bash">&lt;span style="display:flex;">&lt;span>awk &lt;span style="color:#e6db74">&amp;#39;{print $1}&amp;#39;&lt;/span> access.log | sort -r |uniq -c | wc -l
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>&lt;p>2.统计PV&lt;/p>
&lt;div class="highlight">&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;">&lt;code class="language-bash" data-lang="bash">&lt;span style="display:flex;">&lt;span>awk &lt;span style="color:#e6db74">&amp;#39;{print $6}&amp;#39;&lt;/span> access.log | wc -l
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>&lt;p>3.查询访问最频繁的URL&lt;/p>
&lt;div class="highlight">&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;">&lt;code class="language-bash" data-lang="bash">&lt;span style="display:flex;">&lt;span>awk &lt;span style="color:#e6db74">&amp;#39;{print $7}&amp;#39;&lt;/span> access.log|sort | uniq -c |sort -n -k &lt;span style="color:#ae81ff">1&lt;/span> -r|more
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>&lt;p>4.查询访问最频繁的IP&lt;/p>
&lt;div class="highlight">&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;">&lt;code class="language-bash" data-lang="bash">&lt;span style="display:flex;">&lt;span>awk &lt;span style="color:#e6db74">&amp;#39;{print $1}&amp;#39;&lt;/span> access.log|sort | uniq -c |sort -n -k &lt;span style="color:#ae81ff">1&lt;/span> -r|more
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>&lt;p>5.UV统计：&lt;/p>
&lt;div class="highlight">&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;">&lt;code class="language-bash" data-lang="bash">&lt;span style="display:flex;">&lt;span>awk &lt;span style="color:#e6db74">&amp;#39;{print $6}&amp;#39;&lt;/span> access.log | sort -r |uniq -c |wc -l
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>&lt;p>6.按小时统计&lt;/p>
&lt;div class="highlight">&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;">&lt;code class="language-bash" data-lang="bash">&lt;span style="display:flex;">&lt;span>cat access.log |awk &lt;span style="color:#e6db74">&amp;#39;{print $4}&amp;#39;&lt;/span> | awk -F &lt;span style="color:#e6db74">&amp;#39;:&amp;#39;&lt;/span> &lt;span style="color:#e6db74">&amp;#39;{print $1,$2}&amp;#39;&lt;/span>|uniq -c | awk &lt;span style="color:#e6db74">&amp;#39;{print $2&amp;#34; &amp;#34;$3&amp;#34; &amp;#34;$1}&amp;#39;&lt;/span>
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div></description></item><item><title>TOML 语言规范 1.0 正式版</title><link>https://blog.baicai.me/article/2021/toml/</link><pubDate>Sat, 05 Jun 2021 02:59:55 +0800</pubDate><author>admin@baicai.me (白菜)</author><guid>https://blog.baicai.me/article/2021/toml/</guid><description>&lt;p>👉 TOML 语言广泛用于 Rust 项目当中，cargo new 一个新项目时都会新建一个 toml 的配置文件，所以学习 Rust 过程中也有必要熟悉 TOML 语言的相关语法，从而熟练在 Rust 项目中编辑配置文件。&lt;/p>
&lt;p>👉 本文来自 &lt;a href="https://github.com/toml-lang/toml.io">toml-lang 的中文翻译版本&lt;/a>，本文收录在此处，只是方便 Rust 学习者统一查阅，若是发现有任何错误或需要完善地方，请在 toml.io 原项目仓库指出或修改错误。&lt;/p>
&lt;h1 id="toml-v100">TOML v1.0.0&lt;/h1>
&lt;p>全称：Tom 的（语义）明显、（配置）最小化的语言。（Tom&amp;rsquo;s Obvious, Minimal Language）&lt;br>
作者：Tom Preston-Werner、Pradyun Gedam 等人。&lt;/p>
&lt;h3 id="宗旨">宗旨&lt;/h3>
&lt;p>TOML 旨在成为一个语义明显且易于阅读的最小化配置文件格式。&lt;br>
TOML 被设计成可以无歧义地映射为哈希表。&lt;br>
TOML 应该能很容易地被解析成各种语言中的数据结构。&lt;/p>
&lt;h3 id="目录">目录&lt;/h3>
&lt;ul>
&lt;li>&lt;a href="#%E8%A7%84%E6%A0%BC">规格&lt;/a>&lt;/li>
&lt;li>&lt;a href="#%E6%B3%A8%E9%87%8A">注释&lt;/a>&lt;/li>
&lt;li>&lt;a href="#%E9%94%AE%E5%80%BC%E5%AF%B9">键值对&lt;/a>&lt;/li>
&lt;li>&lt;a href="#%E9%94%AE%E5%90%8D">键名&lt;/a>&lt;/li>
&lt;li>&lt;a href="#%E5%AD%97%E7%AC%A6%E4%B8%B2">字符串&lt;/a>&lt;/li>
&lt;li>&lt;a href="#%E6%95%B4%E6%95%B0">整数&lt;/a>&lt;/li>
&lt;li>&lt;a href="#%E6%B5%AE%E7%82%B9%E6%95%B0">浮点数&lt;/a>&lt;/li>
&lt;li>&lt;a href="#%E5%B8%83%E5%B0%94%E5%80%BC">布尔值&lt;/a>&lt;/li>
&lt;li>&lt;a href="#%E5%9D%90%E6%A0%87%E6%97%A5%E6%9C%9F%E6%97%B6%E5%88%BB">坐标日期时刻&lt;/a>&lt;/li>
&lt;li>&lt;a href="#%E5%90%84%E5%9C%B0%E6%97%A5%E6%9C%9F%E6%97%B6%E5%88%BB">各地日期时刻&lt;/a>&lt;/li>
&lt;li>&lt;a href="#%E5%90%84%E5%9C%B0%E6%97%A5%E6%9C%9F">各地日期&lt;/a>&lt;/li>
&lt;li>&lt;a href="#%E5%90%84%E5%9C%B0%E6%97%B6%E5%88%BB">各地时刻&lt;/a>&lt;/li>
&lt;li>&lt;a href="#%E6%95%B0%E7%BB%84">数组&lt;/a>&lt;/li>
&lt;li>&lt;a href="#%E8%A1%A8">表&lt;/a>&lt;/li>
&lt;li>&lt;a href="#%E5%86%85%E8%81%94%E8%A1%A8">内联表&lt;/a>&lt;/li>
&lt;li>&lt;a href="#%E8%A1%A8%E6%95%B0%E7%BB%84">表数组&lt;/a>&lt;/li>
&lt;li>&lt;a href="#%E6%96%87%E4%BB%B6%E6%89%A9%E5%B1%95%E5%90%8D">文件扩展名&lt;/a>&lt;/li>
&lt;li>&lt;a href="#mime-%E7%B1%BB%E5%9E%8B">MIME 类型&lt;/a>&lt;/li>
&lt;li>&lt;a href="#abnf-%E8%AF%AD%E6%B3%95">ABNF 语法&lt;/a>&lt;/li>
&lt;/ul>
&lt;h3 id="规格">规格&lt;/h3>
&lt;ul>
&lt;li>TOML 是大小写敏感的。&lt;/li>
&lt;li>TOML 文件必须是合法的 UTF-8 编码的 Unicode 文档。&lt;/li>
&lt;li>空白是指制表符（0x09）或空格（0x20）。&lt;/li>
&lt;li>换行是指 LF（0x0A）或 CRLF（0x0D0A）。&lt;/li>
&lt;/ul>
&lt;h3 id="注释">注释&lt;/h3>
&lt;p>井字符将该行余下的部分标记为注释，除非它在字符串中。&lt;/p>
&lt;div class="highlight">&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;">&lt;code class="language-toml" data-lang="toml">&lt;span style="display:flex;">&lt;span>&lt;span style="color:#75715e"># 这是一个全行注释&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#a6e22e">key&lt;/span> = &lt;span style="color:#e6db74">&amp;#34;value&amp;#34;&lt;/span> &lt;span style="color:#75715e"># 这是一个行末注释&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#a6e22e">another&lt;/span> = &lt;span style="color:#e6db74">&amp;#34;# 这不是一个注释&amp;#34;&lt;/span>
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>&lt;p>除制表符以外的控制字符（U+0000 至 U+0008，U+000A 至 U+001F，U+007F）不允许出现在注释中。&lt;/p>
&lt;h3 id="键值对">键值对&lt;/h3>
&lt;p>TOML 文档最基本的构成区块是键值对。&lt;/p>
&lt;p>键名在等号的左边而值在右边。&lt;br>
键名和键值周围的空白会被忽略。&lt;br>
键、等号和值必须在同一行（不过有些值可以跨多行）。&lt;/p>
&lt;div class="highlight">&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;">&lt;code class="language-toml" data-lang="toml">&lt;span style="display:flex;">&lt;span>&lt;span style="color:#a6e22e">key&lt;/span> = &lt;span style="color:#e6db74">&amp;#34;value&amp;#34;&lt;/span>
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>&lt;p>值必须是下述类型之一。&lt;/p>
&lt;ul>
&lt;li>&lt;a href="#%E5%AD%97%E7%AC%A6%E4%B8%B2">字符串&lt;/a>&lt;/li>
&lt;li>&lt;a href="#%E6%95%B4%E6%95%B0">整数&lt;/a>&lt;/li>
&lt;li>&lt;a href="#%E6%B5%AE%E7%82%B9%E6%95%B0">浮点数&lt;/a>&lt;/li>
&lt;li>&lt;a href="#%E5%B8%83%E5%B0%94%E5%80%BC">布尔值&lt;/a>&lt;/li>
&lt;li>&lt;a href="#%E5%9D%90%E6%A0%87%E6%97%A5%E6%9C%9F%E6%97%B6%E5%88%BB">坐标日期时刻&lt;/a>&lt;/li>
&lt;li>&lt;a href="#%E5%90%84%E5%9C%B0%E6%97%A5%E6%9C%9F%E6%97%B6%E5%88%BB">各地日期时刻&lt;/a>&lt;/li>
&lt;li>&lt;a href="#%E5%90%84%E5%9C%B0%E6%97%A5%E6%9C%9F">各地日期&lt;/a>&lt;/li>
&lt;li>&lt;a href="#%E5%90%84%E5%9C%B0%E6%97%B6%E5%88%BB">各地时刻&lt;/a>&lt;/li>
&lt;li>&lt;a href="#%E6%95%B0%E7%BB%84">数组&lt;/a>&lt;/li>
&lt;li>&lt;a href="#%E5%86%85%E8%81%94%E8%A1%A8">内联表&lt;/a>&lt;/li>
&lt;/ul>
&lt;p>不指定值是非法的。&lt;/p>
&lt;div class="highlight">&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;">&lt;code class="language-toml" data-lang="toml">&lt;span style="display:flex;">&lt;span>&lt;span style="color:#a6e22e">key&lt;/span> = &lt;span style="color:#75715e"># 非法&lt;/span>
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>&lt;p>键值对后必须换行（或结束文件）。&lt;br>
（例外见&lt;a href="#%E5%86%85%E8%81%94%E8%A1%A8">内联表&lt;/a>）&lt;/p>
&lt;pre tabindex="0">&lt;code>first = &amp;#34;Tom&amp;#34; last = &amp;#34;Preston-Werner&amp;#34; # 非法
&lt;/code>&lt;/pre>&lt;h3 id="键名">键名&lt;/h3>
&lt;p>键名可以是裸露的，引号引起来的，或点分隔的。&lt;/p>
&lt;p>&lt;strong>裸键&lt;/strong>只能包含 ASCII 字母，ASCII 数字，下划线和短横线（&lt;code>A-Za-z0-9_-&lt;/code>）。&lt;br>
注意裸键允许仅由纯 ASCII 数字构成，例如 &lt;code>1234&lt;/code>，但是是被理解为字符串的。&lt;/p>
&lt;div class="highlight">&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;">&lt;code class="language-toml" data-lang="toml">&lt;span style="display:flex;">&lt;span>&lt;span style="color:#a6e22e">key&lt;/span> = &lt;span style="color:#e6db74">&amp;#34;value&amp;#34;&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#a6e22e">bare_key&lt;/span> = &lt;span style="color:#e6db74">&amp;#34;value&amp;#34;&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#a6e22e">bare-key&lt;/span> = &lt;span style="color:#e6db74">&amp;#34;value&amp;#34;&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#ae81ff">1234&lt;/span> = &lt;span style="color:#e6db74">&amp;#34;value&amp;#34;&lt;/span>
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>&lt;p>&lt;strong>引号键&lt;/strong>遵循与基本字符串或字面量字符串相同的规则并允许你使用更为广泛的键名。&lt;br>
除非明显必要，使用裸键方为最佳实践。&lt;/p>
&lt;div class="highlight">&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;">&lt;code class="language-toml" data-lang="toml">&lt;span style="display:flex;">&lt;span>&lt;span style="color:#e6db74">&amp;#34;127.0.0.1&amp;#34;&lt;/span> = &lt;span style="color:#e6db74">&amp;#34;value&amp;#34;&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#e6db74">&amp;#34;character encoding&amp;#34;&lt;/span> = &lt;span style="color:#e6db74">&amp;#34;value&amp;#34;&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#e6db74">&amp;#34;ʎǝʞ&amp;#34;&lt;/span> = &lt;span style="color:#e6db74">&amp;#34;value&amp;#34;&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#e6db74">&amp;#39;key2&amp;#39;&lt;/span> = &lt;span style="color:#e6db74">&amp;#34;value&amp;#34;&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#e6db74">&amp;#39;quoted &amp;#34;value&amp;#34;&amp;#39;&lt;/span> = &lt;span style="color:#e6db74">&amp;#34;value&amp;#34;&lt;/span>
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>&lt;p>裸键中不能为空，但空引号键是允许的（虽然不建议如此）。&lt;/p>
&lt;div class="highlight">&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;">&lt;code class="language-toml" data-lang="toml">&lt;span style="display:flex;">&lt;span>= &lt;span style="color:#e6db74">&amp;#34;no key name&amp;#34;&lt;/span> &lt;span style="color:#75715e"># 非法&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#e6db74">&amp;#34;&amp;#34;&lt;/span> = &lt;span style="color:#e6db74">&amp;#34;blank&amp;#34;&lt;/span> &lt;span style="color:#75715e"># 合法但不鼓励&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#e6db74">&amp;#39;&amp;#39;&lt;/span> = &lt;span style="color:#e6db74">&amp;#39;blank&amp;#39;&lt;/span> &lt;span style="color:#75715e"># 合法但不鼓励&lt;/span>
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>&lt;p>&lt;strong>点分隔键&lt;/strong>是一系列通过点相连的裸键或引号键。&lt;br>
这允许了你将相近属性放在一起：&lt;/p>
&lt;div class="highlight">&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;">&lt;code class="language-toml" data-lang="toml">&lt;span style="display:flex;">&lt;span>&lt;span style="color:#a6e22e">name&lt;/span> = &lt;span style="color:#e6db74">&amp;#34;Orange&amp;#34;&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#a6e22e">physical&lt;/span>.&lt;span style="color:#a6e22e">color&lt;/span> = &lt;span style="color:#e6db74">&amp;#34;orange&amp;#34;&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#a6e22e">physical&lt;/span>.&lt;span style="color:#a6e22e">shape&lt;/span> = &lt;span style="color:#e6db74">&amp;#34;round&amp;#34;&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#a6e22e">site&lt;/span>.&lt;span style="color:#e6db74">&amp;#34;google.com&amp;#34;&lt;/span> = &lt;span style="color:#66d9ef">true&lt;/span>
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>&lt;p>等价于 JSON 的如下结构：&lt;/p>
&lt;div class="highlight">&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;">&lt;code class="language-json" data-lang="json">&lt;span style="display:flex;">&lt;span>{
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#f92672">&amp;#34;name&amp;#34;&lt;/span>: &lt;span style="color:#e6db74">&amp;#34;Orange&amp;#34;&lt;/span>,
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#f92672">&amp;#34;physical&amp;#34;&lt;/span>: {
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#f92672">&amp;#34;color&amp;#34;&lt;/span>: &lt;span style="color:#e6db74">&amp;#34;orange&amp;#34;&lt;/span>,
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#f92672">&amp;#34;shape&amp;#34;&lt;/span>: &lt;span style="color:#e6db74">&amp;#34;round&amp;#34;&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> },
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#f92672">&amp;#34;site&amp;#34;&lt;/span>: {
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#f92672">&amp;#34;google.com&amp;#34;&lt;/span>: &lt;span style="color:#66d9ef">true&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> }
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>}
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>&lt;p>有关点分隔键定义表的详细信息，请参阅后文&lt;a href="#%E8%A1%A8">表&lt;/a>一节。&lt;/p>
&lt;p>点分隔符周围的空白会被忽略。&lt;br>
不过，最佳实践是不要使用任何不必要的空白。&lt;/p>
&lt;div class="highlight">&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;">&lt;code class="language-toml" data-lang="toml">&lt;span style="display:flex;">&lt;span>&lt;span style="color:#a6e22e">fruit&lt;/span>.&lt;span style="color:#a6e22e">name&lt;/span> = &lt;span style="color:#e6db74">&amp;#34;banana&amp;#34;&lt;/span> &lt;span style="color:#75715e"># 这是最佳实践&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#a6e22e">fruit&lt;/span>. &lt;span style="color:#a6e22e">color&lt;/span> = &lt;span style="color:#e6db74">&amp;#34;yellow&amp;#34;&lt;/span> &lt;span style="color:#75715e"># 等同于 fruit.color&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#a6e22e">fruit&lt;/span> . &lt;span style="color:#a6e22e">flavor&lt;/span> = &lt;span style="color:#e6db74">&amp;#34;banana&amp;#34;&lt;/span> &lt;span style="color:#75715e"># 等同于 fruit.flavor&lt;/span>
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>&lt;p>缩进被作为空白对待而被忽略。&lt;/p>
&lt;p>多次定义同一个键是非法的。&lt;/p>
&lt;pre tabindex="0">&lt;code># 不要这样做
name = &amp;#34;Tom&amp;#34;
name = &amp;#34;Pradyun&amp;#34;
&lt;/code>&lt;/pre>&lt;p>注意裸键和引号键是等价的：&lt;/p>
&lt;pre tabindex="0">&lt;code># 这是不可行的
spelling = &amp;#34;favorite&amp;#34;
&amp;#34;spelling&amp;#34; = &amp;#34;favourite&amp;#34;
&lt;/code>&lt;/pre>&lt;p>只要一个键还没有被直接定义过，你就仍可以对它和它下属的键名赋值。&lt;/p>
&lt;pre tabindex="0">&lt;code># 这使“fruit”键作为表存在。
fruit.apple.smooth = true
# 所以接下来你可以像中这样对“fruit”表添加内容：
fruit.orange = 2
&lt;/code>&lt;/pre>&lt;pre tabindex="0">&lt;code># 以下是非法的
# 这将 fruit.apple 的值定义为一个整数。
fruit.apple = 1
# 但接下来这将 fruit.apple 像表一样对待了。
# 整数不能变成表。
fruit.apple.smooth = true
&lt;/code>&lt;/pre>&lt;p>不鼓励跳跃式地定义点分隔键。&lt;/p>
&lt;div class="highlight">&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;">&lt;code class="language-toml" data-lang="toml">&lt;span style="display:flex;">&lt;span>&lt;span style="color:#75715e"># 合法但不鼓励&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#a6e22e">apple&lt;/span>.&lt;span style="color:#a6e22e">type&lt;/span> = &lt;span style="color:#e6db74">&amp;#34;水果&amp;#34;&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#a6e22e">orange&lt;/span>.&lt;span style="color:#a6e22e">type&lt;/span> = &lt;span style="color:#e6db74">&amp;#34;水果&amp;#34;&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#a6e22e">apple&lt;/span>.&lt;span style="color:#a6e22e">skin&lt;/span> = &lt;span style="color:#e6db74">&amp;#34;薄&amp;#34;&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#a6e22e">orange&lt;/span>.&lt;span style="color:#a6e22e">skin&lt;/span> = &lt;span style="color:#e6db74">&amp;#34;厚&amp;#34;&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#a6e22e">apple&lt;/span>.&lt;span style="color:#a6e22e">color&lt;/span> = &lt;span style="color:#e6db74">&amp;#34;红&amp;#34;&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#a6e22e">orange&lt;/span>.&lt;span style="color:#a6e22e">color&lt;/span> = &lt;span style="color:#e6db74">&amp;#34;橙&amp;#34;&lt;/span>
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>&lt;div class="highlight">&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;">&lt;code class="language-toml" data-lang="toml">&lt;span style="display:flex;">&lt;span>&lt;span style="color:#75715e"># 建议&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#a6e22e">apple&lt;/span>.&lt;span style="color:#a6e22e">type&lt;/span> = &lt;span style="color:#e6db74">&amp;#34;水果&amp;#34;&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#a6e22e">apple&lt;/span>.&lt;span style="color:#a6e22e">skin&lt;/span> = &lt;span style="color:#e6db74">&amp;#34;薄&amp;#34;&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#a6e22e">apple&lt;/span>.&lt;span style="color:#a6e22e">color&lt;/span> = &lt;span style="color:#e6db74">&amp;#34;红&amp;#34;&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#a6e22e">orange&lt;/span>.&lt;span style="color:#a6e22e">type&lt;/span> = &lt;span style="color:#e6db74">&amp;#34;水果&amp;#34;&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#a6e22e">orange&lt;/span>.&lt;span style="color:#a6e22e">skin&lt;/span> = &lt;span style="color:#e6db74">&amp;#34;厚&amp;#34;&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#a6e22e">orange&lt;/span>.&lt;span style="color:#a6e22e">color&lt;/span> = &lt;span style="color:#e6db74">&amp;#34;红&amp;#34;&lt;/span>
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>&lt;p>由于裸键可以仅由 ASCII 整数组成，所以可能写出看起来像浮点数、但实际上是两部分的点分隔键。&lt;br>
除非你有充分的理由（基本不太会），否则不要这样做。&lt;/p>
&lt;div class="highlight">&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;">&lt;code class="language-toml" data-lang="toml">&lt;span style="display:flex;">&lt;span>&lt;span style="color:#ae81ff">3.14159&lt;/span> = &lt;span style="color:#e6db74">&amp;#34;派&amp;#34;&lt;/span>
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>&lt;p>上面的 TOML 对应以下 JSON。&lt;/p>
&lt;div class="highlight">&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;">&lt;code class="language-json" data-lang="json">&lt;span style="display:flex;">&lt;span>{ &lt;span style="color:#f92672">&amp;#34;3&amp;#34;&lt;/span>: { &lt;span style="color:#f92672">&amp;#34;14159&amp;#34;&lt;/span>: &lt;span style="color:#e6db74">&amp;#34;派&amp;#34;&lt;/span> } }
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>&lt;h3 id="字符串">字符串&lt;/h3>
&lt;p>共有四种方式来表示字符串：基本字符串、多行基本字符串、字面量和多行字面量。&lt;br>
所有字符串都只能包含有效的 UTF-8 字符。&lt;/p>
&lt;p>&lt;strong>基本字符串&lt;/strong>由引号（&lt;code>&amp;quot;&lt;/code>）包裹。&lt;br>
任何 Unicode 字符都可以使用，除了那些必须转义的：引号，反斜杠，以及除制表符外的控制字符（U+0000 至 U+0008，U+000A 至 U+001F，U+007F）。&lt;/p>
&lt;div class="highlight">&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;">&lt;code class="language-toml" data-lang="toml">&lt;span style="display:flex;">&lt;span>&lt;span style="color:#a6e22e">str&lt;/span> = &lt;span style="color:#e6db74">&amp;#34;我是一个字符串。\&amp;#34;你可以把我引起来\&amp;#34;。姓名\tJos\u00E9\n位置\t旧金山。&amp;#34;&lt;/span>
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>&lt;p>为了方便，一些流行的字符有其简便转义写法。&lt;/p>
&lt;pre tabindex="0">&lt;code>\b - backspace (U+0008)
\t - tab (U+0009)
\n - linefeed (U+000A)
\f - form feed (U+000C)
\r - carriage return (U+000D)
\&amp;#34; - quote (U+0022)
\\ - backslash (U+005C)
\uXXXX - unicode (U+XXXX)
\UXXXXXXXX - unicode (U+XXXXXXXX)
&lt;/code>&lt;/pre>&lt;p>任何 Unicode 字符都可以用 &lt;code>\uXXXX&lt;/code> 或 &lt;code>\UXXXXXXXX&lt;/code> 的形式来转义。&lt;br>
转义码必须是有效的 Unicode &lt;a href="https://unicode.org/glossary/#unicode_scalar_value">标量值&lt;/a>。&lt;/p>
&lt;p>所有上面未列出的其它转义序列都是保留的；如果用了，TOML 应当产生错误。&lt;/p>
&lt;p>有时你需要表示一小篇文本（例如译文）或者想要对非常长的字符串进行折行。&lt;br>
TOML 对此进行了简化。&lt;/p>
&lt;p>&lt;strong>多行基本字符串&lt;/strong>由三个引号包裹，允许折行。&lt;br>
紧随开头引号的那个换行会被去除。&lt;br>
其它空白和换行会被原样保留。&lt;/p>
&lt;div class="highlight">&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;">&lt;code class="language-toml" data-lang="toml">&lt;span style="display:flex;">&lt;span>&lt;span style="color:#a6e22e">str1&lt;/span> = &lt;span style="color:#e6db74">&amp;#34;&amp;#34;&amp;#34;
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#e6db74">Roses are red
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#e6db74">Violets are blue&amp;#34;&amp;#34;&amp;#34;&lt;/span>
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>&lt;p>TOML 解析器可以相对灵活地解析成对所在平台有效的换行字符。&lt;/p>
&lt;div class="highlight">&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;">&lt;code class="language-toml" data-lang="toml">&lt;span style="display:flex;">&lt;span>&lt;span style="color:#75715e"># 在 Unix 系统，上面的多行字符串可能等同于：&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#a6e22e">str2&lt;/span> = &lt;span style="color:#e6db74">&amp;#34;Roses are red\nViolets are blue&amp;#34;&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#75715e"># 在 Windows 系统，它可能等价于：&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#a6e22e">str3&lt;/span> = &lt;span style="color:#e6db74">&amp;#34;Roses are red\r\nViolets are blue&amp;#34;&lt;/span>
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>&lt;p>想书写长字符串却不想引入无关空白，可以用“行末反斜杠”。&lt;br>
当一行的最后一个非空白字符是未被转义的 &lt;code>\&lt;/code> 时，它会连同它后面的所有空白（包括换行）一起被去除，直到下一个非空白字符或结束引号为止。&lt;br>
所有对基本字符串有效的转义序列，对多行基本字符串也同样适用。&lt;/p>
&lt;div class="highlight">&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;">&lt;code class="language-toml" data-lang="toml">&lt;span style="display:flex;">&lt;span>&lt;span style="color:#75715e"># 下列字符串的每一个字节都完全相同：&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#a6e22e">str1&lt;/span> = &lt;span style="color:#e6db74">&amp;#34;The quick brown fox jumps over the lazy dog.&amp;#34;&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#a6e22e">str2&lt;/span> = &lt;span style="color:#e6db74">&amp;#34;&amp;#34;&amp;#34;
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#e6db74">The quick brown \
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#e6db74">
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#e6db74">
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#e6db74"> fox jumps over \
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#e6db74"> the lazy dog.&amp;#34;&amp;#34;&amp;#34;&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#a6e22e">str3&lt;/span> = &lt;span style="color:#e6db74">&amp;#34;&amp;#34;&amp;#34;\
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#e6db74"> The quick brown \
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#e6db74"> fox jumps over \
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#e6db74"> the lazy dog.\
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#e6db74"> &amp;#34;&amp;#34;&amp;#34;&lt;/span>
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>&lt;p>任何 Unicode 字符都可以使用，除了那些必须被转义的：反斜杠和除制表符、换行符、回车符外的控制字符（U+0000 至 U+0008，U+000B，U+000C，U+000E 至 U+001F，U+007F）。&lt;/p>
&lt;p>你可以在多行基本字符串内的任何地方写一个引号或两个毗连的引号。&lt;br>
它们也可以写在紧邻界分符内的位置。&lt;/p>
&lt;div class="highlight">&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;">&lt;code class="language-toml" data-lang="toml">&lt;span style="display:flex;">&lt;span>&lt;span style="color:#a6e22e">str4&lt;/span> = &lt;span style="color:#e6db74">&amp;#34;&amp;#34;&amp;#34;这有两个引号：&amp;#34;&amp;#34;。够简单。&amp;#34;&amp;#34;&amp;#34;&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#75715e"># str5 = &amp;#34;&amp;#34;&amp;#34;这有两个引号：&amp;#34;&amp;#34;&amp;#34;。&amp;#34;&amp;#34;&amp;#34; # 非法&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#a6e22e">str5&lt;/span> = &lt;span style="color:#e6db74">&amp;#34;&amp;#34;&amp;#34;这有三个引号：&amp;#34;&amp;#34;\&amp;#34;。&amp;#34;&amp;#34;&amp;#34;&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#a6e22e">str6&lt;/span> = &lt;span style="color:#e6db74">&amp;#34;&amp;#34;&amp;#34;这有十五个引号：&amp;#34;&amp;#34;\&amp;#34;&amp;#34;&amp;#34;\&amp;#34;&amp;#34;&amp;#34;\&amp;#34;&amp;#34;&amp;#34;\&amp;#34;&amp;#34;&amp;#34;\&amp;#34;。&amp;#34;&amp;#34;&amp;#34;&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#75715e"># &amp;#34;这，&amp;#34;她说，&amp;#34;只是个无意义的条款。&amp;#34;&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#a6e22e">str7&lt;/span> = &lt;span style="color:#e6db74">&amp;#34;&amp;#34;&amp;#34;&amp;#34;&lt;/span>&lt;span style="color:#960050;background-color:#1e0010">这，&lt;/span>&lt;span style="color:#e6db74">&amp;#34;她说，&amp;#34;&lt;/span>&lt;span style="color:#960050;background-color:#1e0010">只是个无意义的条款。&lt;/span>&lt;span style="color:#e6db74">&amp;#34;&amp;#34;&amp;#34;&amp;#34;&lt;/span>
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>&lt;p>如果你常常要指定 Windows 路径或正则表达式，那么必须转义反斜杠就马上成为啰嗦而易错的了。&lt;br>
为了帮助搞定这点，TOML 支持字面量字符串，它完全不允许转义。&lt;/p>
&lt;p>&lt;strong>字面量字符串&lt;/strong>由单引号包裹。&lt;br>
类似于基本字符串，他们只能表现为单行：&lt;/p>
&lt;div class="highlight">&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;">&lt;code class="language-toml" data-lang="toml">&lt;span style="display:flex;">&lt;span>&lt;span style="color:#75715e"># 所见即所得。&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#a6e22e">winpath&lt;/span> = &lt;span style="color:#e6db74">&amp;#39;C:\Users\nodejs\templates&amp;#39;&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#a6e22e">winpath2&lt;/span> = &lt;span style="color:#e6db74">&amp;#39;\\ServerX\admin$\system32\&amp;#39;
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#e6db74">quoted = &amp;#39;&lt;/span>&lt;span style="color:#a6e22e">Tom&lt;/span> &lt;span style="color:#e6db74">&amp;#34;Dubs&amp;#34;&lt;/span> &lt;span style="color:#a6e22e">Preston-Werner&lt;/span>&lt;span style="color:#e6db74">&amp;#39;
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#e6db74">regex = &amp;#39;&lt;/span>&lt;span style="color:#960050;background-color:#1e0010">&amp;lt;\&lt;/span>&lt;span style="color:#a6e22e">i&lt;/span>&lt;span style="color:#960050;background-color:#1e0010">\&lt;/span>&lt;span style="color:#a6e22e">c&lt;/span>&lt;span style="color:#960050;background-color:#1e0010">*\&lt;/span>&lt;span style="color:#a6e22e">s&lt;/span>&lt;span style="color:#960050;background-color:#1e0010">*&amp;gt;&amp;#39;&lt;/span>
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>&lt;p>由于没有转义，无法在由单引号包裹的字面量字符串中写入单引号。&lt;br>
万幸，TOML 支持一种多行版本的字面量字符串来解决这个问题。&lt;/p>
&lt;p>&lt;strong>多行字面量字符串&lt;/strong>两侧各有三个单引号来包裹，允许换行。&lt;br>
类似于字面量字符串，无论任何转义都不存在。&lt;br>
紧随开始标记的那个换行会被剔除。&lt;br>
开始结束标记之间的所有其它内容会原样对待。&lt;/p>
&lt;div class="highlight">&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;">&lt;code class="language-toml" data-lang="toml">&lt;span style="display:flex;">&lt;span>&lt;span style="color:#a6e22e">regex2&lt;/span> = &lt;span style="color:#e6db74">&amp;#39;&amp;#39;&amp;#39;I [dw]on&amp;#39;&lt;/span>&lt;span style="color:#a6e22e">t&lt;/span> &lt;span style="color:#a6e22e">need&lt;/span> &lt;span style="color:#960050;background-color:#1e0010">\&lt;/span>&lt;span style="color:#a6e22e">d&lt;/span>{&lt;span style="color:#ae81ff">2&lt;/span>} &lt;span style="color:#a6e22e">apples&lt;/span>&lt;span style="color:#e6db74">&amp;#39;&amp;#39;&amp;#39;
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#e6db74">lines = &amp;#39;&amp;#39;&amp;#39;&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#960050;background-color:#1e0010">原始字符串中的&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#960050;background-color:#1e0010">第一个换行被剔除了。&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#960050;background-color:#1e0010">所有其它空白&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#960050;background-color:#1e0010">都保留了。&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#e6db74">&amp;#39;&amp;#39;&lt;/span>&lt;span style="color:#960050;background-color:#1e0010">&amp;#39;&lt;/span>
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>&lt;p>你可以在多行字面量字符串中的任何位置写一个或两个单引号，但三个以上的单引号序列不可以。&lt;/p>
&lt;div class="highlight">&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;">&lt;code class="language-toml" data-lang="toml">&lt;span style="display:flex;">&lt;span>&lt;span style="color:#a6e22e">quot15&lt;/span> = &lt;span style="color:#e6db74">&amp;#39;&amp;#39;&amp;#39;这有十五个引号：&amp;#34;&amp;#34;&amp;#34;&amp;#34;&amp;#34;&amp;#34;&amp;#34;&amp;#34;&amp;#34;&amp;#34;&amp;#34;&amp;#34;&amp;#34;&amp;#34;&amp;#34;&amp;#39;&amp;#39;&amp;#39;&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#75715e"># apos15 = &amp;#39;&amp;#39;&amp;#39;这有十五个撇号：&amp;#39;&amp;#39;&amp;#39;&amp;#39;&amp;#39;&amp;#39;&amp;#39;&amp;#39;&amp;#39;&amp;#39;&amp;#39;&amp;#39;&amp;#39;&amp;#39;&amp;#39;&amp;#39;&amp;#39;&amp;#39; # 非法&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#a6e22e">apos15&lt;/span> = &lt;span style="color:#e6db74">&amp;#34;这有十五个撇号：&amp;#39;&amp;#39;&amp;#39;&amp;#39;&amp;#39;&amp;#39;&amp;#39;&amp;#39;&amp;#39;&amp;#39;&amp;#39;&amp;#39;&amp;#39;&amp;#39;&amp;#39;&amp;#34;&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#75715e"># &amp;#39;那，&amp;#39;她说，&amp;#39;仍然没有意义。&amp;#39;&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#a6e22e">str&lt;/span> = &lt;span style="color:#e6db74">&amp;#39;&amp;#39;&amp;#39;&amp;#39;&lt;/span>&lt;span style="color:#960050;background-color:#1e0010">那，&lt;/span>&lt;span style="color:#e6db74">&amp;#39;她说，&amp;#39;&lt;/span>&lt;span style="color:#960050;background-color:#1e0010">仍然没有意义。&lt;/span>&lt;span style="color:#e6db74">&amp;#39;&amp;#39;&amp;#39;&amp;#39;&lt;/span>
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>&lt;p>除制表符以外的所有控制字符都不允许出现在字面量字符串中。&lt;br>
因此，对于二进制数据，建议你使用 Base64 或其它合适的 ASCII 或 UTF-8 编码。&lt;br>
对那些编码的处理方式，将交由应用程序自己来确定。&lt;/p>
&lt;h3 id="整数">整数&lt;/h3>
&lt;p>整数是纯数字。&lt;br>
正数可以有加号前缀。&lt;br>
负数的前缀是减号。&lt;/p>
&lt;div class="highlight">&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;">&lt;code class="language-toml" data-lang="toml">&lt;span style="display:flex;">&lt;span>&lt;span style="color:#a6e22e">int1&lt;/span> = &lt;span style="color:#ae81ff">+99&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#a6e22e">int2&lt;/span> = &lt;span style="color:#ae81ff">42&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#a6e22e">int3&lt;/span> = &lt;span style="color:#ae81ff">0&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#a6e22e">int4&lt;/span> = &lt;span style="color:#ae81ff">-17&lt;/span>
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>&lt;p>对于大数，你可以在数字之间用下划线来增强可读性。&lt;br>
每个下划线两侧必须至少有一个数字。&lt;/p>
&lt;div class="highlight">&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;">&lt;code class="language-toml" data-lang="toml">&lt;span style="display:flex;">&lt;span>&lt;span style="color:#a6e22e">int5&lt;/span> = &lt;span style="color:#ae81ff">1_000&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#a6e22e">int6&lt;/span> = &lt;span style="color:#ae81ff">5_349_221&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#a6e22e">int7&lt;/span> = &lt;span style="color:#ae81ff">53_49_221&lt;/span> &lt;span style="color:#75715e"># 印度记数体系分组&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#a6e22e">int8&lt;/span> = &lt;span style="color:#ae81ff">1_2_3_4_5&lt;/span> &lt;span style="color:#75715e"># 合法但不鼓励&lt;/span>
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>&lt;p>前导零是不允许的。&lt;br>
整数值 &lt;code>-0&lt;/code> 与 &lt;code>+0&lt;/code> 是有效的，并等同于无前缀的零。&lt;/p>
&lt;p>非负整数值也可以用十六进制、八进制或二进制来表示。&lt;br>
在这些格式中，&lt;code>+&lt;/code> 不被允许，而（前缀后的）前导零是允许的。&lt;br>
十六进制值大小写不敏感。&lt;br>
数字间的下划线是允许的（但不能存在于前缀和值之间）。&lt;/p>
&lt;div class="highlight">&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;">&lt;code class="language-toml" data-lang="toml">&lt;span style="display:flex;">&lt;span>&lt;span style="color:#75715e"># 带有 `0x` 前缀的十六进制&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#a6e22e">hex1&lt;/span> = &lt;span style="color:#ae81ff">0&lt;/span>&lt;span style="color:#a6e22e">xDEADBEEF&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#a6e22e">hex2&lt;/span> = &lt;span style="color:#ae81ff">0&lt;/span>&lt;span style="color:#a6e22e">xdeadbeef&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#a6e22e">hex3&lt;/span> = &lt;span style="color:#ae81ff">0&lt;/span>&lt;span style="color:#a6e22e">xdead_beef&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#75715e"># 带有 `0o` 前缀的八进制&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#a6e22e">oct1&lt;/span> = &lt;span style="color:#ae81ff">0&lt;/span>&lt;span style="color:#a6e22e">o01234567&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#a6e22e">oct2&lt;/span> = &lt;span style="color:#ae81ff">0&lt;/span>&lt;span style="color:#a6e22e">o755&lt;/span> &lt;span style="color:#75715e"># 对于表示 Unix 文件权限很有用&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#75715e"># 带有 `0b` 前缀的二进制&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#a6e22e">bin1&lt;/span> = &lt;span style="color:#ae81ff">0&lt;/span>&lt;span style="color:#a6e22e">b11010110&lt;/span>
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>&lt;p>任何 64 位有符号整数（从 −2^63 到 2^63−1）都应当被接受并无损处理。&lt;br>
如果无法无损表现某个整数，则必须抛出错误。&lt;/p>
&lt;h3 id="浮点数">浮点数&lt;/h3>
&lt;p>浮点数应当被实现为 IEEE 754 binary64 值。&lt;/p>
&lt;p>一个浮点数由一个整数部分（遵从与十进制整数值相同的规则）后跟上一个小数部分和/或一个指数部分组成。&lt;br>
如果小数部分和指数部分兼有，那小数部分必须在指数部分前面。&lt;/p>
&lt;div class="highlight">&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;">&lt;code class="language-toml" data-lang="toml">&lt;span style="display:flex;">&lt;span>&lt;span style="color:#75715e"># 小数&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#a6e22e">flt1&lt;/span> = &lt;span style="color:#ae81ff">+1.0&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#a6e22e">flt2&lt;/span> = &lt;span style="color:#ae81ff">3.1415&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#a6e22e">flt3&lt;/span> = &lt;span style="color:#ae81ff">-0.01&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#75715e"># 指数&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#a6e22e">flt4&lt;/span> = &lt;span style="color:#ae81ff">5&lt;/span>&lt;span style="color:#a6e22e">e&lt;/span>&lt;span style="color:#ae81ff">+22&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#a6e22e">flt5&lt;/span> = &lt;span style="color:#ae81ff">1&lt;/span>&lt;span style="color:#a6e22e">e06&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#a6e22e">flt6&lt;/span> = &lt;span style="color:#ae81ff">-2&lt;/span>&lt;span style="color:#a6e22e">E-2&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#75715e"># 都有&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#a6e22e">flt7&lt;/span> = &lt;span style="color:#ae81ff">6.626&lt;/span>&lt;span style="color:#a6e22e">e-34&lt;/span>
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>&lt;p>小数部分是一个小数点后跟一个或多个数字。&lt;/p>
&lt;p>一个指数部分是一个 E（大小写均可）后跟一个整数部分（遵从与十进制整数值相同的规则，但可以包含前导零）。&lt;/p>
&lt;p>小数点，如果有用到的话，每侧必须紧邻至少一个数字。&lt;/p>
&lt;pre tabindex="0">&lt;code># 非法的浮点数
invalid_float_1 = .7
invalid_float_2 = 7.
invalid_float_3 = 3.e+20
&lt;/code>&lt;/pre>&lt;p>与整数相似，你可以使用下划线来增强可读性。&lt;br>
每个下划线必须被至少一个数字围绕。&lt;/p>
&lt;div class="highlight">&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;">&lt;code class="language-toml" data-lang="toml">&lt;span style="display:flex;">&lt;span>&lt;span style="color:#a6e22e">flt8&lt;/span> = &lt;span style="color:#ae81ff">224_617.445&lt;/span>&lt;span style="color:#a6e22e">_991_228&lt;/span>
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>&lt;p>浮点数值 &lt;code>-0.0&lt;/code> 与 &lt;code>+0.0&lt;/code> 是有效的，并且应当遵从 IEEE 754。&lt;/p>
&lt;p>特殊浮点值也能够表示。&lt;br>
它们是小写的。&lt;/p>
&lt;div class="highlight">&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;">&lt;code class="language-toml" data-lang="toml">&lt;span style="display:flex;">&lt;span>&lt;span style="color:#75715e"># 无穷&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#a6e22e">sf1&lt;/span> = &lt;span style="color:#a6e22e">inf&lt;/span> &lt;span style="color:#75715e"># 正无穷&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#a6e22e">sf2&lt;/span> = &lt;span style="color:#960050;background-color:#1e0010">+&lt;/span>&lt;span style="color:#a6e22e">inf&lt;/span> &lt;span style="color:#75715e"># 正无穷&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#a6e22e">sf3&lt;/span> = &lt;span style="color:#a6e22e">-inf&lt;/span> &lt;span style="color:#75715e"># 负无穷&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#75715e"># 非数&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#a6e22e">sf4&lt;/span> = &lt;span style="color:#a6e22e">nan&lt;/span> &lt;span style="color:#75715e"># 实际上对应信号非数码还是静默非数码，取决于实现&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#a6e22e">sf5&lt;/span> = &lt;span style="color:#960050;background-color:#1e0010">+&lt;/span>&lt;span style="color:#a6e22e">nan&lt;/span> &lt;span style="color:#75715e"># 等同于 `nan`&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#a6e22e">sf6&lt;/span> = &lt;span style="color:#a6e22e">-nan&lt;/span> &lt;span style="color:#75715e"># 有效，实际码取决于实现&lt;/span>
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>&lt;h3 id="布尔值">布尔值&lt;/h3>
&lt;p>布尔值就是你所惯用的那样。&lt;br>
要小写。&lt;/p>
&lt;div class="highlight">&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;">&lt;code class="language-toml" data-lang="toml">&lt;span style="display:flex;">&lt;span>&lt;span style="color:#a6e22e">bool1&lt;/span> = &lt;span style="color:#66d9ef">true&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#a6e22e">bool2&lt;/span> = &lt;span style="color:#66d9ef">false&lt;/span>
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>&lt;h3 id="坐标日期时刻">坐标日期时刻&lt;/h3>
&lt;p>要准确地表示世上的一个特定时间，你可以使用指定了时区偏移量的 &lt;a href="https://tools.ietf.org/html/rfc3339">RFC 3339&lt;/a> 格式的日期时刻。&lt;/p>
&lt;div class="highlight">&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;">&lt;code class="language-toml" data-lang="toml">&lt;span style="display:flex;">&lt;span>&lt;span style="color:#a6e22e">odt1&lt;/span> = &lt;span style="color:#e6db74">1979-05-27T07:32:00Z&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#a6e22e">odt2&lt;/span> = &lt;span style="color:#e6db74">1979-05-27T00:32:00-07:00&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#a6e22e">odt3&lt;/span> = &lt;span style="color:#ae81ff">1979-05-27&lt;/span>&lt;span style="color:#a6e22e">T00&lt;/span>&lt;span style="color:#960050;background-color:#1e0010">:&lt;/span>&lt;span style="color:#ae81ff">32&lt;/span>&lt;span style="color:#960050;background-color:#1e0010">:&lt;/span>&lt;span style="color:#ae81ff">00.999999&lt;/span>&lt;span style="color:#ae81ff">-07&lt;/span>&lt;span style="color:#960050;background-color:#1e0010">:&lt;/span>&lt;span style="color:#ae81ff">00&lt;/span>
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>&lt;p>出于可读性的目的，你可以用一个空格字符替代日期和时刻之间的 T（RFC 3339 的第 5.6 节中允许了这样做）。&lt;/p>
&lt;div class="highlight">&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;">&lt;code class="language-toml" data-lang="toml">&lt;span style="display:flex;">&lt;span>&lt;span style="color:#a6e22e">odt4&lt;/span> = &lt;span style="color:#ae81ff">1979-05-27&lt;/span> &lt;span style="color:#ae81ff">07&lt;/span>&lt;span style="color:#960050;background-color:#1e0010">:&lt;/span>&lt;span style="color:#ae81ff">32&lt;/span>&lt;span style="color:#960050;background-color:#1e0010">:&lt;/span>&lt;span style="color:#ae81ff">00&lt;/span>&lt;span style="color:#a6e22e">Z&lt;/span>
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>&lt;p>毫秒级的精度是必须的。&lt;br>
更高精度的小数秒取决于实现。&lt;br>
如果它的值超出了实现所支持的精度，那超出的部分必须被舍弃，而不能四舍五入。&lt;/p>
&lt;h3 id="各地日期时刻">各地日期时刻&lt;/h3>
&lt;p>如果你省略了 &lt;a href="https://tools.ietf.org/html/rfc3339">RFC 3339&lt;/a> 日期时刻中的时区偏移量，这表示该日期时刻的使用并不涉及时区偏移。&lt;br>
在没有其它信息的情况下，并不知道它究竟该被转化成世上的哪一刻。&lt;br>
如果仍被要求转化，那结果将取决于实现。&lt;/p>
&lt;div class="highlight">&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;">&lt;code class="language-toml" data-lang="toml">&lt;span style="display:flex;">&lt;span>&lt;span style="color:#a6e22e">ldt1&lt;/span> = &lt;span style="color:#ae81ff">1979-05-27&lt;/span>&lt;span style="color:#a6e22e">T07&lt;/span>&lt;span style="color:#960050;background-color:#1e0010">:&lt;/span>&lt;span style="color:#ae81ff">32&lt;/span>&lt;span style="color:#960050;background-color:#1e0010">:&lt;/span>&lt;span style="color:#ae81ff">00&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#a6e22e">ldt2&lt;/span> = &lt;span style="color:#ae81ff">1979-05-27&lt;/span>&lt;span style="color:#a6e22e">T00&lt;/span>&lt;span style="color:#960050;background-color:#1e0010">:&lt;/span>&lt;span style="color:#ae81ff">32&lt;/span>&lt;span style="color:#960050;background-color:#1e0010">:&lt;/span>&lt;span style="color:#ae81ff">00.999999&lt;/span>
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>&lt;p>毫秒级的精度是必须的。&lt;br>
更高精度的小数秒取决于实现。&lt;br>
如果它的值超出了实现所支持的精度，那多余的部分必须被舍弃，而不能四舍五入。&lt;/p>
&lt;h3 id="各地日期">各地日期&lt;/h3>
&lt;p>如果你只写了 &lt;a href="https://tools.ietf.org/html/rfc3339">RFC 3339&lt;/a> 日期时刻中的日期部分，那它表示一整天，同时也不涉及时区偏移。&lt;/p>
&lt;div class="highlight">&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;">&lt;code class="language-toml" data-lang="toml">&lt;span style="display:flex;">&lt;span>&lt;span style="color:#a6e22e">ld1&lt;/span> = &lt;span style="color:#ae81ff">1979-05-27&lt;/span>
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>&lt;h3 id="各地时刻">各地时刻&lt;/h3>
&lt;p>如果你只写了 &lt;a href="https://tools.ietf.org/html/rfc3339">RFC 3339&lt;/a> 日期时刻中的时刻部分，它将只表示一天之中的那个时刻，而与任何特定的日期无关、亦不涉及时区偏移。&lt;/p>
&lt;div class="highlight">&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;">&lt;code class="language-toml" data-lang="toml">&lt;span style="display:flex;">&lt;span>&lt;span style="color:#a6e22e">lt1&lt;/span> = &lt;span style="color:#ae81ff">07&lt;/span>&lt;span style="color:#960050;background-color:#1e0010">:&lt;/span>&lt;span style="color:#ae81ff">32&lt;/span>&lt;span style="color:#960050;background-color:#1e0010">:&lt;/span>&lt;span style="color:#ae81ff">00&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#a6e22e">lt2&lt;/span> = &lt;span style="color:#ae81ff">00&lt;/span>&lt;span style="color:#960050;background-color:#1e0010">:&lt;/span>&lt;span style="color:#ae81ff">32&lt;/span>&lt;span style="color:#960050;background-color:#1e0010">:&lt;/span>&lt;span style="color:#ae81ff">00.999999&lt;/span>
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>&lt;p>毫秒级的精度是必须的。&lt;br>
更高精度的小数秒取决于实现。&lt;br>
如果它的值超出了实现所支持的精度，那多余的部分必须被舍弃，而不能四舍五入。&lt;/p>
&lt;h3 id="数组">数组&lt;/h3>
&lt;p>数组是内含值的方括号。&lt;br>
空白会被忽略。&lt;br>
子元素由逗号分隔。&lt;br>
数组可以包含与键值对所允许的相同数据类型的值。&lt;br>
可以混合不同类型的值。&lt;/p>
&lt;div class="highlight">&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;">&lt;code class="language-toml" data-lang="toml">&lt;span style="display:flex;">&lt;span>&lt;span style="color:#a6e22e">integers&lt;/span> = [ &lt;span style="color:#ae81ff">1&lt;/span>, &lt;span style="color:#ae81ff">2&lt;/span>, &lt;span style="color:#ae81ff">3&lt;/span> ]
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#a6e22e">colors&lt;/span> = [ &lt;span style="color:#e6db74">&amp;#34;红&amp;#34;&lt;/span>, &lt;span style="color:#e6db74">&amp;#34;黄&amp;#34;&lt;/span>, &lt;span style="color:#e6db74">&amp;#34;绿&amp;#34;&lt;/span> ]
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#a6e22e">nested_array_of_ints&lt;/span> = [ [ &lt;span style="color:#ae81ff">1&lt;/span>, &lt;span style="color:#ae81ff">2&lt;/span> ], [&lt;span style="color:#ae81ff">3&lt;/span>, &lt;span style="color:#ae81ff">4&lt;/span>, &lt;span style="color:#ae81ff">5&lt;/span>] ]
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#a6e22e">nested_mixed_array&lt;/span> = [ [ &lt;span style="color:#ae81ff">1&lt;/span>, &lt;span style="color:#ae81ff">2&lt;/span> ], [&lt;span style="color:#e6db74">&amp;#34;a&amp;#34;&lt;/span>, &lt;span style="color:#e6db74">&amp;#34;b&amp;#34;&lt;/span>, &lt;span style="color:#e6db74">&amp;#34;c&amp;#34;&lt;/span>] ]
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#a6e22e">string_array&lt;/span> = [ &lt;span style="color:#e6db74">&amp;#34;所有的&amp;#34;&lt;/span>, &lt;span style="color:#e6db74">&amp;#39;字符串&amp;#39;&lt;/span>, &lt;span style="color:#e6db74">&amp;#34;&amp;#34;&amp;#34;是相同的&amp;#34;&amp;#34;&amp;#34;&lt;/span>, &lt;span style="color:#e6db74">&amp;#39;&amp;#39;&amp;#39;类型&amp;#39;&amp;#39;&amp;#39;&lt;/span> ]
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#75715e"># 允许混合类型的数组&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#a6e22e">numbers&lt;/span> = [ &lt;span style="color:#ae81ff">0.1&lt;/span>, &lt;span style="color:#ae81ff">0.2&lt;/span>, &lt;span style="color:#ae81ff">0.5&lt;/span>, &lt;span style="color:#ae81ff">1&lt;/span>, &lt;span style="color:#ae81ff">2&lt;/span>, &lt;span style="color:#ae81ff">5&lt;/span> ]
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#a6e22e">contributors&lt;/span> = [
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#e6db74">&amp;#34;Foo Bar &amp;lt;foo@example.com&amp;gt;&amp;#34;&lt;/span>,
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> { &lt;span style="color:#a6e22e">name&lt;/span> = &lt;span style="color:#e6db74">&amp;#34;Baz Qux&amp;#34;&lt;/span>, &lt;span style="color:#a6e22e">email&lt;/span> = &lt;span style="color:#e6db74">&amp;#34;bazqux@example.com&amp;#34;&lt;/span>, &lt;span style="color:#a6e22e">url&lt;/span> = &lt;span style="color:#e6db74">&amp;#34;https://example.com/bazqux&amp;#34;&lt;/span> }
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>]
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>&lt;p>数组可以跨行。&lt;br>
数组的最后一个值后面可以有终逗号（也称为尾逗号）。&lt;br>
值、逗号、结束括号前可以存在任意数量的换行和注释。&lt;br>
数组值和逗号之间的缩进被作为空白对待而被忽略。&lt;/p>
&lt;div class="highlight">&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;">&lt;code class="language-toml" data-lang="toml">&lt;span style="display:flex;">&lt;span>&lt;span style="color:#a6e22e">integers2&lt;/span> = [
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#ae81ff">1&lt;/span>, &lt;span style="color:#ae81ff">2&lt;/span>, &lt;span style="color:#ae81ff">3&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>]
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#a6e22e">integers3&lt;/span> = [
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#ae81ff">1&lt;/span>,
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#ae81ff">2&lt;/span>, &lt;span style="color:#75715e"># 这是可以的&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>]
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>&lt;h3 id="表">表&lt;/h3>
&lt;p>表（也被称为哈希表或字典）是键值对的集合。&lt;br>
它们由表头定义，连同方括号作为单独的行出现。&lt;br>
看得出表头不同于数组，因为数组只有值。&lt;/p>
&lt;div class="highlight">&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;">&lt;code class="language-toml" data-lang="toml">&lt;span style="display:flex;">&lt;span>[&lt;span style="color:#a6e22e">table&lt;/span>]
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>&lt;p>在它下方，直至下一个表头或文件结束，都是这个表的键值对。&lt;br>
表不保证保持键值对的指定顺序。&lt;/p>
&lt;div class="highlight">&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;">&lt;code class="language-toml" data-lang="toml">&lt;span style="display:flex;">&lt;span>[&lt;span style="color:#a6e22e">table-1&lt;/span>]
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#a6e22e">key1&lt;/span> = &lt;span style="color:#e6db74">&amp;#34;some string&amp;#34;&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#a6e22e">key2&lt;/span> = &lt;span style="color:#ae81ff">123&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>[&lt;span style="color:#a6e22e">table-2&lt;/span>]
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#a6e22e">key1&lt;/span> = &lt;span style="color:#e6db74">&amp;#34;another string&amp;#34;&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#a6e22e">key2&lt;/span> = &lt;span style="color:#ae81ff">456&lt;/span>
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>&lt;p>表名的规则与键名相同（见前文&lt;a href="#%E9%94%AE%E5%90%8D">键名&lt;/a>定义）。&lt;/p>
&lt;div class="highlight">&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;">&lt;code class="language-toml" data-lang="toml">&lt;span style="display:flex;">&lt;span>[&lt;span style="color:#a6e22e">dog&lt;/span>.&lt;span style="color:#e6db74">&amp;#34;tater.man&amp;#34;&lt;/span>]
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#a6e22e">type&lt;/span>.&lt;span style="color:#a6e22e">name&lt;/span> = &lt;span style="color:#e6db74">&amp;#34;pug&amp;#34;&lt;/span>
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>&lt;p>等价于 JSON 的如下结构：&lt;/p>
&lt;div class="highlight">&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;">&lt;code class="language-json" data-lang="json">&lt;span style="display:flex;">&lt;span>{ &lt;span style="color:#f92672">&amp;#34;dog&amp;#34;&lt;/span>: { &lt;span style="color:#f92672">&amp;#34;tater.man&amp;#34;&lt;/span>: { &lt;span style="color:#f92672">&amp;#34;type&amp;#34;&lt;/span>: { &lt;span style="color:#f92672">&amp;#34;name&amp;#34;&lt;/span>: &lt;span style="color:#e6db74">&amp;#34;pug&amp;#34;&lt;/span> } } } }
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>&lt;p>键名周围的空格会被忽略。&lt;br>
然而，最佳实践还是不要有任何多余的空白。&lt;/p>
&lt;div class="highlight">&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;">&lt;code class="language-toml" data-lang="toml">&lt;span style="display:flex;">&lt;span>[&lt;span style="color:#a6e22e">a&lt;/span>.&lt;span style="color:#a6e22e">b&lt;/span>.&lt;span style="color:#a6e22e">c&lt;/span>] &lt;span style="color:#75715e"># 这是最佳实践&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>[ &lt;span style="color:#a6e22e">d&lt;/span>.&lt;span style="color:#a6e22e">e&lt;/span>.&lt;span style="color:#a6e22e">f&lt;/span> ] &lt;span style="color:#75715e"># 等同于 [d.e.f]&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>[ &lt;span style="color:#a6e22e">g&lt;/span> . &lt;span style="color:#a6e22e">h&lt;/span> . &lt;span style="color:#a6e22e">i&lt;/span> ] &lt;span style="color:#75715e"># 等同于 [g.h.i]&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>[ &lt;span style="color:#a6e22e">j&lt;/span> . &lt;span style="color:#e6db74">&amp;#34;ʞ&amp;#34;&lt;/span> . &lt;span style="color:#e6db74">&amp;#39;l&amp;#39;&lt;/span> ] &lt;span style="color:#75715e"># 等同于 [j.&amp;#34;ʞ&amp;#34;.&amp;#39;l&amp;#39;]&lt;/span>
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>&lt;p>缩进被作为空白对待而被忽略。&lt;/p>
&lt;p>你不必层层完整地写出你不想写的所有途径的父表。&lt;br>
TOML 知道该怎么办。&lt;/p>
&lt;div class="highlight">&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;">&lt;code class="language-toml" data-lang="toml">&lt;span style="display:flex;">&lt;span>&lt;span style="color:#75715e"># [x] 你&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#75715e"># [x.y] 不&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#75715e"># [x.y.z] 需要这些&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>[&lt;span style="color:#a6e22e">x&lt;/span>.&lt;span style="color:#a6e22e">y&lt;/span>.&lt;span style="color:#a6e22e">z&lt;/span>.&lt;span style="color:#a6e22e">w&lt;/span>] &lt;span style="color:#75715e"># 来让这生效&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>[&lt;span style="color:#a6e22e">x&lt;/span>] &lt;span style="color:#75715e"># 后置父表定义是可以的&lt;/span>
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>&lt;p>空表是允许的，只要里面没有键值对就行了。&lt;/p>
&lt;p>类似于键名，你不能重复定义一个表。&lt;br>
这样做是非法的。&lt;/p>
&lt;pre tabindex="0">&lt;code># 不要这样做
[fruit]
apple = &amp;#34;红&amp;#34;
[fruit]
orange = &amp;#34;橙&amp;#34;
&lt;/code>&lt;/pre>&lt;pre tabindex="0">&lt;code># 也不要这样做
[fruit]
apple = &amp;#34;红&amp;#34;
[fruit.apple]
texture = &amp;#34;光滑&amp;#34;
&lt;/code>&lt;/pre>&lt;p>不鼓励无序地定义表。&lt;/p>
&lt;div class="highlight">&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;">&lt;code class="language-toml" data-lang="toml">&lt;span style="display:flex;">&lt;span>&lt;span style="color:#75715e"># 有效但不鼓励&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>[&lt;span style="color:#a6e22e">fruit&lt;/span>.&lt;span style="color:#a6e22e">apple&lt;/span>]
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>[&lt;span style="color:#a6e22e">animal&lt;/span>]
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>[&lt;span style="color:#a6e22e">fruit&lt;/span>.&lt;span style="color:#a6e22e">orange&lt;/span>]
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>&lt;div class="highlight">&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;">&lt;code class="language-toml" data-lang="toml">&lt;span style="display:flex;">&lt;span>&lt;span style="color:#75715e"># 推荐&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>[&lt;span style="color:#a6e22e">fruit&lt;/span>.&lt;span style="color:#a6e22e">apple&lt;/span>]
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>[&lt;span style="color:#a6e22e">fruit&lt;/span>.&lt;span style="color:#a6e22e">orange&lt;/span>]
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>[&lt;span style="color:#a6e22e">animal&lt;/span>]
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>&lt;p>顶层表，又被称为根表，于文档开始处开始并在第一个表头（或文件结束处）前结束。&lt;br>
不同于其它表，它没有名字且无法后置。&lt;/p>
&lt;div class="highlight">&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;">&lt;code class="language-toml" data-lang="toml">&lt;span style="display:flex;">&lt;span>&lt;span style="color:#75715e"># 顶层表开始。&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#a6e22e">name&lt;/span> = &lt;span style="color:#e6db74">&amp;#34;Fido&amp;#34;&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#a6e22e">breed&lt;/span> = &lt;span style="color:#e6db74">&amp;#34;pug&amp;#34;&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#75715e"># 顶层表结束。&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>[&lt;span style="color:#a6e22e">owner&lt;/span>]
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#a6e22e">name&lt;/span> = &lt;span style="color:#e6db74">&amp;#34;Regina Dogman&amp;#34;&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#a6e22e">member_since&lt;/span> = &lt;span style="color:#ae81ff">1999-08-04&lt;/span>
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>&lt;p>点分隔键为最后一个键名前的每个键名创建并定义一个表，倘若这些表尚未被创建的话。&lt;/p>
&lt;div class="highlight">&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;">&lt;code class="language-toml" data-lang="toml">&lt;span style="display:flex;">&lt;span>&lt;span style="color:#a6e22e">fruit&lt;/span>.&lt;span style="color:#a6e22e">apple&lt;/span>.&lt;span style="color:#a6e22e">color&lt;/span> = &lt;span style="color:#e6db74">&amp;#34;red&amp;#34;&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#75715e"># 定义一个名为 fruit 的表&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#75715e"># 定义一个名为 fruit.apple 的表&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#a6e22e">fruit&lt;/span>.&lt;span style="color:#a6e22e">apple&lt;/span>.&lt;span style="color:#a6e22e">taste&lt;/span>.&lt;span style="color:#a6e22e">sweet&lt;/span> = &lt;span style="color:#66d9ef">true&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#75715e"># 定义一个名为 fruit.apple.taste 的表&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#75715e"># fruit 和 fruit.apple 已经创建过了&lt;/span>
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>&lt;p>由于表不能定义多于一次，不允许使用 &lt;code>[table]&lt;/code> 头重定义这样的表。&lt;br>
同样地，使用点分隔键来重定义已经以 &lt;code>[table]&lt;/code> 形式定义过的表也是不允许的。&lt;br>
不过，&lt;code>[table]&lt;/code> 形式可以被用来定义通过点分隔键定义的表中的子表。&lt;/p>
&lt;div class="highlight">&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;">&lt;code class="language-toml" data-lang="toml">&lt;span style="display:flex;">&lt;span>[&lt;span style="color:#a6e22e">fruit&lt;/span>]
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#a6e22e">apple&lt;/span>.&lt;span style="color:#a6e22e">color&lt;/span> = &lt;span style="color:#e6db74">&amp;#34;红&amp;#34;&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#a6e22e">apple&lt;/span>.&lt;span style="color:#a6e22e">taste&lt;/span>.&lt;span style="color:#a6e22e">sweet&lt;/span> = &lt;span style="color:#66d9ef">true&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#75715e"># [fruit.apple] # 非法&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#75715e"># [fruit.apple.taste] # 非法&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>[&lt;span style="color:#a6e22e">fruit&lt;/span>.&lt;span style="color:#a6e22e">apple&lt;/span>.&lt;span style="color:#a6e22e">texture&lt;/span>] &lt;span style="color:#75715e"># 你可以添加子表&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#a6e22e">smooth&lt;/span> = &lt;span style="color:#66d9ef">true&lt;/span>
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>&lt;h3 id="内联表">内联表&lt;/h3>
&lt;p>内联表提供了一种更为紧凑的语法来表示表。&lt;br>
对于否则就很啰嗦的成组数据，这尤其有用。&lt;br>
内联表被完整地定义在花括号之中：&lt;code>{&lt;/code> 和 &lt;code>}&lt;/code>。&lt;br>
括号中，可以出现零或更多个以逗号分隔的键值对。&lt;br>
键值对采取与标准表中的键值对相同的形式。&lt;br>
什么类型的值都可以，包括内联表。&lt;/p>
&lt;p>内联表得出现在同一行内。&lt;br>
内联表中，最后一对键值对后不允许终逗号（也称为尾逗号）。&lt;br>
不允许花括号中出现任何换行，除非在值中它们合法。&lt;br>
即便如此，也强烈不建议把一个内联表搞成纵跨多行的样子。&lt;br>
如果你发现自己真的需要，那意味着你应该使用标准表。&lt;/p>
&lt;div class="highlight">&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;">&lt;code class="language-toml" data-lang="toml">&lt;span style="display:flex;">&lt;span>&lt;span style="color:#a6e22e">name&lt;/span> = { &lt;span style="color:#a6e22e">first&lt;/span> = &lt;span style="color:#e6db74">&amp;#34;Tom&amp;#34;&lt;/span>, &lt;span style="color:#a6e22e">last&lt;/span> = &lt;span style="color:#e6db74">&amp;#34;Preston-Werner&amp;#34;&lt;/span> }
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#a6e22e">point&lt;/span> = { &lt;span style="color:#a6e22e">x&lt;/span> = &lt;span style="color:#ae81ff">1&lt;/span>, &lt;span style="color:#a6e22e">y&lt;/span> = &lt;span style="color:#ae81ff">2&lt;/span> }
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#a6e22e">animal&lt;/span> = { &lt;span style="color:#a6e22e">type&lt;/span>.&lt;span style="color:#a6e22e">name&lt;/span> = &lt;span style="color:#e6db74">&amp;#34;pug&amp;#34;&lt;/span> }
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>&lt;p>上述内联表等同于下面的标准表定义：&lt;/p>
&lt;div class="highlight">&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;">&lt;code class="language-toml" data-lang="toml">&lt;span style="display:flex;">&lt;span>[&lt;span style="color:#a6e22e">name&lt;/span>]
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#a6e22e">first&lt;/span> = &lt;span style="color:#e6db74">&amp;#34;Tom&amp;#34;&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#a6e22e">last&lt;/span> = &lt;span style="color:#e6db74">&amp;#34;Preston-Werner&amp;#34;&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>[&lt;span style="color:#a6e22e">point&lt;/span>]
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#a6e22e">x&lt;/span> = &lt;span style="color:#ae81ff">1&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#a6e22e">y&lt;/span> = &lt;span style="color:#ae81ff">2&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>[&lt;span style="color:#a6e22e">animal&lt;/span>]
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#a6e22e">type&lt;/span>.&lt;span style="color:#a6e22e">name&lt;/span> = &lt;span style="color:#e6db74">&amp;#34;pug&amp;#34;&lt;/span>
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>&lt;p>内联表是独立自足的，在内部定义全部的键与子表。&lt;br>
不能在括号以外的地方，再添加键与子表。&lt;/p>
&lt;div class="highlight">&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;">&lt;code class="language-toml" data-lang="toml">&lt;span style="display:flex;">&lt;span>[&lt;span style="color:#a6e22e">product&lt;/span>]
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#a6e22e">type&lt;/span> = { &lt;span style="color:#a6e22e">name&lt;/span> = &lt;span style="color:#e6db74">&amp;#34;Nail&amp;#34;&lt;/span> }
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#75715e"># type.edible = false # 非法&lt;/span>
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>&lt;p>类似地，内联表不能被用于向一个已定义的表添加键或子表。&lt;/p>
&lt;div class="highlight">&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;">&lt;code class="language-toml" data-lang="toml">&lt;span style="display:flex;">&lt;span>[&lt;span style="color:#a6e22e">product&lt;/span>]
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#a6e22e">type&lt;/span>.&lt;span style="color:#a6e22e">name&lt;/span> = &lt;span style="color:#e6db74">&amp;#34;Nail&amp;#34;&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#75715e"># type = { edible = false } # 非法&lt;/span>
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>&lt;h3 id="表数组">表数组&lt;/h3>
&lt;p>最后一个还没讲到的语法允许你写表数组。&lt;br>
这可以通过把表名写在双方括号里的表头来表示。&lt;br>
表头的第一例定义了这个数组及其首个表元素，而后续的每个则在该数组中创建并定义一个新的表元素。&lt;br>
这些表按出现顺序插入该数组。&lt;/p>
&lt;div class="highlight">&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;">&lt;code class="language-toml" data-lang="toml">&lt;span style="display:flex;">&lt;span>[[&lt;span style="color:#a6e22e">products&lt;/span>]]
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#a6e22e">name&lt;/span> = &lt;span style="color:#e6db74">&amp;#34;Hammer&amp;#34;&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#a6e22e">sku&lt;/span> = &lt;span style="color:#ae81ff">738594937&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>[[&lt;span style="color:#a6e22e">products&lt;/span>]] &lt;span style="color:#75715e"># 数组里的空表&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>[[&lt;span style="color:#a6e22e">products&lt;/span>]]
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#a6e22e">name&lt;/span> = &lt;span style="color:#e6db74">&amp;#34;Nail&amp;#34;&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#a6e22e">sku&lt;/span> = &lt;span style="color:#ae81ff">284758393&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#a6e22e">color&lt;/span> = &lt;span style="color:#e6db74">&amp;#34;gray&amp;#34;&lt;/span>
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>&lt;p>等价于 JSON 的如下结构。&lt;/p>
&lt;div class="highlight">&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;">&lt;code class="language-json" data-lang="json">&lt;span style="display:flex;">&lt;span>{
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#f92672">&amp;#34;products&amp;#34;&lt;/span>: [
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> { &lt;span style="color:#f92672">&amp;#34;name&amp;#34;&lt;/span>: &lt;span style="color:#e6db74">&amp;#34;Hammer&amp;#34;&lt;/span>, &lt;span style="color:#f92672">&amp;#34;sku&amp;#34;&lt;/span>: &lt;span style="color:#ae81ff">738594937&lt;/span> },
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> { },
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> { &lt;span style="color:#f92672">&amp;#34;name&amp;#34;&lt;/span>: &lt;span style="color:#e6db74">&amp;#34;Nail&amp;#34;&lt;/span>, &lt;span style="color:#f92672">&amp;#34;sku&amp;#34;&lt;/span>: &lt;span style="color:#ae81ff">284758393&lt;/span>, &lt;span style="color:#f92672">&amp;#34;color&amp;#34;&lt;/span>: &lt;span style="color:#e6db74">&amp;#34;gray&amp;#34;&lt;/span> }
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> ]
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>}
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>&lt;p>任何对表数组的引用都指向该数组里最近定义的表元素。&lt;br>
这允许你在最近的表内定义子表，甚至子表数组。&lt;/p>
&lt;div class="highlight">&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;">&lt;code class="language-toml" data-lang="toml">&lt;span style="display:flex;">&lt;span>[[&lt;span style="color:#a6e22e">fruits&lt;/span>]]
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#a6e22e">name&lt;/span> = &lt;span style="color:#e6db74">&amp;#34;apple&amp;#34;&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>[&lt;span style="color:#a6e22e">fruits&lt;/span>.&lt;span style="color:#a6e22e">physical&lt;/span>] &lt;span style="color:#75715e"># 子表&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#a6e22e">color&lt;/span> = &lt;span style="color:#e6db74">&amp;#34;red&amp;#34;&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#a6e22e">shape&lt;/span> = &lt;span style="color:#e6db74">&amp;#34;round&amp;#34;&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>[[&lt;span style="color:#a6e22e">fruits&lt;/span>.&lt;span style="color:#a6e22e">varieties&lt;/span>]] &lt;span style="color:#75715e"># 嵌套表数组&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#a6e22e">name&lt;/span> = &lt;span style="color:#e6db74">&amp;#34;red delicious&amp;#34;&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>[[&lt;span style="color:#a6e22e">fruits&lt;/span>.&lt;span style="color:#a6e22e">varieties&lt;/span>]]
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#a6e22e">name&lt;/span> = &lt;span style="color:#e6db74">&amp;#34;granny smith&amp;#34;&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>[[&lt;span style="color:#a6e22e">fruits&lt;/span>]]
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#a6e22e">name&lt;/span> = &lt;span style="color:#e6db74">&amp;#34;banana&amp;#34;&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>[[&lt;span style="color:#a6e22e">fruits&lt;/span>.&lt;span style="color:#a6e22e">varieties&lt;/span>]]
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#a6e22e">name&lt;/span> = &lt;span style="color:#e6db74">&amp;#34;plantain&amp;#34;&lt;/span>
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>&lt;p>上述 TOML 等价于 JSON 的如下结构。&lt;/p>
&lt;div class="highlight">&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;">&lt;code class="language-json" data-lang="json">&lt;span style="display:flex;">&lt;span>{
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#f92672">&amp;#34;fruits&amp;#34;&lt;/span>: [
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> {
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#f92672">&amp;#34;name&amp;#34;&lt;/span>: &lt;span style="color:#e6db74">&amp;#34;apple&amp;#34;&lt;/span>,
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#f92672">&amp;#34;physical&amp;#34;&lt;/span>: {
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#f92672">&amp;#34;color&amp;#34;&lt;/span>: &lt;span style="color:#e6db74">&amp;#34;red&amp;#34;&lt;/span>,
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#f92672">&amp;#34;shape&amp;#34;&lt;/span>: &lt;span style="color:#e6db74">&amp;#34;round&amp;#34;&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> },
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#f92672">&amp;#34;varieties&amp;#34;&lt;/span>: [
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> { &lt;span style="color:#f92672">&amp;#34;name&amp;#34;&lt;/span>: &lt;span style="color:#e6db74">&amp;#34;red delicious&amp;#34;&lt;/span> },
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> { &lt;span style="color:#f92672">&amp;#34;name&amp;#34;&lt;/span>: &lt;span style="color:#e6db74">&amp;#34;granny smith&amp;#34;&lt;/span> }
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> ]
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> },
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> {
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#f92672">&amp;#34;name&amp;#34;&lt;/span>: &lt;span style="color:#e6db74">&amp;#34;banana&amp;#34;&lt;/span>,
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#f92672">&amp;#34;varieties&amp;#34;&lt;/span>: [
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> { &lt;span style="color:#f92672">&amp;#34;name&amp;#34;&lt;/span>: &lt;span style="color:#e6db74">&amp;#34;plantain&amp;#34;&lt;/span> }
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> ]
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> }
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> ]
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>}
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>&lt;p>如果一个表或表数组的父级是一个数组元素，该元素必须在定义子级前先定义。&lt;br>
顺序颠倒的行为，必须在解析时报错。&lt;/p>
&lt;pre tabindex="0">&lt;code># 非法的 TOML 文档
[fruit.physical] # 子表，但它应该隶属于哪个父元素？
color = &amp;#34;red&amp;#34;
shape = &amp;#34;round&amp;#34;
[[fruit]] # 解析器必须在发现“fruit”是数组而非表时抛出错误
name = &amp;#34;apple&amp;#34;
&lt;/code>&lt;/pre>&lt;p>若试图向一个静态定义的数组追加内容，即便数组尚且为空，也必须在解析时报错。&lt;/p>
&lt;pre tabindex="0">&lt;code># 非法的 TOML 文档
fruits = []
[[fruits]] # 不允许
&lt;/code>&lt;/pre>&lt;p>若试图用已经确定为数组的名称定义表，必须在解析时报错。&lt;br>
将数组重定义为普通表的行为，也必须在解析时报错。&lt;/p>
&lt;pre tabindex="0">&lt;code># 非法的 TOML 文档
[[fruits]]
name = &amp;#34;apple&amp;#34;
[[fruits.varieties]]
name = &amp;#34;red delicious&amp;#34;
# 非法：该表与之前的表数组相冲突
[fruits.varieties]
name = &amp;#34;granny smith&amp;#34;
[fruits.physical]
color = &amp;#34;red&amp;#34;
shape = &amp;#34;round&amp;#34;
# 非法：该表数组与之前的表相冲突
[[fruits.physical]]
color = &amp;#34;green&amp;#34;
&lt;/code>&lt;/pre>&lt;p>你也可以适当使用内联表：&lt;/p>
&lt;div class="highlight">&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;">&lt;code class="language-toml" data-lang="toml">&lt;span style="display:flex;">&lt;span>&lt;span style="color:#a6e22e">points&lt;/span> = [ { &lt;span style="color:#a6e22e">x&lt;/span> = &lt;span style="color:#ae81ff">1&lt;/span>, &lt;span style="color:#a6e22e">y&lt;/span> = &lt;span style="color:#ae81ff">2&lt;/span>, &lt;span style="color:#a6e22e">z&lt;/span> = &lt;span style="color:#ae81ff">3&lt;/span> },
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> { &lt;span style="color:#a6e22e">x&lt;/span> = &lt;span style="color:#ae81ff">7&lt;/span>, &lt;span style="color:#a6e22e">y&lt;/span> = &lt;span style="color:#ae81ff">8&lt;/span>, &lt;span style="color:#a6e22e">z&lt;/span> = &lt;span style="color:#ae81ff">9&lt;/span> },
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> { &lt;span style="color:#a6e22e">x&lt;/span> = &lt;span style="color:#ae81ff">2&lt;/span>, &lt;span style="color:#a6e22e">y&lt;/span> = &lt;span style="color:#ae81ff">4&lt;/span>, &lt;span style="color:#a6e22e">z&lt;/span> = &lt;span style="color:#ae81ff">8&lt;/span> } ]
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>&lt;h3 id="文件扩展名">文件扩展名&lt;/h3>
&lt;p>TOML 文件应当使用 &lt;code>.toml&lt;/code> 扩展名。&lt;/p>
&lt;h3 id="mime-类型">MIME 类型&lt;/h3>
&lt;p>在互联网上传输 TOML 文件时，恰当的 MIME 类型是 &lt;code>application/toml&lt;/code>。&lt;/p>
&lt;h3 id="abnf-语法">ABNF 语法&lt;/h3>
&lt;p>TOML 语法的严谨说明，由一个 &lt;a href="https://github.com/toml-lang/toml/blob/1.0.0/toml.abnf">ABNF 文件&lt;/a>另行提供。&lt;/p></description></item><item><title>塔防游戏-YORG.io</title><link>https://blog.baicai.me/article/2021/tower-defense/</link><pubDate>Wed, 02 Jun 2021 19:52:08 +0800</pubDate><author>admin@baicai.me (白菜)</author><guid>https://blog.baicai.me/article/2021/tower-defense/</guid><description>&lt;h3 id="塔防游戏">塔防游戏&lt;/h3>
&lt;blockquote>
&lt;p>可玩性很高的一款塔防游戏，需要各类元素合成，通过传送带传送宝石、木材、铁等元素，最后合成弓箭、大炮、闪电塔等来抵御怪兽的袭击，一玩就停不下来。&lt;/p>&lt;/blockquote>
&lt;p>传送门 &lt;a href="https://yorg.io/">https://yorg.io/&lt;/a>&lt;/p>
&lt;h3 id="玩法">玩法&lt;/h3>
&lt;p>通过传送带传送宝石、木材、铁等元素，最后合成弓箭、大炮、闪电塔等来抵御怪兽的袭击&lt;/p></description></item><item><title>网页版红色警戒2-Red Alert 2: Chrono Divide</title><link>https://blog.baicai.me/article/2021/red-alert-2-chronodivide/</link><pubDate>Wed, 02 Jun 2021 19:22:30 +0800</pubDate><author>admin@baicai.me (白菜)</author><guid>https://blog.baicai.me/article/2021/red-alert-2-chronodivide/</guid><description>&lt;h3 id="在线红警">在线红警&lt;/h3>
&lt;blockquote>
&lt;p>又是一波人的集体回忆。。。网站高度还原了经典游戏——红色警戒2，原汁原味的画面和音效，仿佛又回到了那个电脑房的年代！&lt;/p>&lt;/blockquote>
&lt;p>传送门 &lt;a href="https://game.chronodivide.com/">https://game.chronodivide.com/&lt;/a>&lt;/p>
&lt;h3 id="玩法">玩法&lt;/h3>
&lt;p>网站支持多人在线对战，注册登陆后即可开始！&lt;/p></description></item><item><title>Goproxy</title><link>https://blog.baicai.me/article/2021/goproxy/</link><pubDate>Thu, 27 May 2021 11:22:40 +0800</pubDate><author>admin@baicai.me (白菜)</author><guid>https://blog.baicai.me/article/2021/goproxy/</guid><description>&lt;h3 id="go-module代理仓库服务">Go Module代理仓库服务&lt;/h3>
&lt;p>七牛云提供的：https://goproxy.cn&lt;/p>
&lt;p>goproxy.io：https://goproxy.io 或 &lt;a href="https://proxy.golang.com.cn">https://proxy.golang.com.cn&lt;/a>&lt;/p>
&lt;p>百度云BOS提供的：https://goproxy.bj.bcebos.com/&lt;/p>
&lt;p>阿里云提供的：https://mirrors.aliyun.com/goproxy/&lt;/p>
&lt;h3 id="下载-go-镜像golang-downloads-mirrors">下载 Go 镜像（Golang Downloads Mirrors）&lt;/h3>
&lt;p>官网：https://go.dev/&lt;/p>
&lt;p>下载 Go 镜像：https://golang.google.cn/&lt;/p>
&lt;p>下载 Go 镜像：https://gomirrors.org/&lt;/p>
&lt;p>下载 Go 镜像：https://studygolang.com/dl&lt;/p></description></item><item><title>使用开源工具进行 Linux 内存取证</title><link>https://blog.baicai.me/article/2021/linux-memory-forensics/</link><pubDate>Wed, 26 May 2021 12:57:28 +0800</pubDate><author>admin@baicai.me (白菜)</author><guid>https://blog.baicai.me/article/2021/linux-memory-forensics/</guid><description>&lt;blockquote>
&lt;p>利用 Volatility 找出应用程序、网络连接、内核模块、文件等方面的情况。&lt;/p>&lt;/blockquote>
&lt;p>计算机的操作系统和应用使用主内存（RAM）来执行不同的任务。这种易失性内存包含大量关于运行应用、网络连接、内核模块、打开的文件以及几乎所有其他的内容信息，但这些信息每次计算机重启的时候都会被清除。&lt;/p>
&lt;p>内存取证是一种从内存中找到和抽取这些有价值的信息的方式。Volatility 是一种使用插件来处理这类信息的开源工具。但是，存在一个问题：在你处理这些信息前，必须将物理内存转储到一个文件中，而 Volatility 没有这种能力。&lt;/p>
&lt;p>因此，这篇文章分为两部分：&lt;/p>
&lt;ul>
&lt;li>第一部分是处理获取物理内存并将其转储到一个文件中。&lt;/li>
&lt;li>第二部分使用 Volatility 从这个内存转储中读取并处理这些信息。&lt;/li>
&lt;/ul>
&lt;p>我在本教程中使用了以下测试系统，不过它可以在任何 Linux 发行版上工作：&lt;/p>
&lt;div class="highlight">&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;">&lt;code class="language-bash" data-lang="bash">&lt;span style="display:flex;">&lt;span>$ cat /etc/redhat-release
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>Red Hat Enterprise Linux release 8.3 &lt;span style="color:#f92672">(&lt;/span>Ootpa&lt;span style="color:#f92672">)&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>$
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>$ uname -r
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>4.18.0-240.el8.x86_64
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>$
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>&lt;pre>&lt;code>注意事项： 部分 1 涉及到编译和加载一个内核模块。不要担心：它并不像听起来那么困难。
一些指南：
按照以下的步骤。
不要在生产系统或你的主要计算机上尝试任何这些步骤。
始终使用测试的虚拟机（VM）来尝试，直到你熟悉使用这些工具并理解它们的工作原理为止。
&lt;/code>&lt;/pre>
&lt;h2 id="安装需要的包">安装需要的包&lt;/h2>
&lt;p>在开始之前安装必要的工具。如果你经常使用基于 Debian 的发行版，可以使用 apt-get 命令。这些包大多数提供了需要的内核信息和工具来编译代码：&lt;/p>
&lt;div class="highlight">&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;">&lt;code class="language-bash" data-lang="bash">&lt;span style="display:flex;">&lt;span>$ yum install kernel-headers kernel-devel gcc elfutils-libelf-devel make git libdwarf-tools python2-devel.x86_64-y
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>&lt;h2 id="部分-1使用-lime-获取内存并将其转储到一个文件中">部分 1：使用 LiME 获取内存并将其转储到一个文件中&lt;/h2>
&lt;p>在开始分析内存之前，你需要一个内存转储供你使用。在实际的取证活动中，这可能来自一个被破坏或者被入侵的系统。这些信息通常会被收集和存储来分析入侵是如何发生的及其影响。由于你可能没有可用的内存转储，你可以获取你的测试 VM 的内存转储，并使用它来执行内存取证。&lt;/p>
&lt;p>Linux 内存提取器（LiME）是一个在 Linux 系统上获取内存很常用的工具。使用以下命令获得 LiME：&lt;/p>
&lt;div class="highlight">&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;">&lt;code class="language-bash" data-lang="bash">&lt;span style="display:flex;">&lt;span>$ git clone https://github.com/504ensicsLabs/LiME.git
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>$
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>$ cd LiME/src/
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>$
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>$ ls
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>deflate.c disk.c hash.c lime.h main.c Makefile Makefile.sample tcp.c
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>$
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>&lt;h3 id="构建-lime-内核模块">构建 LiME 内核模块&lt;/h3>
&lt;p>在 src 文件夹下运行 make 命令。这会创建一个以 .ko 为扩展名的内核模块。理想情况下，在 make 结束时，lime.ko 文件会使用格式 &lt;code>lime-&amp;lt;your-kernel-version&amp;gt;.ko&lt;/code> 被重命名。&lt;/p>
&lt;div class="highlight">&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;">&lt;code class="language-bash" data-lang="bash">&lt;span style="display:flex;">&lt;span>$ make
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>make -C /lib/modules/4.18.0-240.el8.x86_64/build M&lt;span style="color:#f92672">=&lt;/span>&lt;span style="color:#e6db74">&amp;#34;/root/LiME/src&amp;#34;&lt;/span> modules
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>make&lt;span style="color:#f92672">[&lt;/span>1&lt;span style="color:#f92672">]&lt;/span>: Entering directory &lt;span style="color:#e6db74">&amp;#39;/usr/src/kernels/4.18.0-240.el8.x86_64&amp;#39;&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&amp;lt;&amp;lt; 删节 &amp;gt;&amp;gt;
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>make&lt;span style="color:#f92672">[&lt;/span>1&lt;span style="color:#f92672">]&lt;/span>: Leaving directory &lt;span style="color:#e6db74">&amp;#39;/usr/src/kernels/4.18.0-240.el8.x86_64&amp;#39;&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>strip --strip-unneeded lime.ko
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>mv lime.ko lime-4.18.0-240.el8.x86_64.ko
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>$
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>$
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>$ ls -l lime-4.18.0-240.el8.x86_64.ko
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>-rw-r--r--. &lt;span style="color:#ae81ff">1&lt;/span> root root &lt;span style="color:#ae81ff">25696&lt;/span> Apr &lt;span style="color:#ae81ff">17&lt;/span> 14:45 lime-4.18.0-240.el8.x86_64.ko
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>$
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>$ file lime-4.18.0-240.el8.x86_64.ko
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>lime-4.18.0-240.el8.x86_64.ko: ELF 64-bit LSB relocatable, x86-64, version &lt;span style="color:#ae81ff">1&lt;/span> &lt;span style="color:#f92672">(&lt;/span>SYSV&lt;span style="color:#f92672">)&lt;/span>, BuildID&lt;span style="color:#f92672">[&lt;/span>sha1&lt;span style="color:#f92672">]=&lt;/span>1d0b5cf932389000d960a7e6b57c428b8e46c9cf, not stripped
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>$
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>&lt;h3 id="加载lime-内核模块">加载LiME 内核模块&lt;/h3>
&lt;p>现在是时候加载内核模块来获取系统内存了。insmod 命令会帮助加载内核模块；模块一旦被加载，会在你的系统上读取主内存（RAM）并且将内存的内容转储到命令行所提供的 path 目录下的文件中。另一个重要的参数是 format；保持 lime 的格式，如下所示。在插入内核模块之后，使用 lsmod 命令验证它是否真的被加载。&lt;/p>
&lt;div class="highlight">&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;">&lt;code class="language-bash" data-lang="bash">&lt;span style="display:flex;">&lt;span>$ lsmod | grep lime
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>$
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>$ insmod ./lime-4.18.0-240.el8.x86_64.ko &lt;span style="color:#e6db74">&amp;#34;path=../RHEL8.3_64bit.mem format=lime&amp;#34;&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>$
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>$ lsmod | grep lime
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>lime &lt;span style="color:#ae81ff">16384&lt;/span> &lt;span style="color:#ae81ff">0&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>$
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>&lt;p>你应该看到给 path 命令的文件已经创建好了，而且文件大小与你系统的物理内存（RAM）大小相同（并不奇怪）。一旦你有了内存转储，你就可以使用 rmmod 命令删除该内核模块：&lt;/p>
&lt;div class="highlight">&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;">&lt;code class="language-bash" data-lang="bash">&lt;span style="display:flex;">&lt;span>$
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>$ ls -l ~/LiME/RHEL8.3_64bit.mem
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>-r--r--r--. &lt;span style="color:#ae81ff">1&lt;/span> root root &lt;span style="color:#ae81ff">4294544480&lt;/span> Apr &lt;span style="color:#ae81ff">17&lt;/span> 14:47 /root/LiME/RHEL8.3_64bit.mem
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>$
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>$ du -sh ~/LiME/RHEL8.3_64bit.mem
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>4.0G /root/LiME/RHEL8.3_64bit.mem
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>$
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>$ free -m
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> total used free shared buff/cache available
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>Mem: &lt;span style="color:#ae81ff">3736&lt;/span> &lt;span style="color:#ae81ff">220&lt;/span> &lt;span style="color:#ae81ff">366&lt;/span> &lt;span style="color:#ae81ff">8&lt;/span> &lt;span style="color:#ae81ff">3149&lt;/span> &lt;span style="color:#ae81ff">3259&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>Swap: &lt;span style="color:#ae81ff">4059&lt;/span> &lt;span style="color:#ae81ff">8&lt;/span> &lt;span style="color:#ae81ff">4051&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>$
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>$ rmmod lime
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>$
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>$ lsmod | grep lime
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>$
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>&lt;h3 id="内存转储中是什么">内存转储中是什么？&lt;/h3>
&lt;p>这个内存转储文件只是原始数据，就像使用 file 命令可以看到的一样。你不可能通过手动去理解它；是的，在这里边有一些 ASCII 字符，但是你无法用编辑器打开这个文件并把它读出来。hexdump 的输出显示，最初的几个字节是 EmiL；这是因为你的请求格式在上面的命令行中是 lime：&lt;/p>
&lt;div class="highlight">&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;">&lt;code class="language-bash" data-lang="bash">&lt;span style="display:flex;">&lt;span>$ file ~/LiME/RHEL8.3_64bit.mem
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>/root/LiME/RHEL8.3_64bit.mem: data
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>$
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>$ hexdump -C ~/LiME/RHEL8.3_64bit.mem | head
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#ae81ff">00000000&lt;/span> &lt;span style="color:#ae81ff">45&lt;/span> 4d &lt;span style="color:#ae81ff">69&lt;/span> 4c &lt;span style="color:#ae81ff">01&lt;/span> &lt;span style="color:#ae81ff">00&lt;/span> &lt;span style="color:#ae81ff">00&lt;/span> &lt;span style="color:#ae81ff">00&lt;/span> &lt;span style="color:#ae81ff">00&lt;/span> &lt;span style="color:#ae81ff">10&lt;/span> &lt;span style="color:#ae81ff">00&lt;/span> &lt;span style="color:#ae81ff">00&lt;/span> &lt;span style="color:#ae81ff">00&lt;/span> &lt;span style="color:#ae81ff">00&lt;/span> &lt;span style="color:#ae81ff">00&lt;/span> &lt;span style="color:#ae81ff">00&lt;/span> |EMiL............|
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#ae81ff">00000010&lt;/span> ff fb &lt;span style="color:#ae81ff">09&lt;/span> &lt;span style="color:#ae81ff">00&lt;/span> &lt;span style="color:#ae81ff">00&lt;/span> &lt;span style="color:#ae81ff">00&lt;/span> &lt;span style="color:#ae81ff">00&lt;/span> &lt;span style="color:#ae81ff">00&lt;/span> &lt;span style="color:#ae81ff">00&lt;/span> &lt;span style="color:#ae81ff">00&lt;/span> &lt;span style="color:#ae81ff">00&lt;/span> &lt;span style="color:#ae81ff">00&lt;/span> &lt;span style="color:#ae81ff">00&lt;/span> &lt;span style="color:#ae81ff">00&lt;/span> &lt;span style="color:#ae81ff">00&lt;/span> &lt;span style="color:#ae81ff">00&lt;/span> |................|
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#ae81ff">00000020&lt;/span> b8 fe 4c cd &lt;span style="color:#ae81ff">21&lt;/span> &lt;span style="color:#ae81ff">44&lt;/span> &lt;span style="color:#ae81ff">00&lt;/span> &lt;span style="color:#ae81ff">32&lt;/span> &lt;span style="color:#ae81ff">20&lt;/span> &lt;span style="color:#ae81ff">00&lt;/span> &lt;span style="color:#ae81ff">00&lt;/span> 2a 2a 2a 2a 2a |..L.!D.2 ..*****|
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#ae81ff">00000030&lt;/span> 2a 2a 2a 2a 2a 2a 2a 2a 2a 2a 2a 2a 2a 2a 2a 2a |****************|
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#ae81ff">00000040&lt;/span> 2a 2a 2a 2a 2a 2a 2a 2a 2a 2a 2a 2a 2a &lt;span style="color:#ae81ff">20&lt;/span> &lt;span style="color:#ae81ff">00&lt;/span> &lt;span style="color:#ae81ff">20&lt;/span> |************* . |
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#ae81ff">00000050&lt;/span> &lt;span style="color:#ae81ff">00&lt;/span> &lt;span style="color:#ae81ff">00&lt;/span> &lt;span style="color:#ae81ff">00&lt;/span> &lt;span style="color:#ae81ff">00&lt;/span> &lt;span style="color:#ae81ff">00&lt;/span> &lt;span style="color:#ae81ff">00&lt;/span> &lt;span style="color:#ae81ff">00&lt;/span> &lt;span style="color:#ae81ff">00&lt;/span> &lt;span style="color:#ae81ff">00&lt;/span> &lt;span style="color:#ae81ff">00&lt;/span> &lt;span style="color:#ae81ff">00&lt;/span> &lt;span style="color:#ae81ff">00&lt;/span> &lt;span style="color:#ae81ff">00&lt;/span> &lt;span style="color:#ae81ff">00&lt;/span> &lt;span style="color:#ae81ff">00&lt;/span> &lt;span style="color:#ae81ff">00&lt;/span> |................|
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>*
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#ae81ff">00000080&lt;/span> &lt;span style="color:#ae81ff">00&lt;/span> &lt;span style="color:#ae81ff">00&lt;/span> &lt;span style="color:#ae81ff">00&lt;/span> &lt;span style="color:#ae81ff">00&lt;/span> &lt;span style="color:#ae81ff">00&lt;/span> &lt;span style="color:#ae81ff">00&lt;/span> &lt;span style="color:#ae81ff">00&lt;/span> &lt;span style="color:#ae81ff">00&lt;/span> &lt;span style="color:#ae81ff">00&lt;/span> &lt;span style="color:#ae81ff">00&lt;/span> &lt;span style="color:#ae81ff">00&lt;/span> &lt;span style="color:#ae81ff">00&lt;/span> &lt;span style="color:#ae81ff">70&lt;/span> &lt;span style="color:#ae81ff">78&lt;/span> &lt;span style="color:#ae81ff">65&lt;/span> 6c |............pxel|
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#ae81ff">00000090&lt;/span> &lt;span style="color:#ae81ff">69&lt;/span> 6e &lt;span style="color:#ae81ff">75&lt;/span> &lt;span style="color:#ae81ff">78&lt;/span> 2e &lt;span style="color:#ae81ff">30&lt;/span> &lt;span style="color:#ae81ff">00&lt;/span> &lt;span style="color:#ae81ff">00&lt;/span> &lt;span style="color:#ae81ff">00&lt;/span> &lt;span style="color:#ae81ff">00&lt;/span> &lt;span style="color:#ae81ff">00&lt;/span> &lt;span style="color:#ae81ff">00&lt;/span> &lt;span style="color:#ae81ff">00&lt;/span> &lt;span style="color:#ae81ff">00&lt;/span> &lt;span style="color:#ae81ff">00&lt;/span> &lt;span style="color:#ae81ff">00&lt;/span> |inux.0..........|
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>000000a0 &lt;span style="color:#ae81ff">00&lt;/span> &lt;span style="color:#ae81ff">00&lt;/span> &lt;span style="color:#ae81ff">00&lt;/span> &lt;span style="color:#ae81ff">00&lt;/span> &lt;span style="color:#ae81ff">00&lt;/span> &lt;span style="color:#ae81ff">00&lt;/span> &lt;span style="color:#ae81ff">00&lt;/span> &lt;span style="color:#ae81ff">00&lt;/span> &lt;span style="color:#ae81ff">00&lt;/span> &lt;span style="color:#ae81ff">00&lt;/span> &lt;span style="color:#ae81ff">00&lt;/span> &lt;span style="color:#ae81ff">00&lt;/span> &lt;span style="color:#ae81ff">00&lt;/span> &lt;span style="color:#ae81ff">00&lt;/span> &lt;span style="color:#ae81ff">00&lt;/span> &lt;span style="color:#ae81ff">00&lt;/span> |................|
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>$
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>&lt;h2 id="部分-2获得-volatility-并使用它来分析你的内存转储">部分 2：获得 Volatility 并使用它来分析你的内存转储&lt;/h2>
&lt;p>现在你有了要分析的示例内存转储，使用下面的命令获取 Volatility 软件。Volatility 已经用 Python 3 重写了，但是本教程使用的是用 Python 2 写的原始的 Volatility 包。如果你想用 Volatility 3 进行实验，可以从合适的 Git 仓库下载它，并在以下命令中使用 Python 3 而不是 Python 2：&lt;/p>
&lt;div class="highlight">&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;">&lt;code class="language-bash" data-lang="bash">&lt;span style="display:flex;">&lt;span>$ git clone https://github.com/volatilityfoundation/volatility.git
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>$
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>$ cd volatility/
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>$
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>$ ls
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>AUTHORS.txt contrib LEGAL.txt Makefile PKG-INFO pyinstaller.spec resources tools vol.py
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>CHANGELOG.txt CREDITS.txt LICENSE.txt MANIFEST.in pyinstaller README.txt setup.py volatility
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>$
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>&lt;p>Volatility 使用两个 Python 库来实现某些功能，所以使用以下命令来安装它们。否则，在你运行 Volatility 工具时，你可能看到一些导入错误；你可以忽略它们，除非你正在运行的插件需要这些库；这种情况下，工具将会报错：&lt;/p>
&lt;div class="highlight">&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;">&lt;code class="language-bash" data-lang="bash">&lt;span style="display:flex;">&lt;span>$ pip2 install pycrypto
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>$ pip2 install distorm3
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>&lt;h3 id="列出-volatility-的-linux-配置文件">列出 Volatility 的 Linux 配置文件&lt;/h3>
&lt;p>你将要运行的第一个 Volatility 命令列出了可用的 Linux 配置文件，运行 Volatility 命令的主要入口点是 vol.py 脚本。使用 Python 2 解释器调用它并提供 &amp;ndash;info 选项。为了缩小输出，查找以 Linux 开头的字符串。正如你所看到的，并没有很多 Linux 配置文件被列出：&lt;/p>
&lt;div class="highlight">&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;">&lt;code class="language-bash" data-lang="bash">&lt;span style="display:flex;">&lt;span>$ python2 vol.py --info | grep ^Linux
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>Volatility Foundation Volatility Framework 2.6.1
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>LinuxAMD64PagedMemory - Linux-specific AMD 64-bit address space.
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>$
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>&lt;h3 id="构建你自己的-linux-配置文件">构建你自己的 Linux 配置文件&lt;/h3>
&lt;p>Linux 发行版是多种多样的，并且是为不同架构而构建的。这就是为什么配置文件是必要的 —— Volatility 在提取信息前必须知道内存转储是从哪个系统和架构获得的。有一些 Volatility 命令可以找到这些信息；但是这个方法很费时。为了加快速度，可以使用以下命令构建一个自定义的 Linux 配置文件：&lt;/p>
&lt;p>移动到 Volatility 仓库的 tools/linux目录下，运行 make 命令：&lt;/p>
&lt;div class="highlight">&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;">&lt;code class="language-bash" data-lang="bash">&lt;span style="display:flex;">&lt;span>$ cd tools/linux/
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>$
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>$ pwd
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>/root/volatility/tools/linux
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>$
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>$ ls
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>kcore Makefile Makefile.enterprise module.c
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>$
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>$ make
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>make -C //lib/modules/4.18.0-240.el8.x86_64/build CONFIG_DEBUG_INFO&lt;span style="color:#f92672">=&lt;/span>y M&lt;span style="color:#f92672">=&lt;/span>&lt;span style="color:#e6db74">&amp;#34;/root/volatility/tools/linux&amp;#34;&lt;/span> modules
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>make&lt;span style="color:#f92672">[&lt;/span>1&lt;span style="color:#f92672">]&lt;/span>: Entering directory &lt;span style="color:#e6db74">&amp;#39;/usr/src/kernels/4.18.0-240.el8.x86_64&amp;#39;&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&amp;lt;&amp;lt; 删节 &amp;gt;&amp;gt;
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>make&lt;span style="color:#f92672">[&lt;/span>1&lt;span style="color:#f92672">]&lt;/span>: Leaving directory &lt;span style="color:#e6db74">&amp;#39;/usr/src/kernels/4.18.0-240.el8.x86_64&amp;#39;&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>$
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>&lt;p>你应该看到一个新的 module.dwarf 文件。你也需要 /boot 目录下的 System.map 文件，因为它包含了所有与当前运行的内核相关的符号：&lt;/p>
&lt;div class="highlight">&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;">&lt;code class="language-bash" data-lang="bash">&lt;span style="display:flex;">&lt;span>$ ls
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>kcore Makefile Makefile.enterprise module.c module.dwarf
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>$
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>$ ls -l module.dwarf
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>-rw-r--r--. &lt;span style="color:#ae81ff">1&lt;/span> root root &lt;span style="color:#ae81ff">3987904&lt;/span> Apr &lt;span style="color:#ae81ff">17&lt;/span> 15:17 module.dwarf
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>$
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>$ ls -l /boot/System.map-4.18.0-240.el8.x86_64
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>-rw-------. &lt;span style="color:#ae81ff">1&lt;/span> root root &lt;span style="color:#ae81ff">4032815&lt;/span> Sep &lt;span style="color:#ae81ff">23&lt;/span> &lt;span style="color:#ae81ff">2020&lt;/span> /boot/System.map-4.18.0-240.el8.x86_64
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>$
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>$
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>&lt;p>要创建一个自定义配置文件，移动回到 Volatility 目录并且运行下面的命令。第一个参数提供了一个自定义 .zip 文件，文件名是你自己命名的。我经常使用操作系统和内核版本来命名。下一个参数是前边创建的 module.dwarf 文件，最后一个参数是 /boot 目录下的 System.map 文件：&lt;/p>
&lt;div class="highlight">&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;">&lt;code class="language-bash" data-lang="bash">&lt;span style="display:flex;">&lt;span>$
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>$ cd volatility/
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>$
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>$ zip volatility/plugins/overlays/linux/Redhat8.3_4.18.0-240.zip tools/linux/module.dwarf /boot/System.map-4.18.0-240.el8.x86_64
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> adding: tools/linux/module.dwarf &lt;span style="color:#f92672">(&lt;/span>deflated 91%&lt;span style="color:#f92672">)&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> adding: boot/System.map-4.18.0-240.el8.x86_64 &lt;span style="color:#f92672">(&lt;/span>deflated 79%&lt;span style="color:#f92672">)&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>$
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>&lt;p>现在自定义配置文件就准备好了，所以在前边给出的位置检查一下 .zip 文件是否被创建好。如果你想知道 Volatility 是否检测到这个自定义配置文件，再一次运行 &amp;ndash;info 命令。现在，你应该可以在下边的列出的内容中看到新的配置文件：&lt;/p>
&lt;div class="highlight">&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;">&lt;code class="language-bash" data-lang="bash">&lt;span style="display:flex;">&lt;span>$
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>$ ls -l volatility/plugins/overlays/linux/Redhat8.3_4.18.0-240.zip
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>-rw-r--r--. &lt;span style="color:#ae81ff">1&lt;/span> root root &lt;span style="color:#ae81ff">1190360&lt;/span> Apr &lt;span style="color:#ae81ff">17&lt;/span> 15:20 volatility/plugins/overlays/linux/Redhat8.3_4.18.0-240.zip
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>$
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>$
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>$ python2 vol.py --info | grep Redhat
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>Volatility Foundation Volatility Framework 2.6.1
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>LinuxRedhat8_3_4_18_0-240x64 - A Profile &lt;span style="color:#66d9ef">for&lt;/span> Linux Redhat8.3_4.18.0-240 x64
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>$
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>$
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>&lt;h3 id="开始使用-volatility">开始使用 Volatility&lt;/h3>
&lt;p>现在你已经准备好去做一些真正的内存取证了。记住，Volatility 是由自定义的插件组成的，你可以针对内存转储来获得信息。命令的通用格式是：&lt;/p>
&lt;div class="highlight">&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;">&lt;code class="language-bash" data-lang="bash">&lt;span style="display:flex;">&lt;span>python2 vol.py -f &amp;lt;memory-dump-file-taken-by-Lime&amp;gt; &amp;lt;plugin-name&amp;gt; --profile&lt;span style="color:#f92672">=&lt;/span>&amp;lt;name-of-our-custom-profile&amp;gt;
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>&lt;p>有了这些信息，运行 linux_banner 插件来看看你是否可从内存转储中识别正确的发行版信息：&lt;/p>
&lt;div class="highlight">&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;">&lt;code class="language-bash" data-lang="bash">&lt;span style="display:flex;">&lt;span>$ python2 vol.py -f ~/LiME/RHEL8.3_64bit.mem linux_banner --profile&lt;span style="color:#f92672">=&lt;/span>LinuxRedhat8_3_4_18_0-240x64
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>Volatility Foundation Volatility Framework 2.6.1
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>Linux version 4.18.0-240.el8.x86_64 &lt;span style="color:#f92672">([&lt;/span>mockbuild@vm09.test.com&lt;span style="color:#f92672">][&lt;/span>4&lt;span style="color:#f92672">])&lt;/span> &lt;span style="color:#f92672">(&lt;/span>gcc version 8.3.1 &lt;span style="color:#ae81ff">20191121&lt;/span> &lt;span style="color:#f92672">(&lt;/span>Red Hat 8.3.1-5&lt;span style="color:#f92672">)&lt;/span> &lt;span style="color:#f92672">(&lt;/span>GCC&lt;span style="color:#f92672">))&lt;/span> &lt;span style="color:#75715e">#1 SMP Wed Sep 23 05:13:10 EDT 2020&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>$
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>&lt;h3 id="找到-linux-插件">找到 Linux 插件&lt;/h3>
&lt;p>到现在都很顺利，所以现在你可能对如何找到所有 Linux 插件的名字比较好奇。有一个简单的技巧：运行 &amp;ndash;info 命令并抓取 linux_ 字符串。有各种各样的插件可用于不同的用途。这里列出一部分：&lt;/p>
&lt;div class="highlight">&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;">&lt;code class="language-bash" data-lang="bash">&lt;span style="display:flex;">&lt;span>$ python2 vol.py --info | grep linux_
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>Volatility Foundation Volatility Framework 2.6.1
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>linux_apihooks - Checks &lt;span style="color:#66d9ef">for&lt;/span> userland apihooks
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>linux_arp - Print the ARP table
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>linux_aslr_shift - Automatically detect the Linux ASLR shift
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&amp;lt;&amp;lt; 删节 &amp;gt;&amp;gt;
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>linux_banner - Prints the Linux banner information
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>linux_vma_cache - Gather VMAs from the vm_area_struct cache
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>linux_volshell - Shell in the memory image
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>linux_yarascan - A shell in the Linux memory image
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>$
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>&lt;p>使用 linux_psaux 插件检查内存转储时系统上正在运行哪些进程。注意列表中的最后一个命令：它是你在转储之前运行的 insmod 命令。&lt;/p>
&lt;div class="highlight">&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;">&lt;code class="language-bash" data-lang="bash">&lt;span style="display:flex;">&lt;span>$ python2 vol.py -f ~/LiME/RHEL8.3_64bit.mem linux_psaux --profile&lt;span style="color:#f92672">=&lt;/span>LinuxRedhat8_3_4_18_0-240x64
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>Volatility Foundation Volatility Framework 2.6.1
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>Pid Uid Gid Arguments
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#ae81ff">1&lt;/span> &lt;span style="color:#ae81ff">0&lt;/span> &lt;span style="color:#ae81ff">0&lt;/span> /usr/lib/systemd/systemd --switched-root --system --deserialize &lt;span style="color:#ae81ff">18&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#ae81ff">2&lt;/span> &lt;span style="color:#ae81ff">0&lt;/span> &lt;span style="color:#ae81ff">0&lt;/span> &lt;span style="color:#f92672">[&lt;/span>kthreadd&lt;span style="color:#f92672">]&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#ae81ff">3&lt;/span> &lt;span style="color:#ae81ff">0&lt;/span> &lt;span style="color:#ae81ff">0&lt;/span> &lt;span style="color:#f92672">[&lt;/span>rcu_gp&lt;span style="color:#f92672">]&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#ae81ff">4&lt;/span> &lt;span style="color:#ae81ff">0&lt;/span> &lt;span style="color:#ae81ff">0&lt;/span> &lt;span style="color:#f92672">[&lt;/span>rcu_par_gp&lt;span style="color:#f92672">]&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#ae81ff">861&lt;/span> &lt;span style="color:#ae81ff">0&lt;/span> &lt;span style="color:#ae81ff">0&lt;/span> /usr/libexec/platform-python -Es /usr/sbin/tuned -l -P
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#ae81ff">869&lt;/span> &lt;span style="color:#ae81ff">0&lt;/span> &lt;span style="color:#ae81ff">0&lt;/span> /usr/bin/rhsmcertd
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#ae81ff">875&lt;/span> &lt;span style="color:#ae81ff">0&lt;/span> &lt;span style="color:#ae81ff">0&lt;/span> /usr/libexec/sssd/sssd_be --domain implicit_files --uid &lt;span style="color:#ae81ff">0&lt;/span> --gid &lt;span style="color:#ae81ff">0&lt;/span> --logger&lt;span style="color:#f92672">=&lt;/span>files
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#ae81ff">878&lt;/span> &lt;span style="color:#ae81ff">0&lt;/span> &lt;span style="color:#ae81ff">0&lt;/span> /usr/libexec/sssd/sssd_nss --uid &lt;span style="color:#ae81ff">0&lt;/span> --gid &lt;span style="color:#ae81ff">0&lt;/span> --logger&lt;span style="color:#f92672">=&lt;/span>files
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&amp;lt;&amp;lt; 删节 &amp;gt;&amp;gt;
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#ae81ff">11064&lt;/span> &lt;span style="color:#ae81ff">89&lt;/span> &lt;span style="color:#ae81ff">89&lt;/span> qmgr -l -t unix -u
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#ae81ff">227148&lt;/span> &lt;span style="color:#ae81ff">0&lt;/span> &lt;span style="color:#ae81ff">0&lt;/span> &lt;span style="color:#f92672">[&lt;/span>kworker/0:0&lt;span style="color:#f92672">]&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#ae81ff">227298&lt;/span> &lt;span style="color:#ae81ff">0&lt;/span> &lt;span style="color:#ae81ff">0&lt;/span> -bash
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#ae81ff">227374&lt;/span> &lt;span style="color:#ae81ff">0&lt;/span> &lt;span style="color:#ae81ff">0&lt;/span> &lt;span style="color:#f92672">[&lt;/span>kworker/u2:1&lt;span style="color:#f92672">]&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#ae81ff">227375&lt;/span> &lt;span style="color:#ae81ff">0&lt;/span> &lt;span style="color:#ae81ff">0&lt;/span> &lt;span style="color:#f92672">[&lt;/span>kworker/0:2&lt;span style="color:#f92672">]&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#ae81ff">227884&lt;/span> &lt;span style="color:#ae81ff">0&lt;/span> &lt;span style="color:#ae81ff">0&lt;/span> &lt;span style="color:#f92672">[&lt;/span>kworker/0:3&lt;span style="color:#f92672">]&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#ae81ff">228573&lt;/span> &lt;span style="color:#ae81ff">0&lt;/span> &lt;span style="color:#ae81ff">0&lt;/span> insmod ./lime-4.18.0-240.el8.x86_64.ko path&lt;span style="color:#f92672">=&lt;/span>../RHEL8.3_64bit.mem format&lt;span style="color:#f92672">=&lt;/span>lime
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#ae81ff">228576&lt;/span> &lt;span style="color:#ae81ff">0&lt;/span> &lt;span style="color:#ae81ff">0&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>$
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>&lt;p>想要知道系统的网络状态吗？运行 linux_netstat 插件来找到在内存转储期间网络连接的状态：&lt;/p>
&lt;div class="highlight">&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;">&lt;code class="language-bash" data-lang="bash">&lt;span style="display:flex;">&lt;span>$ python2 vol.py -f ~/LiME/RHEL8.3_64bit.mem linux_netstat --profile&lt;span style="color:#f92672">=&lt;/span>LinuxRedhat8_3_4_18_0-240x64
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>Volatility Foundation Volatility Framework 2.6.1
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>UNIX &lt;span style="color:#ae81ff">18113&lt;/span> systemd/1 /run/systemd/private
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>UNIX &lt;span style="color:#ae81ff">11411&lt;/span> systemd/1 /run/systemd/notify
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>UNIX &lt;span style="color:#ae81ff">11413&lt;/span> systemd/1 /run/systemd/cgroups-agent
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>UNIX &lt;span style="color:#ae81ff">11415&lt;/span> systemd/1
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>UNIX &lt;span style="color:#ae81ff">11416&lt;/span> systemd/1
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&amp;lt;&amp;lt; 删节 &amp;gt;&amp;gt;
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>$
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>&lt;p>接下来，使用 linux_mount 插件来看在内存转储期间哪些文件系统被挂载：&lt;/p>
&lt;div class="highlight">&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;">&lt;code class="language-bash" data-lang="bash">&lt;span style="display:flex;">&lt;span>$ python2 vol.py -f ~/LiME/RHEL8.3_64bit.mem linux_mount --profile&lt;span style="color:#f92672">=&lt;/span>LinuxRedhat8_3_4_18_0-240x64
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>Volatility Foundation Volatility Framework 2.6.1
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>tmpfs /sys/fs/cgroup tmpfs ro,nosuid,nodev,noexec
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>cgroup /sys/fs/cgroup/pids cgroup rw,relatime,nosuid,nodev,noexec
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>systemd-1 /proc/sys/fs/binfmt_misc autofs rw,relatime
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>sunrpc /var/lib/nfs/rpc_pipefs rpc_pipefs rw,relatime
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>/dev/mapper/rhel_kvm--03--guest11-root / xfs rw,relatime
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>tmpfs /dev/shm tmpfs rw,nosuid,nodev
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>selinuxfs /sys/fs/selinux selinuxfs rw,relatime
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&amp;lt;&amp;lt; 删节 &amp;gt;&amp;gt;
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>cgroup /sys/fs/cgroup/net_cls,net_prio cgroup rw,relatime,nosuid,nodev,noexec
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>cgroup /sys/fs/cgroup/cpu,cpuacct cgroup rw,relatime,nosuid,nodev,noexec
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>bpf /sys/fs/bpf bpf rw,relatime,nosuid,nodev,noexec
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>cgroup /sys/fs/cgroup/memory cgroup ro,relatime,nosuid,nodev,noexec
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>cgroup /sys/fs/cgroup/cpuset cgroup rw,relatime,nosuid,nodev,noexec
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>mqueue /dev/mqueue mqueue rw,relatime
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>$
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>&lt;p>好奇哪些内核模块被加载了吗？Volatility 也为这个提供了一个插件 linux_lsmod：&lt;/p>
&lt;div class="highlight">&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;">&lt;code class="language-bash" data-lang="bash">&lt;span style="display:flex;">&lt;span>$ python2 vol.py -f ~/LiME/RHEL8.3_64bit.mem linux_lsmod --profile&lt;span style="color:#f92672">=&lt;/span>LinuxRedhat8_3_4_18_0-240x64
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>Volatility Foundation Volatility Framework 2.6.1
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>ffffffffc0535040 lime &lt;span style="color:#ae81ff">20480&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>ffffffffc0530540 binfmt_misc &lt;span style="color:#ae81ff">20480&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>ffffffffc05e8040 sunrpc &lt;span style="color:#ae81ff">479232&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&amp;lt;&amp;lt; 删节 &amp;gt;&amp;gt;
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>ffffffffc04f9540 nfit &lt;span style="color:#ae81ff">65536&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>ffffffffc0266280 dm_mirror &lt;span style="color:#ae81ff">28672&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>ffffffffc025e040 dm_region_hash &lt;span style="color:#ae81ff">20480&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>ffffffffc0258180 dm_log &lt;span style="color:#ae81ff">20480&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>ffffffffc024bbc0 dm_mod &lt;span style="color:#ae81ff">151552&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>$
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>&lt;p>想知道哪些文件被哪些进程打开了吗？使用 linux_bash 插件可以列出这些信息：&lt;/p>
&lt;div class="highlight">&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;">&lt;code class="language-bash" data-lang="bash">&lt;span style="display:flex;">&lt;span>$ python2 vol.py -f ~/LiME/RHEL8.3_64bit.mem linux_bash --profile&lt;span style="color:#f92672">=&lt;/span>LinuxRedhat8_3_4_18_0-240x64 -v
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>Volatility Foundation Volatility Framework 2.6.1
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>Pid Name Command Time Command
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>-------- -------------------- ------------------------------ -------
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#ae81ff">227221&lt;/span> bash 2021-04-17 18:38:24 UTC+0000 lsmod
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#ae81ff">227221&lt;/span> bash 2021-04-17 18:38:24 UTC+0000 rm -f .log
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#ae81ff">227221&lt;/span> bash 2021-04-17 18:38:24 UTC+0000 ls -l /etc/zzz
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#ae81ff">227221&lt;/span> bash 2021-04-17 18:38:24 UTC+0000 cat ~/.vimrc
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#ae81ff">227221&lt;/span> bash 2021-04-17 18:38:24 UTC+0000 ls
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#ae81ff">227221&lt;/span> bash 2021-04-17 18:38:24 UTC+0000 cat /proc/817/cwd
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#ae81ff">227221&lt;/span> bash 2021-04-17 18:38:24 UTC+0000 ls -l /proc/817/cwd
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#ae81ff">227221&lt;/span> bash 2021-04-17 18:38:24 UTC+0000 ls /proc/817/
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&amp;lt;&amp;lt; 删节 &amp;gt;&amp;gt;
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#ae81ff">227298&lt;/span> bash 2021-04-17 18:40:30 UTC+0000 gcc prt.c
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#ae81ff">227298&lt;/span> bash 2021-04-17 18:40:30 UTC+0000 ls
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#ae81ff">227298&lt;/span> bash 2021-04-17 18:40:30 UTC+0000 ./a.out
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#ae81ff">227298&lt;/span> bash 2021-04-17 18:40:30 UTC+0000 vim prt.c
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#ae81ff">227298&lt;/span> bash 2021-04-17 18:40:30 UTC+0000 gcc prt.c
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#ae81ff">227298&lt;/span> bash 2021-04-17 18:40:30 UTC+0000 ./a.out
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#ae81ff">227298&lt;/span> bash 2021-04-17 18:40:30 UTC+0000 ls
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>$
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>&lt;p>想知道哪些文件被哪些进程打开了吗？使用 linux_lsof 插件可以列出这些信息：&lt;/p>
&lt;div class="highlight">&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;">&lt;code class="language-bash" data-lang="bash">&lt;span style="display:flex;">&lt;span>$ python2 vol.py -f ~/LiME/RHEL8.3_64bit.mem linux_lsof --profile&lt;span style="color:#f92672">=&lt;/span>LinuxRedhat8_3_4_18_0-240x64
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>Volatility Foundation Volatility Framework 2.6.1
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>Offset Name Pid FD Path
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>------------------ ------------------------------ -------- -------- ----
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>0xffff9c83fb1e9f40 rsyslogd &lt;span style="color:#ae81ff">71194&lt;/span> &lt;span style="color:#ae81ff">0&lt;/span> /dev/null
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>0xffff9c83fb1e9f40 rsyslogd &lt;span style="color:#ae81ff">71194&lt;/span> &lt;span style="color:#ae81ff">1&lt;/span> /dev/null
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>0xffff9c83fb1e9f40 rsyslogd &lt;span style="color:#ae81ff">71194&lt;/span> &lt;span style="color:#ae81ff">2&lt;/span> /dev/null
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>0xffff9c83fb1e9f40 rsyslogd &lt;span style="color:#ae81ff">71194&lt;/span> &lt;span style="color:#ae81ff">3&lt;/span> /dev/urandom
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>0xffff9c83fb1e9f40 rsyslogd &lt;span style="color:#ae81ff">71194&lt;/span> &lt;span style="color:#ae81ff">4&lt;/span> socket:&lt;span style="color:#f92672">[&lt;/span>83565&lt;span style="color:#f92672">]&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>0xffff9c83fb1e9f40 rsyslogd &lt;span style="color:#ae81ff">71194&lt;/span> &lt;span style="color:#ae81ff">5&lt;/span> /var/log/messages
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>0xffff9c83fb1e9f40 rsyslogd &lt;span style="color:#ae81ff">71194&lt;/span> &lt;span style="color:#ae81ff">6&lt;/span> anon_inode:&lt;span style="color:#f92672">[&lt;/span>9063&lt;span style="color:#f92672">]&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>0xffff9c83fb1e9f40 rsyslogd &lt;span style="color:#ae81ff">71194&lt;/span> &lt;span style="color:#ae81ff">7&lt;/span> /var/log/secure
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&amp;lt;&amp;lt; 删节 &amp;gt;&amp;gt;
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>0xffff9c8365761f40 insmod &lt;span style="color:#ae81ff">228573&lt;/span> &lt;span style="color:#ae81ff">0&lt;/span> /dev/pts/0
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>0xffff9c8365761f40 insmod &lt;span style="color:#ae81ff">228573&lt;/span> &lt;span style="color:#ae81ff">1&lt;/span> /dev/pts/0
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>0xffff9c8365761f40 insmod &lt;span style="color:#ae81ff">228573&lt;/span> &lt;span style="color:#ae81ff">2&lt;/span> /dev/pts/0
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>0xffff9c8365761f40 insmod &lt;span style="color:#ae81ff">228573&lt;/span> &lt;span style="color:#ae81ff">3&lt;/span> /root/LiME/src/lime-4.18.0-240.el8.x86_64.ko
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>$
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>&lt;h3 id="访问-linux-插件脚本位置">访问 Linux 插件脚本位置&lt;/h3>
&lt;p>通过读取内存转储和处理这些信息，你可以获得更多的信息。如果你会 Python，并且好奇这些信息是如何被处理的，可以到存储所有插件的目录，选择一个你感兴趣的，并看看 Volatility 是如何获得这些信息的：&lt;/p>
&lt;div class="highlight">&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;">&lt;code class="language-bash" data-lang="bash">&lt;span style="display:flex;">&lt;span>$ ls volatility/plugins/linux/
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>apihooks.py common.py kernel_opened_files.py malfind.py psaux.py
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>apihooks.pyc common.pyc kernel_opened_files.pyc malfind.pyc psaux.pyc
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>arp.py cpuinfo.py keyboard_notifiers.py mount_cache.py psenv.py
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>arp.pyc cpuinfo.pyc keyboard_notifiers.pyc mount_cache.pyc psenv.pyc
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>aslr_shift.py dentry_cache.py ld_env.py mount.py pslist_cache.py
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>aslr_shift.pyc dentry_cache.pyc ld_env.pyc mount.pyc pslist_cache.pyc
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&amp;lt;&amp;lt; 删节 &amp;gt;&amp;gt;
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>check_syscall_arm.py __init__.py lsmod.py proc_maps.py tty_check.py
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>check_syscall_arm.pyc __init__.pyc lsmod.pyc proc_maps.pyc tty_check.pyc
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>check_syscall.py iomem.py lsof.py proc_maps_rb.py vma_cache.py
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>check_syscall.pyc iomem.pyc lsof.pyc proc_maps_rb.pyc vma_cache.pyc
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>$
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>$
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>&lt;p>我喜欢 Volatility 的理由是他提供了许多安全插件。这些信息很难手动获取：&lt;/p>
&lt;pre>&lt;code>linux_hidden_modules - Carves memory to find hidden kernel modules
linux_malfind - Looks for suspicious process mappings
linux_truecrypt_passphrase - Recovers cached Truecrypt passphrases
&lt;/code>&lt;/pre>
&lt;p>Volatility 也允许你在内存转储中打开一个 shell，所以你可以运行 shell 命令来代替上面所有命令，并获得相同的信息：&lt;/p>
&lt;div class="highlight">&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;">&lt;code class="language-bash" data-lang="bash">&lt;span style="display:flex;">&lt;span>$ python2 vol.py -f ~/LiME/RHEL8.3_64bit.mem linux_volshell --profile&lt;span style="color:#f92672">=&lt;/span>LinuxRedhat8_3_4_18_0-240x64 -v
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>Volatility Foundation Volatility Framework 2.6.1
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>Current context: process systemd, pid&lt;span style="color:#f92672">=&lt;/span>&lt;span style="color:#ae81ff">1&lt;/span> DTB&lt;span style="color:#f92672">=&lt;/span>0x1042dc000
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>Welcome to volshell! Current memory image is:
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>file:///root/LiME/RHEL8.3_64bit.mem
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>To get help, type &lt;span style="color:#e6db74">&amp;#39;hh()&amp;#39;&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&amp;gt;&amp;gt;&amp;gt;
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&amp;gt;&amp;gt;&amp;gt; sc&lt;span style="color:#f92672">()&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>Current context: process systemd, pid&lt;span style="color:#f92672">=&lt;/span>&lt;span style="color:#ae81ff">1&lt;/span> DTB&lt;span style="color:#f92672">=&lt;/span>0x1042dc000
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&amp;gt;&amp;gt;&amp;gt;
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>&lt;h2 id="接下来的步骤">接下来的步骤&lt;/h2>
&lt;p>内存转储是了解 Linux 内部情况的好方法。试一试 Volatility 的所有插件，并详细研究它们的输出。然后思考这些信息如何能够帮助你识别入侵或安全问题。深入了解这些插件的工作原理，甚至尝试改进它们。如果你没有找到你想做的事情的插件，那就写一个并提交给 Volatility，这样其他人也可以使用它。&lt;/p>
&lt;h3 id="参考">参考&lt;/h3>
&lt;p>使用开源工具进行 Linux 内存取证 &lt;a href="https://linux.cn/article-13425-1.html">[1]&lt;/a>&lt;/p>
&lt;p>Perform Linux memory forensics with this open source tool &lt;a href="https://opensource.com/article/21/4/linux-memory-forensics">[2]&lt;/a>&lt;/p></description></item><item><title>使用 sed 命令进行复制、剪切和粘贴</title><link>https://blog.baicai.me/article/2021/linux_sed/</link><pubDate>Mon, 24 May 2021 00:39:20 +0800</pubDate><author>admin@baicai.me (白菜)</author><guid>https://blog.baicai.me/article/2021/linux_sed/</guid><description>&lt;blockquote>
&lt;p>很少有 Unix 命令像 sed、grep 和 awk 一样出名，它们经常组合在一起，可能是因为它们具有奇怪的名称和强大的文本解析能力。它们还在一些语法和逻辑上有相似之处。虽然它们都能用于文本解析，但都有其特殊性。本文研究 sed 命令，它是一个 流编辑器。&lt;/p>&lt;/blockquote>
&lt;h3 id="安装-sed">安装 sed&lt;/h3>
&lt;p>如果你使用的是 Linux、BSD 或 macOS，那么它们已经安装了 GNU 的或 BSD 的 sed。这些是原始 sed 命令的独特重新实现。虽然它们很相似，但也有一些细微的差别。本文已经在 Linux 和 NetBSD 版本上进行了测试，所以你可以使用你的计算机上找到的任何 sed，但是对于 BSD sed，你必须使用短选项（例如 -n 而不是 &amp;ndash;quiet）。&lt;/p>
&lt;p>GNU sed 通常被认为是功能最丰富的 sed，因此无论你是否运行 Linux，你可能都想要尝试一下。如果在 Ports 树中找不到 GNU sed（在非 Linux 系统上通常称为 gsed），你可以从 GNU 网站 下载源代码。 安装 GNU sed 的好处是，你可以使用它的额外功能，但是如果需要可移植性，还可以限制它以遵守 sed 的 POSIX 规范。&lt;/p>
&lt;p>MacOS 用户可以在 MacPorts 或 Homebrew 上找到 GNU sed。&lt;/p>
&lt;p>在 Windows 上，你可以通过 Chocolatey 来 安装 GNU sed。&lt;/p>
&lt;h3 id="了解模式空间和保留空间">了解模式空间和保留空间&lt;/h3>
&lt;p>sed 一次只能处理一行。因为它没有可视化模式，所以会创建一个 模式空间，这是一个内存空间，其中包含来自输入流的当前行（删除了尾部的任何换行符）。填充模式空间后，sed 将执行你的指令。当命令执行完时，sed 将模式空间中的内容打印到输出流，默认是 标准输出，但是可以将输出重定向到文件，甚至使用 &lt;code>--in-place=.bak&lt;/code> 选项重定向到同一文件。&lt;/p>
&lt;p>然后，循环从下一个输入行再次开始。&lt;/p>
&lt;p>为了在遍历文件时提供一点灵活性，sed 还提供了保留空间（有时也称为 保留缓冲区），即 sed 内存中为临时数据存储保留的空间。你可以将保留空间当作剪贴板，实际上，这正是本文所演示的内容：如何使用 sed 复制/剪切和粘贴。&lt;/p>
&lt;p>首先，创建一个示例文本文件，其内容如下：&lt;/p>
&lt;pre>&lt;code>Line one
Line three
Line two
&lt;/code>&lt;/pre>
&lt;h3 id="复制数据到保留空间">复制数据到保留空间&lt;/h3>
&lt;p>要将内容放置在 sed 的保留空间，使用 &lt;code>h&lt;/code> 或 &lt;code>H&lt;/code> 命令。小写的 &lt;code>h&lt;/code> 告诉 sed 覆盖保留空间中的当前内容，而大写的 &lt;code>H&lt;/code> 告诉 sed 将数据追加到保留空间中已经存在的内容之后。&lt;/p>
&lt;p>单独使用，什么都看不到：&lt;/p>
&lt;div class="highlight">&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;">&lt;code class="language-bash" data-lang="bash">&lt;span style="display:flex;">&lt;span>$ sed --quiet -e &lt;span style="color:#e6db74">&amp;#39;/three/ h&amp;#39;&lt;/span> example.txt
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>$
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>&lt;p>&lt;code>--quiet&lt;/code>（缩写为 &lt;code>-n&lt;/code>）选项禁止显示所有输出，但 sed 执行了我的搜索需求。在这种情况下，sed 选择包含字符串 three 的任何行，并将其复制到保留空间。我没有告诉 sed 打印任何东西，所以没有输出。&lt;/p>
&lt;h3 id="从保留空间复制数据">从保留空间复制数据&lt;/h3>
&lt;p>要了解保留空间，你可以从保留空间复制内容，然后使用 g 命令将其放入模式空间，观察会发生什么：&lt;/p>
&lt;div class="highlight">&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;">&lt;code class="language-bash" data-lang="bash">&lt;span style="display:flex;">&lt;span>$ sed -n -e &lt;span style="color:#e6db74">&amp;#39;/three/h&amp;#39;&lt;/span> -e &lt;span style="color:#e6db74">&amp;#39;g;p&amp;#39;&lt;/span> example.txt
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>Line three
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>Line three
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>&lt;p>第一个空白行是因为当 sed 第一次复制内容到模式空间时，保留空间为空。&lt;/p>
&lt;p>接下来的两行包含 &lt;code>Line three&lt;/code> 是因为这是从第二行开始的保留空间。&lt;/p>
&lt;p>该命令使用两个唯一的脚本（-e）纯粹是为了帮助提高可读性和组织性。将步骤划分为单独的脚本可能会很有用，但是从技术上讲，以下命令与一个脚本语句一样有效：&lt;/p>
&lt;div class="highlight">&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;">&lt;code class="language-bash" data-lang="bash">&lt;span style="display:flex;">&lt;span>$ sed -n -e &lt;span style="color:#e6db74">&amp;#39;/three/h ; g ; p&amp;#39;&lt;/span> example.txt
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>Line three
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>Line three
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>&lt;h3 id="将数据追加到模式空间">将数据追加到模式空间&lt;/h3>
&lt;p>&lt;code>G&lt;/code> 命令会将一个换行符和保留空间的内容添加到模式空间。&lt;/p>
&lt;div class="highlight">&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;">&lt;code class="language-bash" data-lang="bash">&lt;span style="display:flex;">&lt;span>$ sed -n -e &lt;span style="color:#e6db74">&amp;#39;/three/h&amp;#39;&lt;/span> -e &lt;span style="color:#e6db74">&amp;#39;G;p&amp;#39;&lt;/span> example.txt
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>Line one
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>Line three
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>Line three
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>Line two
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>Line three
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>&lt;p>此输出的前两行同时包含模式空间（&lt;code>Line one&lt;/code>）的内容和空的保留空间。接下来的两行与搜索文本（&lt;code>three&lt;/code>）匹配，因此它既包含模式空间又包含保留空间。第三行的保留空间没有变化，因此在模式空间（&lt;code>Line two&lt;/code>）的末尾是保留空间（仍然是 &lt;code>Line three&lt;/code>）。&lt;/p>
&lt;h3 id="用-sed-剪切和粘贴">用 sed 剪切和粘贴&lt;/h3>
&lt;p>现在你知道了如何将字符串从模式空间转到保留空间并再次返回，你可以设计一个 sed 脚本来复制、删除，然后在文档中粘贴一行。例如，将示例文件的 Line three 挪至第三行，sed 可以解决这个问题：&lt;/p>
&lt;div class="highlight">&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;">&lt;code class="language-bash" data-lang="bash">&lt;span style="display:flex;">&lt;span>$ sed -n -e &lt;span style="color:#e6db74">&amp;#39;/three/ h&amp;#39;&lt;/span> -e &lt;span style="color:#e6db74">&amp;#39;/three/ d&amp;#39;&lt;/span> &lt;span style="color:#ae81ff">\
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#ae81ff">&lt;/span>-e &lt;span style="color:#e6db74">&amp;#39;/two/ G;p&amp;#39;&lt;/span> example.txt
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>Line one
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>Line two
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>Line three
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>&lt;ul>
&lt;li>第一个脚本找到包含字符串 &lt;code>three&lt;/code> 的行，并将其从模式空间复制到保留空间，替换当前保留空间中的任何内容。&lt;/li>
&lt;li>第二个脚本删除包含字符串 &lt;code>three&lt;/code> 的任何行。这样就完成了与文字处理器或文本编辑器中的 剪切 动作等效的功能。&lt;/li>
&lt;li>最后一个脚本找到包含字符串 &lt;code>two&lt;/code> 的行，并将保留空间的内容_追加_到模式空间，然后打印模式空间。&lt;/li>
&lt;/ul>
&lt;p>任务完成。&lt;/p>
&lt;h3 id="使用-sed-编写脚本">使用 sed 编写脚本&lt;/h3>
&lt;p>再说一次，使用单独的脚本语句纯粹是为了视觉和心理上的简单。剪切和粘贴命令作为一个脚本同样有效：&lt;/p>
&lt;div class="highlight">&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;">&lt;code class="language-bash" data-lang="bash">&lt;span style="display:flex;">&lt;span>$ sed -n -e &lt;span style="color:#e6db74">&amp;#39;/three/ h ; /three/ d ; /two/ G ; p&amp;#39;&lt;/span> example.txt
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>Line one
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>Line two
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>Line three
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>&lt;p>它甚至可以写在一个专门的脚本文件中：&lt;/p>
&lt;div class="highlight">&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;">&lt;code class="language-bash" data-lang="bash">&lt;span style="display:flex;">&lt;span>&lt;span style="color:#75715e">#!/usr/bin/sed -nf
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#75715e">&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>/three/h
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>/three/d
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>/two/ G
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>p
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>&lt;p>要运行该脚本，将其加入可执行权限，然后用示例文件尝试：&lt;/p>
&lt;div class="highlight">&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;">&lt;code class="language-bash" data-lang="bash">&lt;span style="display:flex;">&lt;span>$ chmod +x myscript.sed
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>$ ./myscript.sed example.txt
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>Line one
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>Line two
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>Line three
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>&lt;p>当然，你需要解析的文本越可预测，则使用 sed 解决问题越容易。发明 sed 操作（例如复制和粘贴）的“配方”通常是不切实际的，因为触发操作的条件可能因文件而异。但是，你对 sed 命令的使用越熟练，就越容易根据需要解析的输入来设计复杂的动作。&lt;/p>
&lt;p>重要的事情是识别不同的操作，了解 sed 何时移至下一行，并预测模式和保留空间包含的内容。&lt;/p>
&lt;p>sed 很复杂。虽然它只有十几个命令，但它灵活的语法和原生功能意味着它充满了无限的潜力。&lt;/p>
&lt;h3 id="参考">参考&lt;/h3>
&lt;p>How to use the Linux sed command &lt;a href="https://opensource.com/article/21/3/sed-cheat-sheet">[1]&lt;/a>&lt;/p>
&lt;p>使用 sed 命令进行复制、剪切和粘贴 &lt;a href="https://linux.cn/article-13417-1.html">[2]&lt;/a>&lt;/p></description></item><item><title>一杯咖啡</title><link>https://blog.baicai.me/donations/</link><pubDate>Wed, 19 May 2021 19:15:33 +0800</pubDate><author>admin@baicai.me (白菜)</author><guid>https://blog.baicai.me/donations/</guid><description>&lt;p>请扫下方二维码打赏一杯咖啡。&lt;/p>
&lt;pre>&lt;code>多少不重要，1元也是支持
&lt;/code>&lt;/pre></description></item><item><title>Swift语法全面解析</title><link>https://blog.baicai.me/article/2021/swift-basic-syntax/</link><pubDate>Thu, 13 May 2021 21:31:19 +0800</pubDate><author>admin@baicai.me (白菜)</author><guid>https://blog.baicai.me/article/2021/swift-basic-syntax/</guid><description>&lt;h3 id="swift介绍">Swift介绍&lt;/h3>
&lt;p>Swift 是一门开发 iOS, macOS, watchOS 和 tvOS 应用的新语言。
swift 是一种安全，快速和互动的编程语言。
swift 支持代码预览（playgrounds），这个特性可以允许程序员在不编译和运行应用程序的前提下运行 Swift 代码并实时查看结果。&lt;/p>
&lt;p>Swift 通过采用现代编程模式来避免大量常见编程错误：&lt;/p>
&lt;ul>
&lt;li>变量始终在使用前初始化。&lt;/li>
&lt;li>检查数组索引超出范围的错误。&lt;/li>
&lt;li>检查整数是否溢出。&lt;/li>
&lt;li>可选值确保明确处理 nil 值。&lt;/li>
&lt;li>内存被自动管理。&lt;/li>
&lt;li>错误处理允许从意外故障控制恢复。&lt;/li>
&lt;/ul>
&lt;h3 id="基础部分">基础部分&lt;/h3>
&lt;h4 id="常量和变量">常量和变量&lt;/h4>
&lt;p>声明常量和变量， 常量和变量必须在使用前声明，使用 let 来声明常量，使用 var 来声明变量。
示例：&lt;/p>
&lt;div class="highlight">&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;">&lt;code class="language-swift" data-lang="swift">&lt;span style="display:flex;">&lt;span>&lt;span style="color:#66d9ef">let&lt;/span> maximumNumberOfLoginAttempts = &lt;span style="color:#ae81ff">10&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#66d9ef">var&lt;/span> currentLoginAttempt = &lt;span style="color:#ae81ff">0&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#75715e">// 类型注解&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#66d9ef">var&lt;/span> welcomeMessage: String
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>&lt;h4 id="注释">注释&lt;/h4>
&lt;p>单行注释双正斜杠（//）， 多行注释（/* 多行的 */）。Swift 的多行注释可以嵌套在其它的多行注释之中。
示例：&lt;/p>
&lt;div class="highlight">&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;">&lt;code class="language-swift" data-lang="swift">&lt;span style="display:flex;">&lt;span>&lt;span style="color:#75715e">// 这是一个注释&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#75715e">/* 这也是一个注释，
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#75715e">但是是多行的 */&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#75715e">/* 这是第一个多行注释的开头
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#75715e">/* 这是第二个被嵌套的多行注释 */
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#75715e">这是第一个多行注释的结尾 */&lt;/span>
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>&lt;h4 id="分号">分号&lt;/h4>
&lt;p>Swift 并不强制要求你在每条语句的结尾处使用分号（;）。
同一行内写多条独立的语句必须用分号分隔。&lt;/p>
&lt;div class="highlight">&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;">&lt;code class="language-swift" data-lang="swift">&lt;span style="display:flex;">&lt;span>&lt;span style="color:#66d9ef">let&lt;/span> cat = &lt;span style="color:#e6db74">&amp;#34;🐱&amp;#34;&lt;/span>; print(cat)
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#75715e">// 输出“🐱”&lt;/span>
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>&lt;h4 id="标识符">标识符&lt;/h4>
&lt;p>标识符就是给变量、常量、方法、函数、枚举、结构体、类、协议等指定的名字。构成标识符的字母均有一定的规范，Swift语言中标识符的命名规则如下：&lt;/p>
&lt;ul>
&lt;li>
&lt;p>区分大小写，Myname与myname是两个不同的标识符；&lt;/p>
&lt;/li>
&lt;li>
&lt;p>标识符首字符可以以下划线（_）或者字母开始，但不能是数字；&lt;/p>
&lt;/li>
&lt;li>
&lt;p>标识符中其他字符可以是下划线（_）、字母或数字。&lt;/p>
&lt;/li>
&lt;/ul>
&lt;p>例如： userName、User_Name、_sys_val、身高等为合法的标识符，而2mail、room#和class为非法的标识符。&lt;/p>
&lt;p>注意:Swift中的字母采用的是Unicode编码。Unicode叫做统一编码制，它包含了亚洲文字编码，如中文、日文、韩文等字符，甚至是我们在聊天工具中使用的表情符号&lt;/p>
&lt;p>如果一定要使用关键字作为标识符，可以在关键字前后添加重音符号（`），例如：&lt;/p>
&lt;div class="highlight">&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;">&lt;code class="language-swift" data-lang="swift">&lt;span style="display:flex;">&lt;span>&lt;span style="color:#66d9ef">let&lt;/span> `&lt;span style="color:#66d9ef">class&lt;/span>` = &lt;span style="color:#e6db74">&amp;#34;xiaobai&amp;#34;&lt;/span>
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>&lt;h4 id="关键字">关键字&lt;/h4>
&lt;p>关键字是类似于标识符的保留字符序列，除非用重音符号（`）将其括起来，否则不能用作标识符。关键字是对编译器具有特殊意义的预定义保留标识符。常见的关键字有以下4种。
&lt;strong>与声明有关的关键字&lt;/strong>&lt;/p>
&lt;pre>&lt;code>class deinit enum extension
func import init internal
let operator private protocol
public static struct subscript
typealias var
&lt;/code>&lt;/pre>
&lt;p>&lt;strong>与语句有关的关键字&lt;/strong>&lt;/p>
&lt;pre>&lt;code>break case continue default
do else fallthrough for
if in return switch
where while
&lt;/code>&lt;/pre>
&lt;p>&lt;strong>表达式和类型关键字&lt;/strong>&lt;/p>
&lt;pre>&lt;code>as dynamicType false is
nil self Self super
true _COLUMN_ _FILE_ _FUNCTION_
_LINE_
&lt;/code>&lt;/pre>
&lt;p>&lt;strong>在特定上下文中使用的关键字&lt;/strong>&lt;/p>
&lt;pre>&lt;code>associativity convenience dynamic didSet
final get infix inout
lazy left mutating none
nonmutating optional override postfix
precedence prefix Protocol required
right set Type unowned
weak willSet
&lt;/code>&lt;/pre>
&lt;h4 id="swift-空格">Swift 空格&lt;/h4>
&lt;p>Swift对空格的使用有一定的要求。
在Swift中，运算符不能直接跟在变量或常量的后面。例如下面的代码会报错：&lt;/p>
&lt;div class="highlight">&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;">&lt;code class="language-swift" data-lang="swift">&lt;span style="display:flex;">&lt;span>&lt;span style="color:#66d9ef">let&lt;/span> a= &lt;span style="color:#ae81ff">1&lt;/span> &lt;span style="color:#f92672">+&lt;/span> &lt;span style="color:#ae81ff">2&lt;/span>
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>&lt;p>错误信息是：&lt;/p>
&lt;p>&lt;code>error: prefix/postfix '=' is reserved&lt;/code>&lt;/p>
&lt;p>意思大概是等号直接跟在前面或后面这种用法是保留的。&lt;/p>
&lt;p>下面的代码还是会报错（继续注意空格）：&lt;/p>
&lt;div class="highlight">&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;">&lt;code class="language-swift" data-lang="swift">&lt;span style="display:flex;">&lt;span>&lt;span style="color:#66d9ef">let&lt;/span> a = &lt;span style="color:#ae81ff">1&lt;/span>&lt;span style="color:#f92672">+&lt;/span> &lt;span style="color:#ae81ff">2&lt;/span>
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>&lt;p>错误信息是：&lt;/p>
&lt;p>&lt;code>error: consecutive statements on a line must be separated by ';'&lt;/code>&lt;/p>
&lt;p>这是因为Swift认为到1+这个语句就结束了，2就是下一个语句了。&lt;/p>
&lt;p>只有这样写才不会报错：&lt;/p>
&lt;div class="highlight">&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;">&lt;code class="language-swift" data-lang="swift">&lt;span style="display:flex;">&lt;span>&lt;span style="color:#66d9ef">let&lt;/span> a = &lt;span style="color:#ae81ff">1&lt;/span> &lt;span style="color:#f92672">+&lt;/span> &lt;span style="color:#ae81ff">2&lt;/span>; &lt;span style="color:#75715e">// 编码规范推荐使用这种写法&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#66d9ef">let&lt;/span> b = &lt;span style="color:#ae81ff">3&lt;/span>&lt;span style="color:#f92672">+&lt;/span>&lt;span style="color:#ae81ff">4&lt;/span> &lt;span style="color:#75715e">// 这样也是OK的&lt;/span>
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>&lt;h4 id="整数浮点数">整数、浮点数&lt;/h4>
&lt;p>统一使用 Int 可以提高代码的可复用性，避免不同类型数字之间的转换， 并且匹配数字的类型推断。
示例：&lt;/p>
&lt;div class="highlight">&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;">&lt;code class="language-swift" data-lang="swift">&lt;span style="display:flex;">&lt;span>&lt;span style="color:#66d9ef">let&lt;/span> minValue = UInt8.min &lt;span style="color:#75715e">// minValue 为 0，是 UInt8 类型&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#66d9ef">let&lt;/span> maxValue = UInt8.max &lt;span style="color:#75715e">// maxValue 为 255，是 UInt8 类型&lt;/span>
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>&lt;h4 id="类型安全和类型推断">类型安全和类型推断&lt;/h4>
&lt;p>Swift 是一门类型安全的语言，这意味着 Swift 可以让你清楚地知道值的类型。
如果你没有显式指定类型，Swift 会使用类型推断来选择合适的类型。（int、double）。
示例：&lt;/p>
&lt;div class="highlight">&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;">&lt;code class="language-swift" data-lang="swift">&lt;span style="display:flex;">&lt;span>&lt;span style="color:#66d9ef">let&lt;/span> meaningOfLife = &lt;span style="color:#ae81ff">42&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#75715e">// meaningOfLife 会被推测为 Int 类型&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#66d9ef">let&lt;/span> pi = &lt;span style="color:#ae81ff">3.14159&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#75715e">// pi 会被推测为 Double 类型&lt;/span>
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>&lt;h4 id="数值型字面量数值型类型转换">数值型字面量、数值型类型转换&lt;/h4>
&lt;p>示例：&lt;/p>
&lt;div class="highlight">&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;">&lt;code class="language-swift" data-lang="swift">&lt;span style="display:flex;">&lt;span>&lt;span style="color:#66d9ef">let&lt;/span> decimalInteger = &lt;span style="color:#ae81ff">17&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#66d9ef">let&lt;/span> binaryInteger = &lt;span style="color:#ae81ff">0b10001&lt;/span> &lt;span style="color:#75715e">// 二进制的17&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#66d9ef">let&lt;/span> octalInteger = &lt;span style="color:#ae81ff">0o21&lt;/span> &lt;span style="color:#75715e">// 八进制的17&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#66d9ef">let&lt;/span> hexadecimalInteger = &lt;span style="color:#ae81ff">0x11&lt;/span> &lt;span style="color:#75715e">// 十六进制的17&lt;/span>
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>&lt;h4 id="类型别名">类型别名&lt;/h4>
&lt;p>类型别名（type aliases）就是给现有类型定义另一个名字。你可以使用 typealias 关键字来定义类型别名。
示例：&lt;/p>
&lt;div class="highlight">&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;">&lt;code class="language-swift" data-lang="swift">&lt;span style="display:flex;">&lt;span>&lt;span style="color:#66d9ef">typealias&lt;/span> AudioSample = UInt16
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#66d9ef">var&lt;/span> maxAmplitudeFound = AudioSample.min
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#75715e">// maxAmplitudeFound 现在是 0&lt;/span>
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>&lt;h4 id="布尔值">布尔值&lt;/h4>
&lt;p>示例：&lt;/p>
&lt;div class="highlight">&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;">&lt;code class="language-swift" data-lang="swift">&lt;span style="display:flex;">&lt;span>&lt;span style="color:#66d9ef">let&lt;/span> orangesAreOrange = &lt;span style="color:#66d9ef">true&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#66d9ef">let&lt;/span> turnipsAreDelicious = &lt;span style="color:#66d9ef">false&lt;/span>
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>&lt;h4 id="元组">元组&lt;/h4>
&lt;p>元组（tuples）把多个值组合成一个复合值。元组内的值可以是任意类型，并不要求是相同类型。
示例：&lt;/p>
&lt;div class="highlight">&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;">&lt;code class="language-swift" data-lang="swift">&lt;span style="display:flex;">&lt;span>&lt;span style="color:#66d9ef">let&lt;/span> http404Error = (&lt;span style="color:#ae81ff">404&lt;/span>, &lt;span style="color:#e6db74">&amp;#34;Not Found&amp;#34;&lt;/span>)
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#75715e">// http404Error 的类型是 (Int, String)，值是 (404, &amp;#34;Not Found&amp;#34;)&lt;/span>
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>&lt;h4 id="可选类型">可选类型&lt;/h4>
&lt;p>使用可选类型（optionals）来处理值可能缺失的情况。可选类型表示两种可能：或者有值， 你可以解析可选类型访问这个值， 或者根本没有值。
示例：&lt;/p>
&lt;div class="highlight">&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;">&lt;code class="language-swift" data-lang="swift">&lt;span style="display:flex;">&lt;span>&lt;span style="color:#66d9ef">var&lt;/span> serverResponseCode: Int? = &lt;span style="color:#ae81ff">404&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#75715e">// serverResponseCode 包含一个可选的 Int 值 404&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>serverResponseCode = &lt;span style="color:#66d9ef">nil&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#75715e">// serverResponseCode 现在不包含值&lt;/span>
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>&lt;h4 id="错误处理">错误处理&lt;/h4>
&lt;p>错误处理，应对程序执行中可能会遇到的错误条件。
示例：&lt;/p>
&lt;div class="highlight">&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;">&lt;code class="language-swift" data-lang="swift">&lt;span style="display:flex;">&lt;span>&lt;span style="color:#66d9ef">func&lt;/span> &lt;span style="color:#a6e22e">makeASandwich&lt;/span>() &lt;span style="color:#66d9ef">throws&lt;/span> {
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#75715e">// ...&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>}
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#66d9ef">do&lt;/span> {
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#66d9ef">try&lt;/span> makeASandwich()
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> eatASandwich()
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>} &lt;span style="color:#66d9ef">catch&lt;/span> SandwichError.outOfCleanDishes {
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> washDishes()
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>} &lt;span style="color:#66d9ef">catch&lt;/span> SandwichError.missingIngredients(&lt;span style="color:#66d9ef">let&lt;/span> ingredients) {
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> buyGroceries(ingredients)
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>}
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>&lt;h4 id="断言和先决条件">断言和先决条件&lt;/h4>
&lt;p>断言和先决条件，是在运行时所做的检查。&lt;/p>
&lt;div class="highlight">&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;">&lt;code class="language-swift" data-lang="swift">&lt;span style="display:flex;">&lt;span>&lt;span style="color:#66d9ef">let&lt;/span> age = &lt;span style="color:#f92672">-&lt;/span>&lt;span style="color:#ae81ff">3&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>assert(age &lt;span style="color:#f92672">&amp;gt;=&lt;/span> &lt;span style="color:#ae81ff">0&lt;/span>, &lt;span style="color:#e6db74">&amp;#34;A person&amp;#39;s age cannot be less than zero&amp;#34;&lt;/span>)
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#75715e">// 因为 age &amp;lt; 0，所以断言会触发&lt;/span>
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>&lt;h4 id="基本运算符">基本运算符&lt;/h4>
&lt;p>&lt;code>Swift 支持大部分标准 C 语言的运算符，还提供了 C 语言没有的区间运算符，例如 a..&amp;lt;b 或 a...b。&lt;/code>
&lt;strong>赋值运算符，算术运算符，组合赋值运算符，比较运算符，三元运算符，空合运算符，区间运算符，逻辑运算符&lt;/strong>&lt;/p>
&lt;p>运算符分为一元、二元和三元运算符。
闭区间运算符（a&amp;hellip;b）定义一个包含从 a 到 b（包括 a 和 b）的所有值的区间。
半开区间运算符（a..&amp;lt;b）定义一个从 a 到 b 但不包括 b 的区间。
闭区间操作符有另一个表达形式，可以表达往一侧无限延伸的区间，(a&amp;hellip;，&amp;hellip;b)。
示例：&lt;/p>
&lt;div class="highlight">&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;">&lt;code class="language-swift" data-lang="swift">&lt;span style="display:flex;">&lt;span>&lt;span style="color:#66d9ef">let&lt;/span> names = [&lt;span style="color:#e6db74">&amp;#34;Anna&amp;#34;&lt;/span>, &lt;span style="color:#e6db74">&amp;#34;Alex&amp;#34;&lt;/span>, &lt;span style="color:#e6db74">&amp;#34;Brian&amp;#34;&lt;/span>, &lt;span style="color:#e6db74">&amp;#34;Jack&amp;#34;&lt;/span>]
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#66d9ef">let&lt;/span> count = names.count
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#66d9ef">for&lt;/span> i &lt;span style="color:#66d9ef">in&lt;/span> &lt;span style="color:#ae81ff">0.&lt;/span>.&amp;lt;count {
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> print(&lt;span style="color:#e6db74">&amp;#34;第 &lt;/span>&lt;span style="color:#e6db74">\(&lt;/span>i &lt;span style="color:#f92672">+&lt;/span> &lt;span style="color:#ae81ff">1&lt;/span>&lt;span style="color:#e6db74">)&lt;/span>&lt;span style="color:#e6db74"> 个人叫 &lt;/span>&lt;span style="color:#e6db74">\(&lt;/span>names[i]&lt;span style="color:#e6db74">)&lt;/span>&lt;span style="color:#e6db74">&amp;#34;&lt;/span>)
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>}
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#75715e">// 第 1 个人叫 Anna&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#75715e">// 第 2 个人叫 Alex&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#75715e">// 第 3 个人叫 Brian&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#75715e">// 第 4 个人叫 Jack&lt;/span>
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>&lt;h4 id="字符串和字符">字符串和字符&lt;/h4>
&lt;p>&lt;strong>字符串字面量，字符串插值，计算字符数量，访问和修改字符串，子字符串，比较字符串&lt;/strong>&lt;/p>
&lt;p>初始化空字符串，字符串可变性，字符串是值类型，连接字符串和字符(+，+=)。
使用字符，可通过 for-in 循环来遍历字符串，获取字符串中每一个字符的值。
字符串插值是一种构建新字符串的方式，可以在其中包含常量、变量、字面量和表达式。可以在已有字符串中插入常量、变量、字面量和表达式从而形成更长的字符串。
Swift 提供了三种方式来比较文本值：字符串字符相等、前缀相等和后缀相等。
示例：&lt;/p>
&lt;div class="highlight">&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;">&lt;code class="language-swift" data-lang="swift">&lt;span style="display:flex;">&lt;span>&lt;span style="color:#75715e">// 多行字符串字面量&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#66d9ef">let&lt;/span> quotation = &lt;span style="color:#e6db74">&amp;#34;&amp;#34;&amp;#34;
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#e6db74">The White Rabbit put on his spectacles. &amp;#34;&lt;/span>Where shall I begin,
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>please your Majesty?&lt;span style="color:#e6db74">&amp;#34; he asked.
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#e6db74">
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#e6db74">&amp;#34;&lt;/span>Begin at the beginning,&lt;span style="color:#e6db74">&amp;#34; the King said gravely, &amp;#34;&lt;/span>and go on
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>till you come to the end; then stop.&lt;span style="color:#e6db74">&amp;#34;
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#e6db74">&amp;#34;&amp;#34;&amp;#34;&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#75715e">// 下面两个字符串其实是一样的&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#66d9ef">let&lt;/span> singleLineString = &lt;span style="color:#e6db74">&amp;#34;These are the same.&amp;#34;&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#66d9ef">let&lt;/span> multilineString = &lt;span style="color:#e6db74">&amp;#34;&amp;#34;&amp;#34;
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#e6db74">These are the same.
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#e6db74">&amp;#34;&amp;#34;&amp;#34;&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#75715e">// 字符串插值&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#66d9ef">let&lt;/span> multiplier = &lt;span style="color:#ae81ff">3&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#66d9ef">let&lt;/span> message = &lt;span style="color:#e6db74">&amp;#34;&lt;/span>&lt;span style="color:#e6db74">\(&lt;/span>multiplier&lt;span style="color:#e6db74">)&lt;/span>&lt;span style="color:#e6db74"> times 2.5 is &lt;/span>&lt;span style="color:#e6db74">\(&lt;/span>Double&lt;span style="color:#e6db74">(&lt;/span>multiplier&lt;span style="color:#e6db74">)&lt;/span> &lt;span style="color:#f92672">*&lt;/span> &lt;span style="color:#ae81ff">2.5&lt;/span>&lt;span style="color:#e6db74">)&lt;/span>&lt;span style="color:#e6db74">&amp;#34;&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#75715e">// message 是 &amp;#34;3 times 2.5 is 7.5&amp;#34;&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#75715e">// 计算字符数量&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#66d9ef">var&lt;/span> word = &lt;span style="color:#e6db74">&amp;#34;cafe&amp;#34;&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>print(&lt;span style="color:#e6db74">&amp;#34;the number of characters in &lt;/span>&lt;span style="color:#e6db74">\(&lt;/span>word&lt;span style="color:#e6db74">)&lt;/span>&lt;span style="color:#e6db74"> is &lt;/span>&lt;span style="color:#e6db74">\(&lt;/span>word.count&lt;span style="color:#e6db74">)&lt;/span>&lt;span style="color:#e6db74">&amp;#34;&lt;/span>)
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#75715e">// 打印输出“the number of characters in cafe is 4”&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#66d9ef">var&lt;/span> emptyString = &lt;span style="color:#e6db74">&amp;#34;&amp;#34;&lt;/span> &lt;span style="color:#75715e">// 空字符串字面量&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#66d9ef">var&lt;/span> anotherEmptyString = String() &lt;span style="color:#75715e">// 初始化方法&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#75715e">// 两个字符串均为空并等价。&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#66d9ef">let&lt;/span> catCharacters: [Character] = [&lt;span style="color:#e6db74">&amp;#34;C&amp;#34;&lt;/span>, &lt;span style="color:#e6db74">&amp;#34;a&amp;#34;&lt;/span>, &lt;span style="color:#e6db74">&amp;#34;t&amp;#34;&lt;/span>, &lt;span style="color:#e6db74">&amp;#34;!&amp;#34;&lt;/span>]
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#66d9ef">let&lt;/span> catString = String(catCharacters)
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>print(catString)
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#75715e">// 打印输出：“Cat!”&lt;/span>
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>&lt;h4 id="集合类型">集合类型&lt;/h4>
&lt;p>Swift 语言提供数组（Array）、集合（Set）和字典（Dictionary）三种基本的集合类型用来存储集合数据。数组是有序数据的集。集合是无序无重复数据的集。字典是无序的键值对的集。
&lt;strong>集合的可变性，数组（Arrays），集合（Sets），集合操作，字典&lt;/strong>&lt;/p>
&lt;p>数组使用有序列表存储同一类型的多个值。相同的值可以多次出现在一个数组的不同位置中。
集合用来存储相同类型并且没有确定顺序的值。当集合元素顺序不重要时或者希望确保每个元素只出现一次时可以使用集合而不是数组。
集合操作，可以高效地完成集合的一些基本操作，比如把两个集合组合到一起，判断两个集合共有元素，或者判断两个集合是否全包含，部分包含或者不相交。
字典是一种无序的集合，它存储的是键值对之间的关系，其所有键的值需要是相同的类型，所有值的类型也需要相同。每个值（value）都关联唯一的键（key），键作为字典中这个值数据的标识符。
示例：&lt;/p>
&lt;div class="highlight">&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;">&lt;code class="language-swift" data-lang="swift">&lt;span style="display:flex;">&lt;span>&lt;span style="color:#75715e">// 集合&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#66d9ef">var&lt;/span> someInts = [Int]()
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>print(&lt;span style="color:#e6db74">&amp;#34;someInts is of type [Int] with &lt;/span>&lt;span style="color:#e6db74">\(&lt;/span>someInts.count&lt;span style="color:#e6db74">)&lt;/span>&lt;span style="color:#e6db74"> items.&amp;#34;&lt;/span>)
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#75715e">// 打印“someInts is of type [Int] with 0 items.”&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#66d9ef">var&lt;/span> threeDoubles = Array(repeating: &lt;span style="color:#ae81ff">0.0&lt;/span>, count: &lt;span style="color:#ae81ff">3&lt;/span>)
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#75715e">// threeDoubles 是一种 [Double] 数组，等价于 [0.0, 0.0, 0.0]&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#66d9ef">var&lt;/span> anotherThreeDoubles = Array(repeating: &lt;span style="color:#ae81ff">2.5&lt;/span>, count: &lt;span style="color:#ae81ff">3&lt;/span>)
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#75715e">// anotherThreeDoubles 被推断为 [Double]，等价于 [2.5, 2.5, 2.5]&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#66d9ef">var&lt;/span> sixDoubles = threeDoubles &lt;span style="color:#f92672">+&lt;/span> anotherThreeDoubles
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#75715e">// sixDoubles 被推断为 [Double]，等价于 [0.0, 0.0, 0.0, 2.5, 2.5, 2.5]&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#75715e">// enumerated() 方法遍历数组&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#66d9ef">var&lt;/span> shoppingList: [String] = [&lt;span style="color:#e6db74">&amp;#34;Eggs&amp;#34;&lt;/span>, &lt;span style="color:#e6db74">&amp;#34;Milk&amp;#34;&lt;/span>]
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#66d9ef">for&lt;/span> (index, value) &lt;span style="color:#66d9ef">in&lt;/span> shoppingList.enumerated() {
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> print(&lt;span style="color:#e6db74">&amp;#34;Item &lt;/span>&lt;span style="color:#e6db74">\(&lt;/span>String&lt;span style="color:#e6db74">(&lt;/span>index &lt;span style="color:#f92672">+&lt;/span> &lt;span style="color:#ae81ff">1&lt;/span>&lt;span style="color:#e6db74">))&lt;/span>&lt;span style="color:#e6db74">: &lt;/span>&lt;span style="color:#e6db74">\(&lt;/span>value&lt;span style="color:#e6db74">)&lt;/span>&lt;span style="color:#e6db74">&amp;#34;&lt;/span>)
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>}
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>&lt;h4 id="控制流">控制流&lt;/h4>
&lt;p>&lt;strong>For-In 循环，While 循环（Repeat-While），条件语句，控制转移语句，提前退出（guard），检测 API 可用性&lt;/strong>&lt;/p>
&lt;p>像 if 语句一样，guard 的执行取决于一个表达式的布尔值。我们可以使用 guard 语句来要求条件必须为真时，以执行 guard 语句后的代码。不同于 if 语句，一个 guard 语句总是有一个 else 从句，如果条件不为真则执行 else 从句中的代码。
Swift 内置支持检查 API 可用性，编译器使用 SDK 中的可用信息来验证我们的代码中使用的所有 API 在项目指定的部署目标上是否可用。如果我们尝试使用一个不可用的 API，Swift 会在编译时报错。
示例：&lt;/p>
&lt;div class="highlight">&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;">&lt;code class="language-swift" data-lang="swift">&lt;span style="display:flex;">&lt;span>&lt;span style="color:#66d9ef">let&lt;/span> names = [&lt;span style="color:#e6db74">&amp;#34;Anna&amp;#34;&lt;/span>, &lt;span style="color:#e6db74">&amp;#34;Alex&amp;#34;&lt;/span>, &lt;span style="color:#e6db74">&amp;#34;Brian&amp;#34;&lt;/span>, &lt;span style="color:#e6db74">&amp;#34;Jack&amp;#34;&lt;/span>]
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#66d9ef">for&lt;/span> name &lt;span style="color:#66d9ef">in&lt;/span> names {
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> print(&lt;span style="color:#e6db74">&amp;#34;Hello, &lt;/span>&lt;span style="color:#e6db74">\(&lt;/span>name&lt;span style="color:#e6db74">)&lt;/span>&lt;span style="color:#e6db74">!&amp;#34;&lt;/span>)
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>}
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#66d9ef">let&lt;/span> numberOfLegs = [&lt;span style="color:#e6db74">&amp;#34;spider&amp;#34;&lt;/span>: &lt;span style="color:#ae81ff">8&lt;/span>, &lt;span style="color:#e6db74">&amp;#34;ant&amp;#34;&lt;/span>: &lt;span style="color:#ae81ff">6&lt;/span>, &lt;span style="color:#e6db74">&amp;#34;cat&amp;#34;&lt;/span>: &lt;span style="color:#ae81ff">4&lt;/span>]
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#66d9ef">for&lt;/span> (animalName, legCount) &lt;span style="color:#66d9ef">in&lt;/span> numberOfLegs {
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> print(&lt;span style="color:#e6db74">&amp;#34;&lt;/span>&lt;span style="color:#e6db74">\(&lt;/span>animalName&lt;span style="color:#e6db74">)&lt;/span>&lt;span style="color:#e6db74">s have &lt;/span>&lt;span style="color:#e6db74">\(&lt;/span>legCount&lt;span style="color:#e6db74">)&lt;/span>&lt;span style="color:#e6db74"> legs&amp;#34;&lt;/span>)
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>}
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#75715e">// repeat-while 循环的一般格式&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#66d9ef">repeat&lt;/span> {
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> statements
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>} &lt;span style="color:#66d9ef">while&lt;/span> condition
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#75715e">// 提前退出&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#66d9ef">func&lt;/span> &lt;span style="color:#a6e22e">greet&lt;/span>(person: [String: String]) {
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#66d9ef">guard&lt;/span> &lt;span style="color:#66d9ef">let&lt;/span> name = person[&lt;span style="color:#e6db74">&amp;#34;name&amp;#34;&lt;/span>] &lt;span style="color:#66d9ef">else&lt;/span> {
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#66d9ef">return&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> }
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> print(&lt;span style="color:#e6db74">&amp;#34;Hello &lt;/span>&lt;span style="color:#e6db74">\(&lt;/span>name&lt;span style="color:#e6db74">)&lt;/span>&lt;span style="color:#e6db74">!&amp;#34;&lt;/span>)
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#66d9ef">guard&lt;/span> &lt;span style="color:#66d9ef">let&lt;/span> location = person[&lt;span style="color:#e6db74">&amp;#34;location&amp;#34;&lt;/span>] &lt;span style="color:#66d9ef">else&lt;/span> {
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> print(&lt;span style="color:#e6db74">&amp;#34;I hope the weather is nice near you.&amp;#34;&lt;/span>)
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#66d9ef">return&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> }
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> print(&lt;span style="color:#e6db74">&amp;#34;I hope the weather is nice in &lt;/span>&lt;span style="color:#e6db74">\(&lt;/span>location&lt;span style="color:#e6db74">)&lt;/span>&lt;span style="color:#e6db74">.&amp;#34;&lt;/span>)
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>}
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>greet(person: [&lt;span style="color:#e6db74">&amp;#34;name&amp;#34;&lt;/span>: &lt;span style="color:#e6db74">&amp;#34;John&amp;#34;&lt;/span>])
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#75715e">// 输出“Hello John!”&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#75715e">// 输出“I hope the weather is nice near you.”&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>greet(person: [&lt;span style="color:#e6db74">&amp;#34;name&amp;#34;&lt;/span>: &lt;span style="color:#e6db74">&amp;#34;Jane&amp;#34;&lt;/span>, &lt;span style="color:#e6db74">&amp;#34;location&amp;#34;&lt;/span>: &lt;span style="color:#e6db74">&amp;#34;Cupertino&amp;#34;&lt;/span>])
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#75715e">// 输出“Hello Jane!”&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#75715e">// 输出“I hope the weather is nice in Cupertino.”&lt;/span>
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>&lt;h4 id="函数">函数&lt;/h4>
&lt;p>&lt;strong>函数的定义与调用，函数参数与返回值，函数参数标签和参数名称，函数类型，嵌套函数&lt;/strong>&lt;/p>
&lt;p>可选元组返回类型。
定义一个输入输出参数时，在参数定义前加 inout 关键字。
示例：&lt;/p>
&lt;div class="highlight">&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;">&lt;code class="language-swift" data-lang="swift">&lt;span style="display:flex;">&lt;span>&lt;span style="color:#75715e">// 函数&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#66d9ef">func&lt;/span> &lt;span style="color:#a6e22e">greet&lt;/span>(person: String) -&amp;gt; String {
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#66d9ef">let&lt;/span> greeting = &lt;span style="color:#e6db74">&amp;#34;Hello, &amp;#34;&lt;/span> &lt;span style="color:#f92672">+&lt;/span> person &lt;span style="color:#f92672">+&lt;/span> &lt;span style="color:#e6db74">&amp;#34;!&amp;#34;&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#66d9ef">return&lt;/span> greeting
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>}
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#66d9ef">func&lt;/span> &lt;span style="color:#a6e22e">greet&lt;/span>(person: String, from hometown: String) -&amp;gt; String {
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#66d9ef">return&lt;/span> &lt;span style="color:#e6db74">&amp;#34;Hello &lt;/span>&lt;span style="color:#e6db74">\(&lt;/span>person&lt;span style="color:#e6db74">)&lt;/span>&lt;span style="color:#e6db74">! Glad you could visit from &lt;/span>&lt;span style="color:#e6db74">\(&lt;/span>hometown&lt;span style="color:#e6db74">)&lt;/span>&lt;span style="color:#e6db74">.&amp;#34;&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>}
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>print(greet(person: &lt;span style="color:#e6db74">&amp;#34;Bill&amp;#34;&lt;/span>, from: &lt;span style="color:#e6db74">&amp;#34;Cupertino&amp;#34;&lt;/span>))
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#75715e">// 打印“Hello Bill! Glad you could visit from Cupertino.”&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#75715e">// 可选元组返回类型&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#66d9ef">func&lt;/span> &lt;span style="color:#a6e22e">minMax&lt;/span>(array: [Int]) -&amp;gt; (min: Int, max: Int)? {
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#66d9ef">if&lt;/span> array.isEmpty { &lt;span style="color:#66d9ef">return&lt;/span> &lt;span style="color:#66d9ef">nil&lt;/span> }
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#66d9ef">var&lt;/span> currentMin = array[&lt;span style="color:#ae81ff">0&lt;/span>]
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#66d9ef">var&lt;/span> currentMax = array[&lt;span style="color:#ae81ff">0&lt;/span>]
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#66d9ef">for&lt;/span> value &lt;span style="color:#66d9ef">in&lt;/span> array[&lt;span style="color:#ae81ff">1.&lt;/span>.&amp;lt;array.count] {
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#66d9ef">if&lt;/span> value &lt;span style="color:#f92672">&amp;lt;&lt;/span> currentMin {
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> currentMin = value
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> } &lt;span style="color:#66d9ef">else&lt;/span> &lt;span style="color:#66d9ef">if&lt;/span> value &lt;span style="color:#f92672">&amp;gt;&lt;/span> currentMax {
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> currentMax = value
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> }
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> }
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#66d9ef">return&lt;/span> (currentMin, currentMax)
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>}
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#75715e">// 隐式返回的函数&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#66d9ef">func&lt;/span> &lt;span style="color:#a6e22e">greeting&lt;/span>(&lt;span style="color:#66d9ef">for&lt;/span> person: String) -&amp;gt; String {
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#e6db74">&amp;#34;Hello, &amp;#34;&lt;/span> &lt;span style="color:#f92672">+&lt;/span> person &lt;span style="color:#f92672">+&lt;/span> &lt;span style="color:#e6db74">&amp;#34;!&amp;#34;&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>}
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>print(greeting(&lt;span style="color:#66d9ef">for&lt;/span>: &lt;span style="color:#e6db74">&amp;#34;Dave&amp;#34;&lt;/span>))
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#75715e">// 打印 &amp;#34;Hello, Dave!&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#75715e">// 参数标签&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#66d9ef">func&lt;/span> &lt;span style="color:#a6e22e">greet&lt;/span>(person: String, from hometown: String) -&amp;gt; String {
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#66d9ef">return&lt;/span> &lt;span style="color:#e6db74">&amp;#34;Hello &lt;/span>&lt;span style="color:#e6db74">\(&lt;/span>person&lt;span style="color:#e6db74">)&lt;/span>&lt;span style="color:#e6db74">! Glad you could visit from &lt;/span>&lt;span style="color:#e6db74">\(&lt;/span>hometown&lt;span style="color:#e6db74">)&lt;/span>&lt;span style="color:#e6db74">.&amp;#34;&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>}
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>print(greet(person: &lt;span style="color:#e6db74">&amp;#34;Bill&amp;#34;&lt;/span>, from: &lt;span style="color:#e6db74">&amp;#34;Cupertino&amp;#34;&lt;/span>))
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#75715e">// 打印“Hello Bill! Glad you could visit from Cupertino.”&lt;/span>
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>&lt;h4 id="闭包">闭包&lt;/h4>
&lt;p>闭包是自包含的函数代码块，可以在代码中被传递和使用。与一些编程语言中的匿名函数（Lambdas）比较相似。
&lt;strong>闭包表达式，尾随闭包，值捕获，闭包是引用类型，逃逸闭包（@escaping），自动闭包&lt;/strong>&lt;/p>
&lt;p>如果你需要将一个很长的闭包表达式作为最后一个参数传递给函数，将这个闭包替换成为尾随闭包的形式很有用。
闭包可以在其被定义的上下文中捕获常量或变量。即使定义这些常量和变量的原作用域已经不存在，闭包仍然可以在闭包函数体内引用和修改这些值。
示例：&lt;/p>
&lt;div class="highlight">&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;">&lt;code class="language-swift" data-lang="swift">&lt;span style="display:flex;">&lt;span>&lt;span style="color:#75715e">// 闭包表达式语法&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>{ (parameters) -&amp;gt; &lt;span style="color:#66d9ef">return&lt;/span> type &lt;span style="color:#66d9ef">in&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> statements
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>}
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#75715e">// 尾随闭包&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#66d9ef">let&lt;/span> digitNames = [
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#ae81ff">0&lt;/span>: &lt;span style="color:#e6db74">&amp;#34;Zero&amp;#34;&lt;/span>, &lt;span style="color:#ae81ff">1&lt;/span>: &lt;span style="color:#e6db74">&amp;#34;One&amp;#34;&lt;/span>, &lt;span style="color:#ae81ff">2&lt;/span>: &lt;span style="color:#e6db74">&amp;#34;Two&amp;#34;&lt;/span>, &lt;span style="color:#ae81ff">3&lt;/span>: &lt;span style="color:#e6db74">&amp;#34;Three&amp;#34;&lt;/span>, &lt;span style="color:#ae81ff">4&lt;/span>: &lt;span style="color:#e6db74">&amp;#34;Four&amp;#34;&lt;/span>,
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#ae81ff">5&lt;/span>: &lt;span style="color:#e6db74">&amp;#34;Five&amp;#34;&lt;/span>, &lt;span style="color:#ae81ff">6&lt;/span>: &lt;span style="color:#e6db74">&amp;#34;Six&amp;#34;&lt;/span>, &lt;span style="color:#ae81ff">7&lt;/span>: &lt;span style="color:#e6db74">&amp;#34;Seven&amp;#34;&lt;/span>, &lt;span style="color:#ae81ff">8&lt;/span>: &lt;span style="color:#e6db74">&amp;#34;Eight&amp;#34;&lt;/span>, &lt;span style="color:#ae81ff">9&lt;/span>: &lt;span style="color:#e6db74">&amp;#34;Nine&amp;#34;&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>]
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#66d9ef">let&lt;/span> numbers = [&lt;span style="color:#ae81ff">16&lt;/span>, &lt;span style="color:#ae81ff">58&lt;/span>, &lt;span style="color:#ae81ff">510&lt;/span>]
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#66d9ef">let&lt;/span> strings = numbers.map {
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> (number) -&amp;gt; String &lt;span style="color:#66d9ef">in&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#66d9ef">var&lt;/span> number = number
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#66d9ef">var&lt;/span> output = &lt;span style="color:#e6db74">&amp;#34;&amp;#34;&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#66d9ef">repeat&lt;/span> {
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> output = digitNames[number &lt;span style="color:#f92672">%&lt;/span> &lt;span style="color:#ae81ff">10&lt;/span>]&lt;span style="color:#f92672">!&lt;/span> &lt;span style="color:#f92672">+&lt;/span> output
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> number &lt;span style="color:#f92672">/=&lt;/span> &lt;span style="color:#ae81ff">10&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> } &lt;span style="color:#66d9ef">while&lt;/span> number &lt;span style="color:#f92672">&amp;gt;&lt;/span> &lt;span style="color:#ae81ff">0&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#66d9ef">return&lt;/span> output
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>}
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#75715e">// strings 常量被推断为字符串类型数组，即 [String]&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#75715e">// 其值为 [&amp;#34;OneSix&amp;#34;, &amp;#34;FiveEight&amp;#34;, &amp;#34;FiveOneZero&amp;#34;]&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#75715e">// 值捕获&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#66d9ef">func&lt;/span> &lt;span style="color:#a6e22e">makeIncrementer&lt;/span>(forIncrement amount: Int) -&amp;gt; () -&amp;gt; Int {
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#66d9ef">var&lt;/span> runningTotal = &lt;span style="color:#ae81ff">0&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#66d9ef">func&lt;/span> &lt;span style="color:#a6e22e">incrementer&lt;/span>() -&amp;gt; Int {
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> runningTotal &lt;span style="color:#f92672">+=&lt;/span> amount
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#66d9ef">return&lt;/span> runningTotal
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> }
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#66d9ef">return&lt;/span> incrementer
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>}
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#75715e">// 自动闭包，延迟求值&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#66d9ef">var&lt;/span> customersInLine = [&lt;span style="color:#e6db74">&amp;#34;Chris&amp;#34;&lt;/span>, &lt;span style="color:#e6db74">&amp;#34;Alex&amp;#34;&lt;/span>, &lt;span style="color:#e6db74">&amp;#34;Ewa&amp;#34;&lt;/span>, &lt;span style="color:#e6db74">&amp;#34;Barry&amp;#34;&lt;/span>, &lt;span style="color:#e6db74">&amp;#34;Daniella&amp;#34;&lt;/span>]
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>print(customersInLine.count)
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#75715e">// 打印出“5”&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#66d9ef">let&lt;/span> customerProvider = { customersInLine.remove(at: &lt;span style="color:#ae81ff">0&lt;/span>) }
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>print(customersInLine.count)
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#75715e">// 打印出“5”&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>print(&lt;span style="color:#e6db74">&amp;#34;Now serving &lt;/span>&lt;span style="color:#e6db74">\(&lt;/span>customerProvider&lt;span style="color:#e6db74">())&lt;/span>&lt;span style="color:#e6db74">!&amp;#34;&lt;/span>)
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#75715e">// Prints &amp;#34;Now serving Chris!&amp;#34;&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>print(customersInLine.count)
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#75715e">// 打印出“4”&lt;/span>
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>&lt;h4 id="枚举">枚举&lt;/h4>
&lt;p>使用 enum 关键词来创建枚举并且把它们的整个定义放在一对大括号内。
&lt;strong>枚举语法，使用 Switch 语句匹配枚举值，枚举成员的遍历，关联值，原始值（默认值），递归枚举（indirect）&lt;/strong>&lt;/p>
&lt;p>可以定义 Swift 枚举来存储任意类型的关联值，每个枚举成员的关联值类型可以各不相同。
示例：&lt;/p>
&lt;div class="highlight">&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;">&lt;code class="language-swift" data-lang="swift">&lt;span style="display:flex;">&lt;span>&lt;span style="color:#75715e">// 枚举语法&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#66d9ef">enum&lt;/span> &lt;span style="color:#a6e22e">SomeEnumeration&lt;/span> {
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#75715e">// 枚举定义放在这里&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>}
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#66d9ef">enum&lt;/span> &lt;span style="color:#a6e22e">CompassPoint&lt;/span> {
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#66d9ef">case&lt;/span> north
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#66d9ef">case&lt;/span> south
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#66d9ef">case&lt;/span> east
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#66d9ef">case&lt;/span> west
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>}
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#66d9ef">enum&lt;/span> &lt;span style="color:#a6e22e">Planet&lt;/span> {
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#66d9ef">case&lt;/span> mercury, venus, earth, mars, jupiter, saturn, uranus, neptune
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>}
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#66d9ef">let&lt;/span> somePlanet = Planet.earth
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#66d9ef">switch&lt;/span> somePlanet {
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#66d9ef">case&lt;/span> .earth:
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> print(&lt;span style="color:#e6db74">&amp;#34;Mostly harmless&amp;#34;&lt;/span>)
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#66d9ef">default&lt;/span>:
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> print(&lt;span style="color:#e6db74">&amp;#34;Not a safe place for humans&amp;#34;&lt;/span>)
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>}
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#75715e">// 打印“Mostly harmless”&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#75715e">// 关联值&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#66d9ef">enum&lt;/span> &lt;span style="color:#a6e22e">Barcode&lt;/span> {
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#66d9ef">case&lt;/span> upc(Int, Int, Int, Int)
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#66d9ef">case&lt;/span> qrCode(String)
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>}
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#66d9ef">var&lt;/span> productBarcode = Barcode.upc(&lt;span style="color:#ae81ff">8&lt;/span>, &lt;span style="color:#ae81ff">85909&lt;/span>, &lt;span style="color:#ae81ff">51226&lt;/span>, &lt;span style="color:#ae81ff">3&lt;/span>)
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>productBarcode = .qrCode(&lt;span style="color:#e6db74">&amp;#34;ABCDEFGHIJKLMNOP&amp;#34;&lt;/span>)
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#66d9ef">switch&lt;/span> productBarcode {
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#66d9ef">case&lt;/span> &lt;span style="color:#66d9ef">let&lt;/span> .upc(numberSystem, manufacturer, product, check):
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> print(&lt;span style="color:#e6db74">&amp;#34;UPC: &lt;/span>&lt;span style="color:#e6db74">\(&lt;/span>numberSystem&lt;span style="color:#e6db74">)&lt;/span>&lt;span style="color:#e6db74">, &lt;/span>&lt;span style="color:#e6db74">\(&lt;/span>manufacturer&lt;span style="color:#e6db74">)&lt;/span>&lt;span style="color:#e6db74">, &lt;/span>&lt;span style="color:#e6db74">\(&lt;/span>product&lt;span style="color:#e6db74">)&lt;/span>&lt;span style="color:#e6db74">, &lt;/span>&lt;span style="color:#e6db74">\(&lt;/span>check&lt;span style="color:#e6db74">)&lt;/span>&lt;span style="color:#e6db74">.&amp;#34;&lt;/span>)
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#66d9ef">case&lt;/span> &lt;span style="color:#66d9ef">let&lt;/span> .qrCode(productCode):
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> print(&lt;span style="color:#e6db74">&amp;#34;QR code: &lt;/span>&lt;span style="color:#e6db74">\(&lt;/span>productCode&lt;span style="color:#e6db74">)&lt;/span>&lt;span style="color:#e6db74">.&amp;#34;&lt;/span>)
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>}
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#75715e">// 打印“QR code: ABCDEFGHIJKLMNOP.”&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#75715e">// 递归枚举&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#66d9ef">indirect&lt;/span> &lt;span style="color:#66d9ef">enum&lt;/span> &lt;span style="color:#a6e22e">ArithmeticExpression&lt;/span> {
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#66d9ef">case&lt;/span> number(Int)
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#66d9ef">case&lt;/span> addition(ArithmeticExpression, ArithmeticExpression)
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#66d9ef">case&lt;/span> multiplication(ArithmeticExpression, ArithmeticExpression)
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>}
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#66d9ef">let&lt;/span> five = ArithmeticExpression.number(&lt;span style="color:#ae81ff">5&lt;/span>)
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#66d9ef">let&lt;/span> four = ArithmeticExpression.number(&lt;span style="color:#ae81ff">4&lt;/span>)
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#66d9ef">let&lt;/span> sum = ArithmeticExpression.addition(five, four)
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#66d9ef">let&lt;/span> product = ArithmeticExpression.multiplication(sum, ArithmeticExpression.number(&lt;span style="color:#ae81ff">2&lt;/span>))
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#75715e">// (5 + 4) * 2&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#66d9ef">func&lt;/span> &lt;span style="color:#a6e22e">evaluate&lt;/span>(&lt;span style="color:#66d9ef">_&lt;/span> expression: ArithmeticExpression) -&amp;gt; Int {
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#66d9ef">switch&lt;/span> expression {
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#66d9ef">case&lt;/span> &lt;span style="color:#66d9ef">let&lt;/span> .number(value):
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#66d9ef">return&lt;/span> value
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#66d9ef">case&lt;/span> &lt;span style="color:#66d9ef">let&lt;/span> .addition(&lt;span style="color:#66d9ef">left&lt;/span>, &lt;span style="color:#66d9ef">right&lt;/span>):
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#66d9ef">return&lt;/span> evaluate(&lt;span style="color:#66d9ef">left&lt;/span>) &lt;span style="color:#f92672">+&lt;/span> evaluate(&lt;span style="color:#66d9ef">right&lt;/span>)
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#66d9ef">case&lt;/span> &lt;span style="color:#66d9ef">let&lt;/span> .multiplication(&lt;span style="color:#66d9ef">left&lt;/span>, &lt;span style="color:#66d9ef">right&lt;/span>):
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#66d9ef">return&lt;/span> evaluate(&lt;span style="color:#66d9ef">left&lt;/span>) &lt;span style="color:#f92672">*&lt;/span> evaluate(&lt;span style="color:#66d9ef">right&lt;/span>)
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> }
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>}
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>print(evaluate(product))
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#75715e">// 打印“18”&lt;/span>
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>&lt;h4 id="结构体和类">结构体和类&lt;/h4>
&lt;p>&lt;strong>结构体和类对比，结构体和枚举是值类型，类是引用类型&lt;/strong>&lt;/p>
&lt;p>结构体和类作为一种通用而又灵活的结构，成为了人们构建代码的基础。你可以使用定义常量、变量和函数的语法，为你的结构体和类定义属性、添加方法。
示例：&lt;/p>
&lt;div class="highlight">&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;">&lt;code class="language-swift" data-lang="swift">&lt;span style="display:flex;">&lt;span>&lt;span style="color:#75715e">// 类和结构体&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#66d9ef">struct&lt;/span> &lt;span style="color:#a6e22e">SomeStructure&lt;/span> {
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#75715e">// 在这里定义结构体&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>}
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#66d9ef">class&lt;/span> &lt;span style="color:#a6e22e">SomeClass&lt;/span> {
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#75715e">// 在这里定义类&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>}
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#66d9ef">struct&lt;/span> &lt;span style="color:#a6e22e">Resolution&lt;/span> {
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#66d9ef">var&lt;/span> width = &lt;span style="color:#ae81ff">0&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#66d9ef">var&lt;/span> height = &lt;span style="color:#ae81ff">0&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>}
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#66d9ef">class&lt;/span> &lt;span style="color:#a6e22e">VideoMode&lt;/span> {
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#66d9ef">var&lt;/span> resolution = Resolution()
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#66d9ef">var&lt;/span> interlaced = &lt;span style="color:#66d9ef">false&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#66d9ef">var&lt;/span> frameRate = &lt;span style="color:#ae81ff">0.0&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#66d9ef">var&lt;/span> name: String?
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>}
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>&lt;h4 id="属性">属性&lt;/h4>
&lt;p>&lt;strong>存储属性，计算属性，属性观察器，属性包装器，全局变量和局部变量，类型属性（static）&lt;/strong>&lt;/p>
&lt;p>属性将值与特定的类、结构体或枚举关联。存储属性会将常量和变量存储为实例的一部分，而计算属性则是直接计算（而不是存储）值。计算属性可以用于类、结构体和枚举，而存储属性只能用于类和结构体。
属性观察器监控和响应属性值的变化，每次属性被设置值的时候都会调用属性观察器，即使新值和当前值相同的时候也不例外。&lt;/p>
&lt;ul>
&lt;li>willSet 在新的值被设置之前调用&lt;/li>
&lt;li>didSet 在新的值被设置之后调用&lt;/li>
&lt;/ul>
&lt;p>属性包装器在管理属性如何存储和定义属性的代码之间添加了一个分隔层。
类型属性也是通过点运算符来访问。但是，类型属性是通过类型本身来访问，而不是通过实例。
示例：&lt;/p>
&lt;div class="highlight">&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;">&lt;code class="language-swift" data-lang="swift">&lt;span style="display:flex;">&lt;span>&lt;span style="color:#75715e">// 属性&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#66d9ef">struct&lt;/span> &lt;span style="color:#a6e22e">Point&lt;/span> {
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#66d9ef">var&lt;/span> x = &lt;span style="color:#ae81ff">0.0&lt;/span>, y = &lt;span style="color:#ae81ff">0.0&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>}
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#66d9ef">struct&lt;/span> &lt;span style="color:#a6e22e">Size&lt;/span> {
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#66d9ef">var&lt;/span> width = &lt;span style="color:#ae81ff">0.0&lt;/span>, height = &lt;span style="color:#ae81ff">0.0&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>}
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#66d9ef">struct&lt;/span> &lt;span style="color:#a6e22e">Rect&lt;/span> {
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#66d9ef">var&lt;/span> origin = Point()
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#66d9ef">var&lt;/span> size = Size() &lt;span style="color:#75715e">//存储属性&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#66d9ef">var&lt;/span> center: Point { &lt;span style="color:#75715e">//计算型属性&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#66d9ef">get&lt;/span> {
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#66d9ef">let&lt;/span> centerX = origin.x &lt;span style="color:#f92672">+&lt;/span> (size.width &lt;span style="color:#f92672">/&lt;/span> &lt;span style="color:#ae81ff">2&lt;/span>)
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#66d9ef">let&lt;/span> centerY = origin.y &lt;span style="color:#f92672">+&lt;/span> (size.height &lt;span style="color:#f92672">/&lt;/span> &lt;span style="color:#ae81ff">2&lt;/span>)
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#66d9ef">return&lt;/span> Point(x: centerX, y: centerY)
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> }
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#66d9ef">set&lt;/span>(newCenter) {
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> origin.x = newCenter.x &lt;span style="color:#f92672">-&lt;/span> (size.width &lt;span style="color:#f92672">/&lt;/span> &lt;span style="color:#ae81ff">2&lt;/span>)
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> origin.y = newCenter.y &lt;span style="color:#f92672">-&lt;/span> (size.height &lt;span style="color:#f92672">/&lt;/span> &lt;span style="color:#ae81ff">2&lt;/span>)
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> }
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> }
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>}
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#66d9ef">var&lt;/span> square = Rect(origin: Point(x: &lt;span style="color:#ae81ff">0.0&lt;/span>, y: &lt;span style="color:#ae81ff">0.0&lt;/span>),
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> size: Size(width: &lt;span style="color:#ae81ff">10.0&lt;/span>, height: &lt;span style="color:#ae81ff">10.0&lt;/span>))
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#66d9ef">let&lt;/span> initialSquareCenter = square.center
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>square.center = Point(x: &lt;span style="color:#ae81ff">15.0&lt;/span>, y: &lt;span style="color:#ae81ff">15.0&lt;/span>)
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>print(&lt;span style="color:#e6db74">&amp;#34;square.origin is now at (&lt;/span>&lt;span style="color:#e6db74">\(&lt;/span>square.origin.x&lt;span style="color:#e6db74">)&lt;/span>&lt;span style="color:#e6db74">, &lt;/span>&lt;span style="color:#e6db74">\(&lt;/span>square.origin.y&lt;span style="color:#e6db74">)&lt;/span>&lt;span style="color:#e6db74">)&amp;#34;&lt;/span>)
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#75715e">// 打印“square.origin is now at (10.0, 10.0)”&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#75715e">// 属性包装器&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>@propertyWrapper
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#66d9ef">struct&lt;/span> &lt;span style="color:#a6e22e">TwelveOrLess&lt;/span> {
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#66d9ef">private&lt;/span> &lt;span style="color:#66d9ef">var&lt;/span> number = &lt;span style="color:#ae81ff">0&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#66d9ef">var&lt;/span> wrappedValue: Int {
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#66d9ef">get&lt;/span> { &lt;span style="color:#66d9ef">return&lt;/span> number }
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#66d9ef">set&lt;/span> { number = min(newValue, &lt;span style="color:#ae81ff">12&lt;/span>) }
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> }
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>}
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>&lt;h4 id="方法">方法&lt;/h4>
&lt;p>&lt;strong>实例方法（Instance Methods），类型方法（static）&lt;/strong>&lt;/p>
&lt;p>方法是与某些特定类型相关联的函数。
类、结构体、枚举都可以定义实例方法；实例方法为给定类型的实例封装了具体的任务与功能。
类、结构体、枚举也可以定义类型方法；类型方法与类型本身相关联。
示例：&lt;/p>
&lt;div class="highlight">&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;">&lt;code class="language-swift" data-lang="swift">&lt;span style="display:flex;">&lt;span>&lt;span style="color:#75715e">// 方法&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#66d9ef">class&lt;/span> &lt;span style="color:#a6e22e">Counter&lt;/span> {
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#66d9ef">var&lt;/span> count = &lt;span style="color:#ae81ff">0&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#66d9ef">func&lt;/span> &lt;span style="color:#a6e22e">increment&lt;/span>() {
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> count &lt;span style="color:#f92672">+=&lt;/span> &lt;span style="color:#ae81ff">1&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> }
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#66d9ef">func&lt;/span> &lt;span style="color:#a6e22e">increment&lt;/span>(by amount: Int) {
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> count &lt;span style="color:#f92672">+=&lt;/span> amount
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> }
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#66d9ef">func&lt;/span> &lt;span style="color:#a6e22e">reset&lt;/span>() {
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> count = &lt;span style="color:#ae81ff">0&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> }
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>}
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>&lt;h4 id="下标">下标&lt;/h4>
&lt;p>下标可以定义在类、结构体和枚举中，是访问集合、列表或序列中元素的快捷方式
下标语法（subscript），下标用法，下标选项，类型下标（static）&lt;/p>
&lt;div class="highlight">&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;">&lt;code class="language-swift" data-lang="swift">&lt;span style="display:flex;">&lt;span>&lt;span style="color:#66d9ef">subscript&lt;/span>(index: Int) -&amp;gt; Int {
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#66d9ef">get&lt;/span> {
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#75715e">// 返回一个适当的 Int 类型的值&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> }
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#66d9ef">set&lt;/span>(newValue) {
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#75715e">// 执行适当的赋值操作&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> }
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>}
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#75715e">// 示例&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#66d9ef">struct&lt;/span> &lt;span style="color:#a6e22e">TimesTable&lt;/span> {
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#66d9ef">let&lt;/span> multiplier: Int
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#66d9ef">subscript&lt;/span>(index: Int) -&amp;gt; Int {
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#66d9ef">return&lt;/span> multiplier &lt;span style="color:#f92672">*&lt;/span> index
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> }
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>}
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#66d9ef">let&lt;/span> threeTimesTable = TimesTable(multiplier: &lt;span style="color:#ae81ff">3&lt;/span>)
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>print(&lt;span style="color:#e6db74">&amp;#34;six times three is &lt;/span>&lt;span style="color:#e6db74">\(&lt;/span>threeTimesTable[&lt;span style="color:#ae81ff">6&lt;/span>]&lt;span style="color:#e6db74">)&lt;/span>&lt;span style="color:#e6db74">&amp;#34;&lt;/span>)
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#75715e">// 打印“six times three is 18”&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#66d9ef">var&lt;/span> numberOfLegs = [&lt;span style="color:#e6db74">&amp;#34;spider&amp;#34;&lt;/span>: &lt;span style="color:#ae81ff">8&lt;/span>, &lt;span style="color:#e6db74">&amp;#34;ant&amp;#34;&lt;/span>: &lt;span style="color:#ae81ff">6&lt;/span>, &lt;span style="color:#e6db74">&amp;#34;cat&amp;#34;&lt;/span>: &lt;span style="color:#ae81ff">4&lt;/span>]
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>numberOfLegs[&lt;span style="color:#e6db74">&amp;#34;bird&amp;#34;&lt;/span>] = &lt;span style="color:#ae81ff">2&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#75715e">// 类型下标&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#66d9ef">enum&lt;/span> &lt;span style="color:#a6e22e">Planet&lt;/span>: Int {
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#66d9ef">case&lt;/span> mercury = &lt;span style="color:#ae81ff">1&lt;/span>, venus, earth, mars, jupiter, saturn, uranus, neptune
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#66d9ef">static&lt;/span> &lt;span style="color:#66d9ef">subscript&lt;/span>(n: Int) -&amp;gt; Planet {
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#66d9ef">return&lt;/span> Planet(rawValue: n)&lt;span style="color:#f92672">!&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> }
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>}
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#66d9ef">let&lt;/span> mars = Planet[&lt;span style="color:#ae81ff">4&lt;/span>]
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>print(mars)
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>&lt;h4 id="继承">继承&lt;/h4>
&lt;p>&lt;strong>定义一个基类，子类生成，重写(override)，防止重写(final)&lt;/strong>&lt;/p>
&lt;p>不继承于其它类的类，称之为基类。
示例：&lt;/p>
&lt;div class="highlight">&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;">&lt;code class="language-swift" data-lang="swift">&lt;span style="display:flex;">&lt;span>&lt;span style="color:#75715e">// 继承&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#66d9ef">class&lt;/span> &lt;span style="color:#a6e22e">SomeClass&lt;/span>: SomeSuperclass {
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#75715e">// 这里是子类的定义&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>}
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#66d9ef">class&lt;/span> &lt;span style="color:#a6e22e">Vehicle&lt;/span> {
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#66d9ef">var&lt;/span> currentSpeed = &lt;span style="color:#ae81ff">0.0&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#66d9ef">var&lt;/span> description: String {
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#66d9ef">return&lt;/span> &lt;span style="color:#e6db74">&amp;#34;traveling at &lt;/span>&lt;span style="color:#e6db74">\(&lt;/span>currentSpeed&lt;span style="color:#e6db74">)&lt;/span>&lt;span style="color:#e6db74"> miles per hour&amp;#34;&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> }
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#66d9ef">func&lt;/span> &lt;span style="color:#a6e22e">makeNoise&lt;/span>() {
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#75715e">// 什么也不做——因为车辆不一定会有噪音&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> }
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>}
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#66d9ef">class&lt;/span> &lt;span style="color:#a6e22e">Car&lt;/span>: Vehicle {
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#66d9ef">var&lt;/span> gear = &lt;span style="color:#ae81ff">1&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#66d9ef">override&lt;/span> &lt;span style="color:#66d9ef">var&lt;/span> description: String {
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#66d9ef">return&lt;/span> &lt;span style="color:#66d9ef">super&lt;/span>.description &lt;span style="color:#f92672">+&lt;/span> &lt;span style="color:#e6db74">&amp;#34; in gear &lt;/span>&lt;span style="color:#e6db74">\(&lt;/span>gear&lt;span style="color:#e6db74">)&lt;/span>&lt;span style="color:#e6db74">&amp;#34;&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> }
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>}
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#66d9ef">class&lt;/span> &lt;span style="color:#a6e22e">AutomaticCar&lt;/span>: Car {
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#66d9ef">override&lt;/span> &lt;span style="color:#66d9ef">var&lt;/span> currentSpeed: Double {
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#66d9ef">didSet&lt;/span> {
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> gear = Int(currentSpeed &lt;span style="color:#f92672">/&lt;/span> &lt;span style="color:#ae81ff">10.0&lt;/span>) &lt;span style="color:#f92672">+&lt;/span> &lt;span style="color:#ae81ff">1&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> }
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> }
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>}
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>&lt;h4 id="构造过程">构造过程&lt;/h4>
&lt;p>构造过程是使用类、结构体或枚举类型的实例之前的准备过程。
&lt;strong>存储属性的初始赋值，自定义构造过程，默认构造器，值类型的构造器代理，类的继承和构造过程，可失败构造器，必要构造器（required）&lt;/strong>&lt;/p>
&lt;p>构造器可以通过调用其它构造器来完成实例的部分构造过程。这一过程称为构造器代理，它能避免多个构造器间的代码重复。
Swift 为类类型提供了两种构造器来确保实例中所有存储型属性都能获得初始值，它们被称为指定构造器和便利构造器。
可以在一个类，结构体或是枚举类型的定义中，添加一个或多个可失败构造器。其语法为在 init 关键字后面添加问号（init?）。
必要构造器，在类的构造器前添加 required 修饰符表明所有该类的子类都必须实现该构造器。
示例：&lt;/p>
&lt;div class="highlight">&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;">&lt;code class="language-swift" data-lang="swift">&lt;span style="display:flex;">&lt;span>&lt;span style="color:#75715e">// 构造过程&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#66d9ef">init&lt;/span>() {
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#75715e">// 在此处执行构造过程&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>}
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#66d9ef">struct&lt;/span> &lt;span style="color:#a6e22e">Fahrenheit&lt;/span> {
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#66d9ef">var&lt;/span> temperature: Double
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#66d9ef">init&lt;/span>() {
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> temperature = &lt;span style="color:#ae81ff">32.0&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> }
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>}
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#66d9ef">var&lt;/span> f = Fahrenheit()
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>print(&lt;span style="color:#e6db74">&amp;#34;The default temperature is &lt;/span>&lt;span style="color:#e6db74">\(&lt;/span>f.temperature&lt;span style="color:#e6db74">)&lt;/span>&lt;span style="color:#e6db74">° Fahrenheit&amp;#34;&lt;/span>)
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#75715e">// 打印“The default temperature is 32.0° Fahrenheit”&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#66d9ef">struct&lt;/span> &lt;span style="color:#a6e22e">Color&lt;/span> {
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#66d9ef">let&lt;/span> red, green, blue: Double
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#66d9ef">init&lt;/span>(red: Double, green: Double, blue: Double) {
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#66d9ef">self&lt;/span>.red = red
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#66d9ef">self&lt;/span>.green = green
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#66d9ef">self&lt;/span>.blue = blue
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> }
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#66d9ef">init&lt;/span>(white: Double) {
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> red = white
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> green = white
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> blue = white
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> }
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>}
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>&lt;h4 id="析构过程">析构过程&lt;/h4>
&lt;p>析构器只适用于类类型，当一个类的实例被释放之前，析构器会被立即调用。析构器用关键字 deinit 来标示，类似于构造器要用 init 来标示。
Swift 会自动释放不再需要的实例以释放资源。
示例：&lt;/p>
&lt;div class="highlight">&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;">&lt;code class="language-swift" data-lang="swift">&lt;span style="display:flex;">&lt;span>&lt;span style="color:#75715e">// 析构过程&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#66d9ef">deinit&lt;/span> {
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#75715e">// 执行析构过程&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>}
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#66d9ef">class&lt;/span> &lt;span style="color:#a6e22e">Bank&lt;/span> {
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#66d9ef">static&lt;/span> &lt;span style="color:#66d9ef">var&lt;/span> coinsInBank = &lt;span style="color:#ae81ff">10_000&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#66d9ef">static&lt;/span> &lt;span style="color:#66d9ef">func&lt;/span> &lt;span style="color:#a6e22e">distribute&lt;/span>(coins numberOfCoinsRequested: Int) -&amp;gt; Int {
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#66d9ef">let&lt;/span> numberOfCoinsToVend = min(numberOfCoinsRequested, coinsInBank)
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> coinsInBank &lt;span style="color:#f92672">-=&lt;/span> numberOfCoinsToVend
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#66d9ef">return&lt;/span> numberOfCoinsToVend
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> }
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#66d9ef">static&lt;/span> &lt;span style="color:#66d9ef">func&lt;/span> &lt;span style="color:#a6e22e">receive&lt;/span>(coins: Int) {
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> coinsInBank &lt;span style="color:#f92672">+=&lt;/span> coins
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> }
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>}
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#66d9ef">class&lt;/span> &lt;span style="color:#a6e22e">Player&lt;/span> {
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#66d9ef">var&lt;/span> coinsInPurse: Int
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#66d9ef">init&lt;/span>(coins: Int) {
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> coinsInPurse = Bank.distribute(coins: coins)
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> }
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#66d9ef">func&lt;/span> &lt;span style="color:#a6e22e">win&lt;/span>(coins: Int) {
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> coinsInPurse &lt;span style="color:#f92672">+=&lt;/span> Bank.distribute(coins: coins)
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> }
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#66d9ef">deinit&lt;/span> {
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> Bank.receive(coins: coinsInPurse)
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> }
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>}
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>&lt;h4 id="可选链式调用">可选链式调用&lt;/h4>
&lt;p>可选链式调用是一种可以在当前值可能为 nil 的可选值上请求和调用属性、方法及下标的方法。
通过在想调用的属性、方法，或下标的可选值后面放一个问号（?），可以定义一个可选链。类似在可选值后面放一个叹号（!）来强制展开它的值。它们的主要区别在于当可选值为空时可选链式调用只会调用失败，然而强制展开将会触发运行时错误。
示例：&lt;/p>
&lt;div class="highlight">&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;">&lt;code class="language-swift" data-lang="swift">&lt;span style="display:flex;">&lt;span>&lt;span style="color:#66d9ef">class&lt;/span> &lt;span style="color:#a6e22e">Person&lt;/span> {
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#66d9ef">var&lt;/span> residence: Residence?
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>}
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#66d9ef">class&lt;/span> &lt;span style="color:#a6e22e">Residence&lt;/span> {
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#66d9ef">var&lt;/span> numberOfRooms = &lt;span style="color:#ae81ff">1&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>}
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#66d9ef">let&lt;/span> john = Person()
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#66d9ef">let&lt;/span> roomCount = john.residence!.numberOfRooms
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#75715e">// 这会引发运行时错误&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#66d9ef">if&lt;/span> &lt;span style="color:#66d9ef">let&lt;/span> roomCount = john.residence?.numberOfRooms {
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> print(&lt;span style="color:#e6db74">&amp;#34;John&amp;#39;s residence has &lt;/span>&lt;span style="color:#e6db74">\(&lt;/span>roomCount&lt;span style="color:#e6db74">)&lt;/span>&lt;span style="color:#e6db74"> room(s).&amp;#34;&lt;/span>)
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>} &lt;span style="color:#66d9ef">else&lt;/span> {
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> print(&lt;span style="color:#e6db74">&amp;#34;Unable to retrieve the number of rooms.&amp;#34;&lt;/span>)
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>}
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#75715e">// 打印“Unable to retrieve the number of rooms.”&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>john.residence = Residence()
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#66d9ef">if&lt;/span> &lt;span style="color:#66d9ef">let&lt;/span> roomCount = john.residence?.numberOfRooms {
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> print(&lt;span style="color:#e6db74">&amp;#34;John&amp;#39;s residence has &lt;/span>&lt;span style="color:#e6db74">\(&lt;/span>roomCount&lt;span style="color:#e6db74">)&lt;/span>&lt;span style="color:#e6db74"> room(s).&amp;#34;&lt;/span>)
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>} &lt;span style="color:#66d9ef">else&lt;/span> {
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> print(&lt;span style="color:#e6db74">&amp;#34;Unable to retrieve the number of rooms.&amp;#34;&lt;/span>)
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>}
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#75715e">// 打印“John&amp;#39;s residence has 1 room(s).”&lt;/span>
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>&lt;h4 id="错误处理-1">错误处理&lt;/h4>
&lt;p>错误处理（Error handling） 是响应错误以及从错误中恢复的过程。Swift 在运行时提供了抛出、捕获、传递和操作可恢复错误（recoverable errors）的一等支持。
&lt;strong>表示与抛出错误，处理错误，指定清理操作&lt;/strong>&lt;/p>
&lt;p>在 Swift 中，错误用遵循 Error 协议的类型的值来表示。
Swift 中有 4 种处理错误的方式。可以把函数抛出的错误传递给调用此函数的代码（throws）、用 do-catch 语句处理错误、将错误作为可选类型处理（try?）、或者断言此错误根本不会发生（try!）。
defer 语句将代码的执行延迟到当前的作用域退出之前。
示例：&lt;/p>
&lt;div class="highlight">&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;">&lt;code class="language-swift" data-lang="swift">&lt;span style="display:flex;">&lt;span>&lt;span style="color:#75715e">// 错误处理&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#66d9ef">enum&lt;/span> &lt;span style="color:#a6e22e">VendingMachineError&lt;/span>: Error {
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#66d9ef">case&lt;/span> invalidSelection &lt;span style="color:#75715e">//选择无效&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#66d9ef">case&lt;/span> insufficientFunds(coinsNeeded: Int) &lt;span style="color:#75715e">//金额不足&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#66d9ef">case&lt;/span> outOfStock &lt;span style="color:#75715e">//缺货&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>}
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#66d9ef">throw&lt;/span> VendingMachineError.insufficientFunds(coinsNeeded: &lt;span style="color:#ae81ff">5&lt;/span>)
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#66d9ef">var&lt;/span> vendingMachine = VendingMachine()
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>vendingMachine.coinsDeposited = &lt;span style="color:#ae81ff">8&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#66d9ef">do&lt;/span> {
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#66d9ef">try&lt;/span> buyFavoriteSnack(person: &lt;span style="color:#e6db74">&amp;#34;Alice&amp;#34;&lt;/span>, vendingMachine: vendingMachine)
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> print(&lt;span style="color:#e6db74">&amp;#34;Success! Yum.&amp;#34;&lt;/span>)
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>} &lt;span style="color:#66d9ef">catch&lt;/span> VendingMachineError.invalidSelection {
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> print(&lt;span style="color:#e6db74">&amp;#34;Invalid Selection.&amp;#34;&lt;/span>)
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>} &lt;span style="color:#66d9ef">catch&lt;/span> VendingMachineError.outOfStock {
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> print(&lt;span style="color:#e6db74">&amp;#34;Out of Stock.&amp;#34;&lt;/span>)
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>} &lt;span style="color:#66d9ef">catch&lt;/span> VendingMachineError.insufficientFunds(&lt;span style="color:#66d9ef">let&lt;/span> coinsNeeded) {
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> print(&lt;span style="color:#e6db74">&amp;#34;Insufficient funds. Please insert an additional &lt;/span>&lt;span style="color:#e6db74">\(&lt;/span>coinsNeeded&lt;span style="color:#e6db74">)&lt;/span>&lt;span style="color:#e6db74"> coins.&amp;#34;&lt;/span>)
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>} &lt;span style="color:#66d9ef">catch&lt;/span> {
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> print(&lt;span style="color:#e6db74">&amp;#34;Unexpected error: &lt;/span>&lt;span style="color:#e6db74">\(&lt;/span>error&lt;span style="color:#e6db74">)&lt;/span>&lt;span style="color:#e6db74">.&amp;#34;&lt;/span>)
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>}
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#75715e">// 打印“Insufficient funds. Please insert an additional 2 coins.”&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#75715e">// 指定清理操作&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#66d9ef">func&lt;/span> &lt;span style="color:#a6e22e">processFile&lt;/span>(filename: String) &lt;span style="color:#66d9ef">throws&lt;/span> {
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#66d9ef">if&lt;/span> exists(filename) {
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#66d9ef">let&lt;/span> file = open(filename)
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#66d9ef">defer&lt;/span> {
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> close(file)
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> }
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#66d9ef">while&lt;/span> &lt;span style="color:#66d9ef">let&lt;/span> line = &lt;span style="color:#66d9ef">try&lt;/span> file.readline() {
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#75715e">// 处理文件。&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> }
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#75715e">// close(file) 会在这里被调用，即作用域的最后。&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> }
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>}
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>&lt;h4 id="类型转换">类型转换&lt;/h4>
&lt;p>类型转换在 Swift 中使用 is 和 as 操作符实现。这两个操作符分别提供了一种简单达意的方式去检查值的类型或者转换它的类型。
&lt;strong>为类型转换定义类层次，检查类型（is），向下转型（as? 或 as!），Any 和 AnyObject 的类型转换&lt;/strong>&lt;/p>
&lt;p>可以将类型转换用在类和子类的层次结构上，检查特定类实例的类型并且转换这个类实例的类型成为这个层次结构中的其他类型。
Swift 为不确定类型提供了两种特殊的类型别名：&lt;/p>
&lt;ul>
&lt;li>
&lt;p>Any 可以表示任何类型，包括函数类型。&lt;/p>
&lt;/li>
&lt;li>
&lt;p>AnyObject 可以表示任何类类型的实例。&lt;/p>
&lt;/li>
&lt;/ul>
&lt;p>示例：&lt;/p>
&lt;div class="highlight">&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;">&lt;code class="language-swift" data-lang="swift">&lt;span style="display:flex;">&lt;span>&lt;span style="color:#75715e">// 类型转换&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#75715e">// 一个基类 MediaItem&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#66d9ef">class&lt;/span> &lt;span style="color:#a6e22e">MediaItem&lt;/span> {
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#66d9ef">var&lt;/span> name: String
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#66d9ef">init&lt;/span>(name: String) {
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#66d9ef">self&lt;/span>.name = name
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> }
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>}
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#66d9ef">class&lt;/span> &lt;span style="color:#a6e22e">Movie&lt;/span>: MediaItem {
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#66d9ef">var&lt;/span> director: String
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#66d9ef">init&lt;/span>(name: String, director: String) {
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#66d9ef">self&lt;/span>.director = director
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#66d9ef">super&lt;/span>.&lt;span style="color:#66d9ef">init&lt;/span>(name: name)
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> }
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>}
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#66d9ef">class&lt;/span> &lt;span style="color:#a6e22e">Song&lt;/span>: MediaItem {
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#66d9ef">var&lt;/span> artist: String
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#66d9ef">init&lt;/span>(name: String, artist: String) {
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#66d9ef">self&lt;/span>.srtist = artist
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#66d9ef">super&lt;/span>.&lt;span style="color:#66d9ef">init&lt;/span>(name: name)
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> }
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>}
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#66d9ef">let&lt;/span> library = [
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> Movie(name: &lt;span style="color:#e6db74">&amp;#34;Casablanca&amp;#34;&lt;/span>, director: &lt;span style="color:#e6db74">&amp;#34;Micheal Curtiz&amp;#34;&lt;/span>),
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> Song(name: &lt;span style="color:#e6db74">&amp;#34;Blue Suede Shose&amp;#34;&lt;/span>, artist: &lt;span style="color:#e6db74">&amp;#34;Elvis Presley&amp;#34;&lt;/span>),
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> Movie(name: &lt;span style="color:#e6db74">&amp;#34;Citizen Kane&amp;#34;&lt;/span>, director: &lt;span style="color:#e6db74">&amp;#34;Orson Wells&amp;#34;&lt;/span>),
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> Song(name: &lt;span style="color:#e6db74">&amp;#34;The One And Only&amp;#34;&lt;/span>, artist: &lt;span style="color:#e6db74">&amp;#34;Chesney Hawkes&amp;#34;&lt;/span>),
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> Song(name: &lt;span style="color:#e6db74">&amp;#34;Never Gonna Give You Up&amp;#34;&lt;/span>, artist: &lt;span style="color:#e6db74">&amp;#34;Rick Astley&amp;#34;&lt;/span>)
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>]
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#66d9ef">var&lt;/span> movieCount = &lt;span style="color:#ae81ff">0&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#66d9ef">var&lt;/span> songCount = &lt;span style="color:#ae81ff">0&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#66d9ef">for&lt;/span> item &lt;span style="color:#66d9ef">in&lt;/span> library {
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#66d9ef">if&lt;/span> item &lt;span style="color:#66d9ef">is&lt;/span> Movie {
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> movieCount &lt;span style="color:#f92672">+=&lt;/span> &lt;span style="color:#ae81ff">1&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> } &lt;span style="color:#66d9ef">else&lt;/span> &lt;span style="color:#66d9ef">if&lt;/span> item &lt;span style="color:#66d9ef">is&lt;/span> Song {
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> songCount &lt;span style="color:#f92672">+=&lt;/span> &lt;span style="color:#ae81ff">1&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> }
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>}
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>print(&lt;span style="color:#e6db74">&amp;#34;Media library contains &lt;/span>&lt;span style="color:#e6db74">\(&lt;/span>movieCount&lt;span style="color:#e6db74">)&lt;/span>&lt;span style="color:#e6db74"> movies and &lt;/span>&lt;span style="color:#e6db74">\(&lt;/span>songCount&lt;span style="color:#e6db74">)&lt;/span>&lt;span style="color:#e6db74">&amp;#34;&lt;/span>)
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#75715e">// 打印“Media library contains 2 movies and 3 songs”&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#66d9ef">for&lt;/span> item &lt;span style="color:#66d9ef">in&lt;/span> library {
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#66d9ef">if&lt;/span> &lt;span style="color:#66d9ef">let&lt;/span> movie = item &lt;span style="color:#66d9ef">as&lt;/span>? Movie {
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> print(&lt;span style="color:#e6db74">&amp;#34;Movie: &lt;/span>&lt;span style="color:#e6db74">\(&lt;/span>movie.name&lt;span style="color:#e6db74">)&lt;/span>&lt;span style="color:#e6db74">, dir. &lt;/span>&lt;span style="color:#e6db74">\(&lt;/span>movie.director&lt;span style="color:#e6db74">)&lt;/span>&lt;span style="color:#e6db74">&amp;#34;&lt;/span>)
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> } &lt;span style="color:#66d9ef">else&lt;/span> &lt;span style="color:#66d9ef">if&lt;/span> &lt;span style="color:#66d9ef">let&lt;/span> song = item &lt;span style="color:#66d9ef">as&lt;/span>? Song {
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> print(&lt;span style="color:#e6db74">&amp;#34;Song: &lt;/span>&lt;span style="color:#e6db74">\(&lt;/span>song.name&lt;span style="color:#e6db74">)&lt;/span>&lt;span style="color:#e6db74">, by &lt;/span>&lt;span style="color:#e6db74">\(&lt;/span>song.artist&lt;span style="color:#e6db74">)&lt;/span>&lt;span style="color:#e6db74">&amp;#34;&lt;/span>)
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> }
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>}
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#75715e">// Movie: Casablanca, dir. Michael Curtiz&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#75715e">// Song: Blue Suede Shoes, by Elvis Presley&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#75715e">// Movie: Citizen Kane, dir. Orson Welles&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#75715e">// Song: The One And Only, by Chesney Hawkes&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#75715e">// Song: Never Gonna Give You Up, by Rick Astley&lt;/span>
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>&lt;h4 id="嵌套类型">嵌套类型&lt;/h4>
&lt;p>Swift 允许定义嵌套类型，可以在支持的类型中定义嵌套的枚举、类和结构体。
&lt;strong>嵌套类型实践，引用嵌套类型&lt;/strong>&lt;/p>
&lt;p>要在一个类型中嵌套另一个类型，将嵌套类型的定义写在其外部类型的 {} 内，而且可以根据需要定义多级嵌套。
示例：&lt;/p>
&lt;div class="highlight">&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;">&lt;code class="language-swift" data-lang="swift">&lt;span style="display:flex;">&lt;span>&lt;span style="color:#75715e">// 嵌套类型&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>stuct BlackjackCard {
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#75715e">// 嵌套的 Suit 枚举&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#66d9ef">enum&lt;/span> &lt;span style="color:#a6e22e">Suit&lt;/span>: Character {
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#66d9ef">case&lt;/span> spades = &lt;span style="color:#e6db74">&amp;#34;1&amp;#34;&lt;/span>, hearts = &lt;span style="color:#e6db74">&amp;#34;2&amp;#34;&lt;/span>, diamonds = &lt;span style="color:#e6db74">&amp;#34;3&amp;#34;&lt;/span>, clubs = &lt;span style="color:#e6db74">&amp;#34;4&amp;#34;&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> }
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#75715e">// 嵌套的 Rank 枚举&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#66d9ef">enum&lt;/span> &lt;span style="color:#a6e22e">Rank&lt;/span>: Int {
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#66d9ef">case&lt;/span> two = &lt;span style="color:#ae81ff">2&lt;/span>, three, four, five, six, seven, eight, nine, ten
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#66d9ef">case&lt;/span> jack, queen, king, ace
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#66d9ef">struct&lt;/span> &lt;span style="color:#a6e22e">Values&lt;/span> {
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#66d9ef">let&lt;/span> first: Int, second: Int?
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> }
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#66d9ef">var&lt;/span> values: Values {
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#66d9ef">switch&lt;/span> &lt;span style="color:#66d9ef">self&lt;/span> {
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#66d9ef">case&lt;/span> .ace:
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#66d9ef">return&lt;/span> Values(first: &lt;span style="color:#ae81ff">1&lt;/span>, second: &lt;span style="color:#ae81ff">11&lt;/span>)
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#66d9ef">case&lt;/span> .jack, .queen, .king:
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#66d9ef">return&lt;/span> Values(first: &lt;span style="color:#ae81ff">10&lt;/span>, second: &lt;span style="color:#66d9ef">nil&lt;/span>)
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#66d9ef">default&lt;/span>:
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#66d9ef">return&lt;/span> Values(first: &lt;span style="color:#66d9ef">self&lt;/span>.rawValue, second: &lt;span style="color:#66d9ef">nil&lt;/span>)
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> }
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> }
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> }
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#75715e">// BlackjackCard 的属性和方法&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#66d9ef">let&lt;/span> rank: Rank, suit: Suit
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#66d9ef">var&lt;/span> description: String {
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#66d9ef">var&lt;/span> output = &lt;span style="color:#e6db74">&amp;#34;suit is &lt;/span>&lt;span style="color:#e6db74">\(&lt;/span>suit.rawValue&lt;span style="color:#e6db74">)&lt;/span>&lt;span style="color:#e6db74">,&amp;#34;&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> output &lt;span style="color:#f92672">+=&lt;/span> &lt;span style="color:#e6db74">&amp;#34; value is &lt;/span>&lt;span style="color:#e6db74">\(&lt;/span>rank.values.first&lt;span style="color:#e6db74">)&lt;/span>&lt;span style="color:#e6db74">&amp;#34;&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#66d9ef">if&lt;/span> &lt;span style="color:#66d9ef">let&lt;/span> second = rank.values.second {
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> output &lt;span style="color:#f92672">+=&lt;/span> &lt;span style="color:#e6db74">&amp;#34; or &lt;/span>&lt;span style="color:#e6db74">\(&lt;/span>second&lt;span style="color:#e6db74">)&lt;/span>&lt;span style="color:#e6db74">&amp;#34;&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> }
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#66d9ef">return&lt;/span> output
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> }
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>}
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#66d9ef">let&lt;/span> theAceOfSpades = BlackjackCard(rank: .ace, suit: .spades)
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>print(&lt;span style="color:#e6db74">&amp;#34;theAceOfSpades: &lt;/span>&lt;span style="color:#e6db74">\(&lt;/span>theAceOfSpades.description&lt;span style="color:#e6db74">)&lt;/span>&lt;span style="color:#e6db74">&amp;#34;&lt;/span>)
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#75715e">// 打印“theAceOfSpades: suit is 1, value is 1 or 11”&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#66d9ef">let&lt;/span> heartsSymbol = BlackjackCard.Suit.hearts.rawValue
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#75715e">// 2&lt;/span>
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>&lt;h4 id="扩展">扩展&lt;/h4>
&lt;p>扩展可以给一个现有的类，结构体，枚举，还有协议添加新的功能。
&lt;strong>扩展的语法，计算型属性，构造器，方法，下标，嵌套类型&lt;/strong>&lt;/p>
&lt;p>Swift 中的扩展可以：&lt;/p>
&lt;ul>
&lt;li>
&lt;p>添加计算型实例属性和计算型类属性&lt;/p>
&lt;/li>
&lt;li>
&lt;p>定义实例方法和类方法&lt;/p>
&lt;/li>
&lt;li>
&lt;p>提供新的构造器&lt;/p>
&lt;/li>
&lt;li>
&lt;p>定义下标&lt;/p>
&lt;/li>
&lt;li>
&lt;p>定义和使用新的嵌套类型&lt;/p>
&lt;/li>
&lt;li>
&lt;p>使已经存在的类型遵循（conform）一个协议&lt;/p>
&lt;/li>
&lt;/ul>
&lt;p>扩展语法:&lt;/p>
&lt;div class="highlight">&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;">&lt;code class="language-swift" data-lang="swift">&lt;span style="display:flex;">&lt;span>&lt;span style="color:#66d9ef">extension&lt;/span> &lt;span style="color:#a6e22e">SomeType&lt;/span> {
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#75715e">// 在这里给 SomeType 添加新的功能&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>}
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>&lt;p>扩展可以给现有类型添加计算型实例属性和计算型类属性。
扩展可以给现有的类型添加新的构造器。
扩展可以给现有类型添加新的实例方法和类方法。
扩展可以给现有的类型添加新的下标。
扩展可以给现有的类，结构体，还有枚举添加新的嵌套类型。
示例：&lt;/p>
&lt;div class="highlight">&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;">&lt;code class="language-swift" data-lang="swift">&lt;span style="display:flex;">&lt;span>&lt;span style="color:#75715e">// 扩展的语法&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#66d9ef">extension&lt;/span> &lt;span style="color:#a6e22e">SomeType&lt;/span> {
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#75715e">// 在这里给 SomeType 添加新的功能&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>}
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#75715e">// 添加一个或多个协议&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#66d9ef">extension&lt;/span> &lt;span style="color:#a6e22e">SomeType&lt;/span>: SomeProtocol, AnotherProtocol {
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#75715e">// 协议所需要的实现写在这里&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>}
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#66d9ef">struct&lt;/span> &lt;span style="color:#a6e22e">Size&lt;/span> {
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#66d9ef">var&lt;/span> width = &lt;span style="color:#ae81ff">0.0&lt;/span>, height = &lt;span style="color:#ae81ff">0.0&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>}
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#66d9ef">struct&lt;/span> &lt;span style="color:#a6e22e">Point&lt;/span> {
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#66d9ef">var&lt;/span> x = &lt;span style="color:#ae81ff">0.0&lt;/span>, y = &lt;span style="color:#ae81ff">0.0&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>}
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#66d9ef">struct&lt;/span> &lt;span style="color:#a6e22e">Rect&lt;/span> {
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#66d9ef">var&lt;/span> origin = Point()
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#66d9ef">var&lt;/span> size = Size()
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>}
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#66d9ef">extension&lt;/span> &lt;span style="color:#a6e22e">Rect&lt;/span> {
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#66d9ef">init&lt;/span>(center: Point, size: Size) {
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#66d9ef">let&lt;/span> originX = center.x &lt;span style="color:#f92672">-&lt;/span> (size.width &lt;span style="color:#f92672">/&lt;/span> &lt;span style="color:#ae81ff">2&lt;/span>)
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#66d9ef">let&lt;/span> originY = center.y &lt;span style="color:#f92672">-&lt;/span> (size.height &lt;span style="color:#f92672">/&lt;/span> &lt;span style="color:#ae81ff">3&lt;/span>)
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#66d9ef">self&lt;/span>.&lt;span style="color:#66d9ef">init&lt;/span>(origin: Point(x: originX, y: originY), size: size)
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> }
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>}
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#66d9ef">let&lt;/span> centerRect = Rect(center: Point(x: &lt;span style="color:#ae81ff">4.0&lt;/span>, y: &lt;span style="color:#ae81ff">4.0&lt;/span>),
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> size: Size(width: &lt;span style="color:#ae81ff">3.0&lt;/span>, height: &lt;span style="color:#ae81ff">3.0&lt;/span>))
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#75715e">// centerRect 的 origin 是 (2.5, 2.5) 并且它的 size 是 (3.0, 3.0)&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#66d9ef">extension&lt;/span> &lt;span style="color:#a6e22e">Int&lt;/span> {
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#66d9ef">func&lt;/span> &lt;span style="color:#a6e22e">repetitions&lt;/span>(task: () -&amp;gt; Void) {
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#66d9ef">for&lt;/span> &lt;span style="color:#66d9ef">_&lt;/span> &lt;span style="color:#66d9ef">in&lt;/span> &lt;span style="color:#ae81ff">0.&lt;/span>.&amp;lt;&lt;span style="color:#66d9ef">self&lt;/span> {
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> task()
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> }
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> }
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>}
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#ae81ff">3.&lt;/span>repetitions {
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> print(&lt;span style="color:#e6db74">&amp;#34;Hello!&amp;#34;&lt;/span>)
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>}
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#75715e">// Hello!&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#75715e">// Hello!&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#75715e">// Hello!&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#66d9ef">extension&lt;/span> &lt;span style="color:#a6e22e">Int&lt;/span> {
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#66d9ef">mutating&lt;/span> &lt;span style="color:#66d9ef">func&lt;/span> &lt;span style="color:#a6e22e">square&lt;/span>() {
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#66d9ef">self&lt;/span> = &lt;span style="color:#66d9ef">self&lt;/span> &lt;span style="color:#f92672">*&lt;/span> &lt;span style="color:#66d9ef">self&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> }
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>}
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#66d9ef">var&lt;/span> somtInt = &lt;span style="color:#ae81ff">3&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>someInt.square()
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#75715e">// someInt 现在是9&lt;/span>
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>&lt;h4 id="协议">协议&lt;/h4>
&lt;p>协议定义了一个蓝图，规定了用来实现某一特定任务或者功能的方法、属性，以及其他需要的东西。
类、结构体或枚举都可以遵循协议，并为协议定义的这些要求提供具体实现。
协议语法，属性要求，方法要求，异变方法要求，构造器要求，协议作为类型，委托，协议类型的集合，协议的继承，类专属的协议，协议合成，检查协议一致性，可选的协议要求，协议扩展，&lt;/p>
&lt;p>协议语法&lt;/p>
&lt;div class="highlight">&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;">&lt;code class="language-swift" data-lang="swift">&lt;span style="display:flex;">&lt;span>&lt;span style="color:#66d9ef">protocol&lt;/span> &lt;span style="color:#a6e22e">SomeProtocol&lt;/span> {
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#75715e">// 这里是协议的定义部分&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>}
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>&lt;p>协议可以要求遵循协议的类型提供特定名称和类型的实例属性或类型属性。
协议可以要求遵循协议的类型实现某些指定的实例方法或类方法。
在值类型（即结构体和枚举）的实例方法中，将 mutating 关键字作为方法的前缀，写在 func 关键字之前，表示可以在该方法中修改它所属的实例以及实例的任意属性的值。
协议可以要求遵循协议的类型实现指定的构造器。
委托是一种设计模式，它允许类或结构体将一些需要它们负责的功能委托给其他类型的实例。
示例：&lt;/p>
&lt;div class="highlight">&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;">&lt;code class="language-swift" data-lang="swift">&lt;span style="display:flex;">&lt;span>&lt;span style="color:#75715e">// 协议语法&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#66d9ef">protocol&lt;/span> &lt;span style="color:#a6e22e">SomeProtocol&lt;/span> {
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#75715e">// 这里是协议的定义部分&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>}
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#66d9ef">struct&lt;/span> &lt;span style="color:#a6e22e">SomeStructure&lt;/span>: FirstProtocol, AnotherProtocol {
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#75715e">// 这里是结构体的定义部分&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>}
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#66d9ef">class&lt;/span> &lt;span style="color:#a6e22e">SomeClass&lt;/span>: SomeSuperClass, FirstProtocol, AnotherProtocol {
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#75715e">// 这里是类的定义部分&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>}
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#66d9ef">protocol&lt;/span> &lt;span style="color:#a6e22e">SomeProtocol&lt;/span> {
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#66d9ef">var&lt;/span> mustBeSettable: Int { &lt;span style="color:#66d9ef">get&lt;/span> &lt;span style="color:#66d9ef">set&lt;/span> }
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#66d9ef">var&lt;/span> doesNotNeedToBeSettable: Int { &lt;span style="color:#66d9ef">get&lt;/span> }
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>}
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#66d9ef">protocol&lt;/span> &lt;span style="color:#a6e22e">AnotherProtocol&lt;/span> {
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#66d9ef">static&lt;/span> &lt;span style="color:#66d9ef">var&lt;/span> someTypeProperty: Int { &lt;span style="color:#66d9ef">get&lt;/span> &lt;span style="color:#66d9ef">set&lt;/span> }
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>}
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#66d9ef">protocol&lt;/span> &lt;span style="color:#a6e22e">FullyNamed&lt;/span> {
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#66d9ef">var&lt;/span> fullName: String { &lt;span style="color:#66d9ef">get&lt;/span> }
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>}
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#66d9ef">struct&lt;/span> &lt;span style="color:#a6e22e">person&lt;/span>: FullyNamed {
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#66d9ef">var&lt;/span> fullName: String
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>}
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#66d9ef">let&lt;/span> john = Person(fullName: &lt;span style="color:#e6db74">&amp;#34;John Appleseed&amp;#34;&lt;/span>)
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#75715e">// john.fullName 为 &amp;#34;John Appleseed&amp;#34;&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#66d9ef">class&lt;/span> &lt;span style="color:#a6e22e">Starship&lt;/span>: FullyNamed {
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#66d9ef">var&lt;/span> prefix: String?
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#66d9ef">var&lt;/span> name: String
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#66d9ef">init&lt;/span>(name: String, &lt;span style="color:#66d9ef">prefix&lt;/span>: String? = &lt;span style="color:#66d9ef">nil&lt;/span>) {
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#66d9ef">self&lt;/span>.name = name
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#66d9ef">self&lt;/span>.&lt;span style="color:#66d9ef">prefix&lt;/span> = &lt;span style="color:#66d9ef">prefix&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> }
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#66d9ef">var&lt;/span> fullName: String {
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#66d9ef">return&lt;/span> (&lt;span style="color:#66d9ef">prefix&lt;/span> &lt;span style="color:#f92672">!=&lt;/span> &lt;span style="color:#66d9ef">nil&lt;/span> ? &lt;span style="color:#66d9ef">prefix&lt;/span>! &lt;span style="color:#f92672">+&lt;/span> &lt;span style="color:#e6db74">&amp;#34; &amp;#34;&lt;/span> : &lt;span style="color:#e6db74">&amp;#34;&amp;#34;&lt;/span>) &lt;span style="color:#f92672">+&lt;/span> name
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> }
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>}
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#66d9ef">var&lt;/span> ncc1701 = Starship(name: &lt;span style="color:#e6db74">&amp;#34;Enterprise&amp;#34;&lt;/span>, &lt;span style="color:#66d9ef">prefix&lt;/span>: &lt;span style="color:#e6db74">&amp;#34;USS&amp;#34;&lt;/span>)
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#75715e">// ncc1701.fullName 为 &amp;#34;USS Enterprise&amp;#34;&lt;/span>
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>&lt;h4 id="泛型">泛型&lt;/h4>
&lt;p>泛型代码让你能根据自定义的需求，编写出适用于任意类型的、灵活可复用的函数及类型。
你可避免编写重复的代码，而是用一种清晰抽象的方式来表达代码的意图。
&lt;strong>泛型函数，类型参数，命名类型参数，泛型类型，泛型扩展，类型约束，关联类型&lt;/strong>&lt;/p>
&lt;p>示例：&lt;/p>
&lt;div class="highlight">&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;">&lt;code class="language-swift" data-lang="swift">&lt;span style="display:flex;">&lt;span>&lt;span style="color:#66d9ef">func&lt;/span> &lt;span style="color:#a6e22e">swapTwoInts&lt;/span>(&lt;span style="color:#66d9ef">_&lt;/span> a: &lt;span style="color:#66d9ef">inout&lt;/span> Int, &lt;span style="color:#66d9ef">_&lt;/span> b: &lt;span style="color:#66d9ef">inout&lt;/span> Int) {
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#66d9ef">let&lt;/span> temporaryA = a
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> a = b
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> b = temporaryA
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>}
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#66d9ef">func&lt;/span> &lt;span style="color:#a6e22e">swapTwoValues&lt;/span>&amp;lt;T&amp;gt;(&lt;span style="color:#66d9ef">_&lt;/span> a: &lt;span style="color:#66d9ef">inout&lt;/span> T, &lt;span style="color:#66d9ef">_&lt;/span> b: &lt;span style="color:#66d9ef">inout&lt;/span> T) {
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#66d9ef">let&lt;/span> temporaryA = a
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> a = b
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> b = temporaryA
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>}
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#66d9ef">func&lt;/span> &lt;span style="color:#a6e22e">swapTwoInts&lt;/span>(&lt;span style="color:#66d9ef">_&lt;/span> a: &lt;span style="color:#66d9ef">inout&lt;/span> Int, &lt;span style="color:#66d9ef">_&lt;/span> b: &lt;span style="color:#66d9ef">inout&lt;/span> Int)
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#66d9ef">func&lt;/span> &lt;span style="color:#a6e22e">swapTwoValues&lt;/span>&amp;lt;T&amp;gt;(&lt;span style="color:#66d9ef">_&lt;/span> a: &lt;span style="color:#66d9ef">inout&lt;/span> T, &lt;span style="color:#66d9ef">_&lt;/span> b: &lt;span style="color:#66d9ef">inout&lt;/span> T)
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#66d9ef">var&lt;/span> someInt = &lt;span style="color:#ae81ff">3&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#66d9ef">var&lt;/span> anotherInt = &lt;span style="color:#ae81ff">107&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>swapTwoValues(&amp;amp;someInt, &amp;amp;anotherInt)
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#75715e">// someInt 现在是 107，anotherInt 现在是 3&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#66d9ef">var&lt;/span> someString = &lt;span style="color:#e6db74">&amp;#34;hello&amp;#34;&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#66d9ef">var&lt;/span> anotherString = &lt;span style="color:#e6db74">&amp;#34;world&amp;#34;&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>swapTwoValues(&amp;amp;someString, &amp;amp;anotherString)
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#75715e">// someString 现在是“world”，anotherString 现在是“hello”&lt;/span>
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>&lt;h4 id="不透明类型">不透明类型&lt;/h4>
&lt;p>具有不透明返回类型的函数或方法会隐藏返回值的类型信息。
函数不再提供具体的类型作为返回类型，而是根据它支持的协议来描述返回值。
&lt;strong>不透明类型解决的问题，返回不透明类型，不透明类型和协议类型的区别&lt;/strong>&lt;/p>
&lt;p>在处理模块和调用代码之间的关系时，隐藏类型信息非常有用，因为返回的底层数据类型仍然可以保持私有。
不透明类型和泛型相反。不透明类型允许函数实现时，选择一个与调用代码无关的返回类型。
如果函数中有多个地方返回了不透明类型，那么所有可能的返回值都必须是同一类型。返回不透明类型和返回协议类型主要区别，就在于是否需要保证类型一致性。
一个不透明类型只能对应一个具体的类型，即便函数调用者并不能知道是哪一种类型；协议类型可以同时对应多个类型，只要它们都遵循同一协议。
示例：&lt;/p>
&lt;div class="highlight">&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;">&lt;code class="language-swift" data-lang="swift">&lt;span style="display:flex;">&lt;span>&lt;span style="color:#66d9ef">protocol&lt;/span> &lt;span style="color:#a6e22e">Shape&lt;/span> {
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#66d9ef">func&lt;/span> &lt;span style="color:#a6e22e">draw&lt;/span>() -&amp;gt; String
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>}
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#66d9ef">struct&lt;/span> &lt;span style="color:#a6e22e">Triangle&lt;/span>: Shape {
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#66d9ef">var&lt;/span> size: Int
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#66d9ef">func&lt;/span> &lt;span style="color:#a6e22e">draw&lt;/span>() -&amp;gt; String {
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#66d9ef">var&lt;/span> result = [String]()
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#66d9ef">for&lt;/span> length &lt;span style="color:#66d9ef">in&lt;/span> &lt;span style="color:#ae81ff">1.&lt;/span>..size {
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> result.append(String(repeating: &lt;span style="color:#e6db74">&amp;#34;*&amp;#34;&lt;/span>, count: length))
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> }
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#66d9ef">return&lt;/span> result.joined(separator: &lt;span style="color:#e6db74">&amp;#34;&lt;/span>&lt;span style="color:#ae81ff">\n&lt;/span>&lt;span style="color:#e6db74">&amp;#34;&lt;/span>)
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> }
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>}
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#66d9ef">let&lt;/span> smallTriangle = Triangle(size: &lt;span style="color:#ae81ff">3&lt;/span>)
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>print(smallTriangle.draw())
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#75715e">// *&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#75715e">// **&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#75715e">// ***&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#66d9ef">struct&lt;/span> &lt;span style="color:#a6e22e">FlippedShape&lt;/span>&amp;lt;T: Shape&amp;gt;: Shape {
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#66d9ef">var&lt;/span> shape: T
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#66d9ef">func&lt;/span> &lt;span style="color:#a6e22e">draw&lt;/span>() -&amp;gt; String {
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#66d9ef">let&lt;/span> lines = shape.draw().split(separator: &lt;span style="color:#e6db74">&amp;#34;&lt;/span>&lt;span style="color:#ae81ff">\n&lt;/span>&lt;span style="color:#e6db74">&amp;#34;&lt;/span>)
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#66d9ef">return&lt;/span> lines.reversed().joined(separator: &lt;span style="color:#e6db74">&amp;#34;&lt;/span>&lt;span style="color:#ae81ff">\n&lt;/span>&lt;span style="color:#e6db74">&amp;#34;&lt;/span>)
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> }
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>}
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#66d9ef">let&lt;/span> flippedTriangle = FlippedShape(shape: smallTriangle)
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>print(flippedTriangle.draw())
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#75715e">// ***&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#75715e">// **&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#75715e">// *&lt;/span>
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>&lt;h4 id="自动引用计数">自动引用计数&lt;/h4>
&lt;p>Swift 使用自动引用计数（ARC）机制来跟踪和管理你的应用程序的内存。
如果两个类实例互相持有对方的强引用，因而每个实例都让对方一直存在，就是这种情况。这就是所谓的循环强引用。
Swift提供了两种办法用来解决你在使用类的属性时所遇到的循环强引用问题：弱引用（weak reference）和无主引用（unowned reference）。&lt;/p>
&lt;ul>
&lt;li>
&lt;p>声明属性或者变量时，在前面加上 weak 关键字表明这是一个弱引用。&lt;/p>
&lt;/li>
&lt;li>
&lt;p>声明属性或者变量时，在前面加上关键字 unowned 表示这是一个无主引用。&lt;/p>
&lt;/li>
&lt;/ul>
&lt;p>示例：&lt;/p>
&lt;div class="highlight">&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;">&lt;code class="language-swift" data-lang="swift">&lt;span style="display:flex;">&lt;span>&lt;span style="color:#75715e">// 自动引用计数实践&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#66d9ef">class&lt;/span> &lt;span style="color:#a6e22e">Person&lt;/span> {
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#66d9ef">let&lt;/span> name: String
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#66d9ef">init&lt;/span>(name: String) {
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#66d9ef">self&lt;/span>.name = name
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> print(&lt;span style="color:#e6db74">&amp;#34;&lt;/span>&lt;span style="color:#e6db74">\(&lt;/span>name&lt;span style="color:#e6db74">)&lt;/span>&lt;span style="color:#e6db74"> is being initialized&amp;#34;&lt;/span>)
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> }
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#66d9ef">deinit&lt;/span> {
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> print(&lt;span style="color:#e6db74">&amp;#34;&lt;/span>&lt;span style="color:#e6db74">\(&lt;/span>name&lt;span style="color:#e6db74">)&lt;/span>&lt;span style="color:#e6db74"> is being deinitialized&amp;#34;&lt;/span>)
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> }
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>}
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#66d9ef">var&lt;/span> reference1: Person?
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#66d9ef">var&lt;/span> reference2: Person?
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#66d9ef">var&lt;/span> reference3: Person?
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>reference1 = Person(name: &lt;span style="color:#e6db74">&amp;#34;John Appleseed&amp;#34;&lt;/span>)
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#75715e">// 打印“John Appleseed is being initialized”&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>reference2 = reference1
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>reference3 = reference1
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>reference1 = &lt;span style="color:#66d9ef">nil&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>reference2 = &lt;span style="color:#66d9ef">nil&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>reference3 = &lt;span style="color:#66d9ef">nil&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#75715e">// 打印“John Appleseed is being deinitialized”&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#75715e">// 循环强引用&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#66d9ef">class&lt;/span> &lt;span style="color:#a6e22e">Person&lt;/span> {
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#66d9ef">let&lt;/span> name: String
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#66d9ef">init&lt;/span>(name: String) { &lt;span style="color:#66d9ef">self&lt;/span>.name = name }
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#66d9ef">var&lt;/span> apartment: Apartment?
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#66d9ef">deinit&lt;/span> { print(&lt;span style="color:#e6db74">&amp;#34;&lt;/span>&lt;span style="color:#e6db74">\(&lt;/span>name&lt;span style="color:#e6db74">)&lt;/span>&lt;span style="color:#e6db74"> is being deinitialized&amp;#34;&lt;/span>) }
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>}
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#66d9ef">class&lt;/span> &lt;span style="color:#a6e22e">Apartment&lt;/span> {
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#66d9ef">let&lt;/span> unit: String
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#66d9ef">init&lt;/span>(unit: String) { &lt;span style="color:#66d9ef">self&lt;/span>.unit = unit }
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#66d9ef">var&lt;/span> tenant: Person?
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#66d9ef">deinit&lt;/span> { print(&lt;span style="color:#e6db74">&amp;#34;Apartment &lt;/span>&lt;span style="color:#e6db74">\(&lt;/span>unit&lt;span style="color:#e6db74">)&lt;/span>&lt;span style="color:#e6db74"> is being deinitialized&amp;#34;&lt;/span>) }
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>}
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#66d9ef">var&lt;/span> john: Person?
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#66d9ef">var&lt;/span> unit4A: Apartment?
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>john = Person(name: &lt;span style="color:#e6db74">&amp;#34;John Appleseed&amp;#34;&lt;/span>)
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>unit4A = Apartment(unit: &lt;span style="color:#e6db74">&amp;#34;4A&amp;#34;&lt;/span>)
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>john = &lt;span style="color:#66d9ef">nil&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>unit4A = &lt;span style="color:#66d9ef">nil&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#75715e">// 弱引用&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#66d9ef">class&lt;/span> &lt;span style="color:#a6e22e">Person&lt;/span> {
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#66d9ef">let&lt;/span> name: String
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#66d9ef">init&lt;/span>(name: String) { &lt;span style="color:#66d9ef">self&lt;/span>.name = name }
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#66d9ef">var&lt;/span> apartment: Apartment?
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#66d9ef">deinit&lt;/span> { print(&lt;span style="color:#e6db74">&amp;#34;&lt;/span>&lt;span style="color:#e6db74">\(&lt;/span>name&lt;span style="color:#e6db74">)&lt;/span>&lt;span style="color:#e6db74"> is being deinitialized&amp;#34;&lt;/span>) }
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>}
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#66d9ef">class&lt;/span> &lt;span style="color:#a6e22e">Apartment&lt;/span> {
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#66d9ef">let&lt;/span> unit: String
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#66d9ef">init&lt;/span>(unit: String) { &lt;span style="color:#66d9ef">self&lt;/span>.unit = unit }
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#66d9ef">weak&lt;/span> &lt;span style="color:#66d9ef">var&lt;/span> tenant: Person?
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#66d9ef">deinit&lt;/span> { print(&lt;span style="color:#e6db74">&amp;#34;Apartment &lt;/span>&lt;span style="color:#e6db74">\(&lt;/span>unit&lt;span style="color:#e6db74">)&lt;/span>&lt;span style="color:#e6db74"> is being deinitialized&amp;#34;&lt;/span>) }
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>}
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#66d9ef">var&lt;/span> john: Person?
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#66d9ef">var&lt;/span> unit4A: Apartment?
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>john = Person(name: &lt;span style="color:#e6db74">&amp;#34;John Appleseed&amp;#34;&lt;/span>)
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>unit4A = Apartment(unit: &lt;span style="color:#e6db74">&amp;#34;4A&amp;#34;&lt;/span>)
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>john!.apartment = unit4A
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>unit4A!.tenant = john
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>john = &lt;span style="color:#66d9ef">nil&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#75715e">// 打印“John Appleseed is being deinitialized”&lt;/span>
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>&lt;h4 id="内存安全">内存安全&lt;/h4>
&lt;p>默认情况下，Swift 会阻止你代码里不安全的行为。
理解内存访问冲突，In-Out 参数的访问冲突，方法里 self 的访问冲突，属性的访问冲突&lt;/p>
&lt;p>示例：&lt;/p>
&lt;div class="highlight">&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;">&lt;code class="language-swift" data-lang="swift">&lt;span style="display:flex;">&lt;span>&lt;span style="color:#66d9ef">func&lt;/span> &lt;span style="color:#a6e22e">balance&lt;/span>(&lt;span style="color:#66d9ef">_&lt;/span> x: &lt;span style="color:#66d9ef">inout&lt;/span> Int, &lt;span style="color:#66d9ef">_&lt;/span> y: &lt;span style="color:#66d9ef">inout&lt;/span> Int) {
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#66d9ef">let&lt;/span> sum = x &lt;span style="color:#f92672">+&lt;/span> y
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> x = sum &lt;span style="color:#f92672">/&lt;/span> &lt;span style="color:#ae81ff">2&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> y = sum &lt;span style="color:#f92672">-&lt;/span> x
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>}
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#66d9ef">var&lt;/span> playerOneScore = &lt;span style="color:#ae81ff">42&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#66d9ef">var&lt;/span> playerTwoScore = &lt;span style="color:#ae81ff">30&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>balance(&amp;amp;playerOneScore, &amp;amp;playerTwoScore) &lt;span style="color:#75715e">// 正常&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>balance(&amp;amp;playerOneScore, &amp;amp;playerOneScore)
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#75715e">// 错误：playerOneScore 访问冲突&lt;/span>
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>&lt;h4 id="访问控制">访问控制&lt;/h4>
&lt;p>访问控制可以限定其它源文件或模块对你的代码的访问。&lt;/p>
&lt;ul>
&lt;li>
&lt;p>open 和 public 级别可以让实体被同一模块源文件中的所有实体访问，在模块外也可以通过导入该模块来访问源文件里的所有实体。通常情况下，你会使用 open 或 public 级别来指定框架的外部接口。&lt;/p>
&lt;/li>
&lt;li>
&lt;p>internal 级别让实体被同一模块源文件中的任何实体访问，但是不能被模块外的实体访问。通常情况下，如果某个接口只在应用程序或框架内部使用，就可以将其设置为 internal 级别。&lt;/p>
&lt;/li>
&lt;li>
&lt;p>fileprivate 限制实体只能在其定义的文件内部访问。如果功能的部分实现细节只需要在文件内使用时，可以使用 fileprivate 来将其隐藏。&lt;/p>
&lt;/li>
&lt;li>
&lt;p>private 限制实体只能在其定义的作用域，以及同一文件内的 extension 访问。如果功能的部分细节只需要在当前作用域内使用时，可以使用 private 来将其隐藏。&lt;/p>
&lt;/li>
&lt;/ul>
&lt;p>open 为最高访问级别（限制最少），private 为最低访问级别（限制最多）。
open 只能作用于类和类的成员，它和 public 的区别主要在于 open 限定的类和成员能够在模块外能被继承和重写。
示例：&lt;/p>
&lt;div class="highlight">&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;">&lt;code class="language-swift" data-lang="swift">&lt;span style="display:flex;">&lt;span>&lt;span style="color:#66d9ef">public&lt;/span> &lt;span style="color:#66d9ef">class&lt;/span> &lt;span style="color:#a6e22e">SomePublicClass&lt;/span> {}
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#66d9ef">internal&lt;/span> &lt;span style="color:#66d9ef">class&lt;/span> &lt;span style="color:#a6e22e">SomeInternalClass&lt;/span> {}
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>fileprivate &lt;span style="color:#66d9ef">class&lt;/span> &lt;span style="color:#a6e22e">SomeFilePrivateClass&lt;/span> {}
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#66d9ef">private&lt;/span> &lt;span style="color:#66d9ef">class&lt;/span> &lt;span style="color:#a6e22e">SomePrivateClass&lt;/span> {}
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#66d9ef">class&lt;/span> &lt;span style="color:#a6e22e">SomeInternalClass&lt;/span> {} &lt;span style="color:#75715e">// 隐式 internal&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#66d9ef">var&lt;/span> someInternalConstant = &lt;span style="color:#ae81ff">0&lt;/span> &lt;span style="color:#75715e">// 隐式 internal&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#66d9ef">public&lt;/span> &lt;span style="color:#66d9ef">class&lt;/span> &lt;span style="color:#a6e22e">SomePublicClass&lt;/span> { &lt;span style="color:#75715e">// 显式 public 类&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#66d9ef">public&lt;/span> &lt;span style="color:#66d9ef">var&lt;/span> somePublicProperty = &lt;span style="color:#ae81ff">0&lt;/span> &lt;span style="color:#75715e">// 显式 public 类成员&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#66d9ef">var&lt;/span> someInternalProperty = &lt;span style="color:#ae81ff">0&lt;/span> &lt;span style="color:#75715e">// 隐式 internal 类成员&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> fileprivate &lt;span style="color:#66d9ef">func&lt;/span> &lt;span style="color:#a6e22e">someFilePrivateMethod&lt;/span>() {} &lt;span style="color:#75715e">// 显式 fileprivate 类成员&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#66d9ef">private&lt;/span> &lt;span style="color:#66d9ef">func&lt;/span> &lt;span style="color:#a6e22e">somePrivateMethod&lt;/span>() {} &lt;span style="color:#75715e">// 显式 private 类成员&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>}
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#66d9ef">class&lt;/span> &lt;span style="color:#a6e22e">SomeInternalClass&lt;/span> { &lt;span style="color:#75715e">// 隐式 internal 类&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#66d9ef">var&lt;/span> someInternalProperty = &lt;span style="color:#ae81ff">0&lt;/span> &lt;span style="color:#75715e">// 隐式 internal 类成员&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> fileprivate &lt;span style="color:#66d9ef">func&lt;/span> &lt;span style="color:#a6e22e">someFilePrivateMethod&lt;/span>() {} &lt;span style="color:#75715e">// 显式 fileprivate 类成员&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#66d9ef">private&lt;/span> &lt;span style="color:#66d9ef">func&lt;/span> &lt;span style="color:#a6e22e">somePrivateMethod&lt;/span>() {} &lt;span style="color:#75715e">// 显式 private 类成员&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>}
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>fileprivate &lt;span style="color:#66d9ef">class&lt;/span> &lt;span style="color:#a6e22e">SomeFilePrivateClass&lt;/span> { &lt;span style="color:#75715e">// 显式 fileprivate 类&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#66d9ef">func&lt;/span> &lt;span style="color:#a6e22e">someFilePrivateMethod&lt;/span>() {} &lt;span style="color:#75715e">// 隐式 fileprivate 类成员&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#66d9ef">private&lt;/span> &lt;span style="color:#66d9ef">func&lt;/span> &lt;span style="color:#a6e22e">somePrivateMethod&lt;/span>() {} &lt;span style="color:#75715e">// 显式 private 类成员&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>}
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#66d9ef">private&lt;/span> &lt;span style="color:#66d9ef">class&lt;/span> &lt;span style="color:#a6e22e">SomePrivateClass&lt;/span> { &lt;span style="color:#75715e">// 显式 private 类&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#66d9ef">func&lt;/span> &lt;span style="color:#a6e22e">somePrivateMethod&lt;/span>() {} &lt;span style="color:#75715e">// 隐式 private 类成员&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>}
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>&lt;h4 id="高级运算符">高级运算符&lt;/h4>
&lt;p>Swift还提供了数种可以对数值进行复杂运算的高级运算符。它们包含了位运算符和移位运算符。
&lt;strong>位运算符、溢出运算符、优先级和结合性、运算符函数、自定义运算符&lt;/strong>&lt;/p>
&lt;p>示例：&lt;/p>
&lt;div class="highlight">&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;">&lt;code class="language-swift" data-lang="swift">&lt;span style="display:flex;">&lt;span>&lt;span style="color:#66d9ef">let&lt;/span> initialBits: UInt8 = &lt;span style="color:#ae81ff">0b00001111&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#66d9ef">let&lt;/span> invertedBits = &lt;span style="color:#f92672">~&lt;/span>initialBits &lt;span style="color:#75715e">// 等于 0b11110000&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#66d9ef">var&lt;/span> potentialOverflow = Int16.max
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#75715e">// potentialOverflow 的值是 32767，这是 Int16 能容纳的最大整数&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>potentialOverflow &lt;span style="color:#f92672">+=&lt;/span> &lt;span style="color:#ae81ff">1&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#75715e">// 这里会报错&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#66d9ef">struct&lt;/span> &lt;span style="color:#a6e22e">Vector2D&lt;/span> {
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#66d9ef">var&lt;/span> x = &lt;span style="color:#ae81ff">0.0&lt;/span>, y = &lt;span style="color:#ae81ff">0.0&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>}
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#66d9ef">extension&lt;/span> &lt;span style="color:#a6e22e">Vector2D&lt;/span> {
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#66d9ef">static&lt;/span> &lt;span style="color:#66d9ef">func&lt;/span> &lt;span style="color:#f92672">+&lt;/span> (&lt;span style="color:#66d9ef">left&lt;/span>: Vector2D, &lt;span style="color:#66d9ef">right&lt;/span>: Vector2D) -&amp;gt; Vector2D {
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#66d9ef">return&lt;/span> Vector2D(x: &lt;span style="color:#66d9ef">left&lt;/span>.x &lt;span style="color:#f92672">+&lt;/span> &lt;span style="color:#66d9ef">right&lt;/span>.x, y: &lt;span style="color:#66d9ef">left&lt;/span>.y &lt;span style="color:#f92672">+&lt;/span> &lt;span style="color:#66d9ef">right&lt;/span>.y)
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> }
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>}
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#66d9ef">let&lt;/span> vector = Vector2D(x: &lt;span style="color:#ae81ff">3.0&lt;/span>, y: &lt;span style="color:#ae81ff">1.0&lt;/span>)
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#66d9ef">let&lt;/span> anotherVector = Vector2D(x: &lt;span style="color:#ae81ff">2.0&lt;/span>, y: &lt;span style="color:#ae81ff">4.0&lt;/span>)
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#66d9ef">let&lt;/span> combinedVector = vector &lt;span style="color:#f92672">+&lt;/span> anotherVector
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#75715e">// combinedVector 是一个新的 Vector2D 实例，值为 (5.0, 5.0)&lt;/span>
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div></description></item><item><title>使用 Golang 的交叉编译</title><link>https://blog.baicai.me/article/2021/go_cross_compilling/</link><pubDate>Thu, 13 May 2021 14:35:47 +0800</pubDate><author>admin@baicai.me (白菜)</author><guid>https://blog.baicai.me/article/2021/go_cross_compilling/</guid><description>&lt;blockquote>
&lt;p>在 Linux 上测试软件时，我使用各种架构的服务器，例如 Intel、AMD、Arm 等。当我 分配了一台满足我的测试需求的 Linux 机器[1]，我仍然需要执行许多步骤：&lt;/p>&lt;/blockquote>
&lt;ul>
&lt;li>下载并安装必备软件&lt;/li>
&lt;li>验证构建服务器上是否有新的测试软件包&lt;/li>
&lt;li>获取并设置依赖软件包所需的 yum 仓库&lt;/li>
&lt;li>下载并安装新的测试软件包（基于步骤 2）&lt;/li>
&lt;li>获取并设置必需的 SSL 证书&lt;/li>
&lt;li>设置测试环境，获取所需的 Git 仓库，更改配置，重新启动守护进程等&lt;/li>
&lt;li>做其他需要做的事情&lt;/li>
&lt;/ul>
&lt;h3 id="用脚本自动化">用脚本自动化&lt;/h3>
&lt;p>这些步骤非常常规，以至于有必要对其进行自动化并将脚本保存到中央位置（例如文件服务器），在需要时可以在此处下载脚本。为此，我编写了 100-120 行的 Bash shell 脚本，它为我完成了所有配置（包括错误检查）。这个脚本通过以下方式简化了我的工作流程：&lt;/p>
&lt;ul>
&lt;li>配置新的 Linux 系统（支持测试的架构）&lt;/li>
&lt;li>登录系统并从中央位置下载自动化 shell 脚本&lt;/li>
&lt;li>运行它来配置系统&lt;/li>
&lt;li>开始测试&lt;/li>
&lt;/ul>
&lt;h3 id="学习-go-语言">学习 Go 语言&lt;/h3>
&lt;p>我想学习 Go 语言 有一段时间了，将我心爱的 Shell 脚本转换为 Go 程序似乎是一个很好的项目，可以帮助我入门。它的语法看起来很简单，在尝试了一些测试程序后，我开始着手提高自己的知识并熟悉 Go 标准库。&lt;/p>
&lt;p>我花了一个星期的时间在笔记本电脑上编写 Go 程序。我经常在我的 x86 服务器上测试程序，清除错误并使程序健壮起来，一切都很顺利。&lt;/p>
&lt;p>直到完全转换到 Go 程序前，我继续依赖自己的 shell 脚本。然后，我将二进制文件推送到中央文件服务器上，以便每次配置新服务器时，我要做的就是获取二进制文件，将可执行标志打开，然后运行二进制文件。我对早期的结果很满意：&lt;/p>
&lt;div class="highlight">&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;">&lt;code class="language-bash" data-lang="bash">&lt;span style="display:flex;">&lt;span>$ wget http://file.example.com/&amp;lt;myuser&amp;gt;/bins/prepnode
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>$ chmod +x ./prepnode
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>$ ./prepnode
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>&lt;p>然后，出现了一个问题&lt;/p>
&lt;p>第二周，我从资源池中分配了一台新的服务器，像往常一样，我下载了二进制文件，设置了可执行标志，然后运行二进制文件。但这次它出错了，是一个奇怪的错误：&lt;/p>
&lt;div class="highlight">&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;">&lt;code class="language-bash" data-lang="bash">&lt;span style="display:flex;">&lt;span>$ ./prepnode
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>bash: ./prepnode: cannot execute binary file: Exec format error
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>$
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>&lt;p>起初，我以为可能没有成功设置可执行标志。但是，它已按预期设置：&lt;/p>
&lt;div class="highlight">&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;">&lt;code class="language-bash" data-lang="bash">&lt;span style="display:flex;">&lt;span>$ ls -l prepnode
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>-rwxr-xr-x. &lt;span style="color:#ae81ff">1&lt;/span> root root &lt;span style="color:#ae81ff">2640529&lt;/span> Dec &lt;span style="color:#ae81ff">16&lt;/span> 05:43 prepnode
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>&lt;p>发生了什么事？我没有对源代码进行任何更改，编译没有引发任何错误或警告，而且上次运行时效果很好，因此我仔细查看了错误消息 format error。&lt;/p>
&lt;p>我检查了二进制文件的格式，一切看起来都没问题：&lt;/p>
&lt;div class="highlight">&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;">&lt;code class="language-bash" data-lang="bash">&lt;span style="display:flex;">&lt;span>$ file prepnode
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>prepnode: ELF 64-bit LSB executable, x86-64, version &lt;span style="color:#ae81ff">1&lt;/span> &lt;span style="color:#f92672">(&lt;/span>SYSV&lt;span style="color:#f92672">)&lt;/span>, statically linked, not stripped
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>&lt;p>我迅速运行了以下命令，识别所配置的测试服务器的架构以及二进制试图运行的平台。它是 Arm64 架构，但是我编译的二进制文件（在我的 x86 笔记本电脑上）生成的是 x86-64 格式的二进制文件：&lt;/p>
&lt;div class="highlight">&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;">&lt;code class="language-bash" data-lang="bash">&lt;span style="display:flex;">&lt;span>$ uname -m
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>aarch64
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>&lt;h3 id="脚本编写人员的编译第一课">脚本编写人员的编译第一课&lt;/h3>
&lt;p>在那之前，我从未考虑过这种情况（尽管我知道这一点）。我主要研究脚本语言（通常是 Python）以及 Shell 脚本。在任何架构的大多数 Linux 服务器上都可以使用 Bash Shell 和 Python 解释器。总之，之前一切都很顺利。&lt;/p>
&lt;p>但是，现在我正在处理 Go 这种编译语言，它生成可执行的二进制文件。编译后的二进制文件由特定架构的指令码或汇编指令组成，这就是为什么我收到格式错误的原因。由于 Arm64 CPU（运行二进制文件的地方）无法解释二进制文件的 x86-64 指令，因此它抛出错误。以前，shell 和 Python 解释器为我处理了底层指令码或特定架构的指令。&lt;/p>
&lt;h3 id="go-的交叉编译">Go 的交叉编译&lt;/h3>
&lt;p>我检查了 Golang 的文档，发现要生成 Arm64 二进制文件，我要做的就是在运行 go build 命令编译 Go 程序之前设置两个环境变量。&lt;/p>
&lt;p>GOOS 指的是操作系统，例如 Linux、Windows、BSD 等，而 GOARCH 指的是要在哪种架构上构建程序。&lt;/p>
&lt;div class="highlight">&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;">&lt;code class="language-bash" data-lang="bash">&lt;span style="display:flex;">&lt;span>$ env GOOS&lt;span style="color:#f92672">=&lt;/span>linux GOARCH&lt;span style="color:#f92672">=&lt;/span>arm64 go build -o prepnode_arm64
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>&lt;p>构建程序后，我重新运行 file 命令，这一次它显示的是 ARM AArch64，而不是之前显示的 x86。因此，我在我的笔记本上能为不同的架构构建二进制文件。&lt;/p>
&lt;div class="highlight">&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;">&lt;code class="language-bash" data-lang="bash">&lt;span style="display:flex;">&lt;span>$ file prepnode_arm64
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>prepnode_arm64: ELF 64-bit LSB executable, ARM aarch64, version &lt;span style="color:#ae81ff">1&lt;/span> &lt;span style="color:#f92672">(&lt;/span>SYSV&lt;span style="color:#f92672">)&lt;/span>, statically linked, not stripped
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>&lt;p>我将二进制文件从笔记本电脑复制到 ARM 服务器上。现在运行二进制文件（将可执行标志打开）不会产生任何错误：&lt;/p>
&lt;div class="highlight">&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;">&lt;code class="language-bash" data-lang="bash">&lt;span style="display:flex;">&lt;span>$ ./prepnode_arm64 -h
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>Usage of ./prepnode_arm64:
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> -c Clean existing installation
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> -n Do not start test run &lt;span style="color:#f92672">(&lt;/span>default true&lt;span style="color:#f92672">)&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> -s Use stage environment, default is qa
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> -v Enable verbose output
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>&lt;h3 id="其他架构呢">其他架构呢？&lt;/h3>
&lt;p>x86 和 Arm 是我测试软件所支持的 5 种架构中的两种，我担心 Go 可能不会支持其它架构，但事实并非如此。你可以查看 Go 支持的架构：&lt;/p>
&lt;div class="highlight">&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;">&lt;code class="language-bash" data-lang="bash">&lt;span style="display:flex;">&lt;span>$ go tool dist list
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>&lt;p>Go 支持多种平台和操作系统，包括：&lt;/p>
&lt;pre>&lt;code>AIX
Android
Darwin
Dragonfly
FreeBSD
Illumos
ios
Js/wasm
JavaScript
Linux
NetBSD
OpenBSD
Plan 9
Solaris
Windows
&lt;/code>&lt;/pre>
&lt;p>要查找其支持的特定 Linux 架构，运行：&lt;/p>
&lt;div class="highlight">&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;">&lt;code class="language-bash" data-lang="bash">&lt;span style="display:flex;">&lt;span>$ go tool dist list | grep linux
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>&lt;p>如下面的输出所示，Go 支持我使用的所有体系结构。尽管 x86_64 不在列表中，但 AMD64 兼容 x86-64，所以你可以生成 AMD64 二进制文件，它可以在 x86 架构上正常运行：&lt;/p>
&lt;div class="highlight">&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;">&lt;code class="language-bash" data-lang="bash">&lt;span style="display:flex;">&lt;span>$ go tool dist list | grep linux
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>linux/386
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>linux/amd64
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>linux/arm
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>linux/arm64
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>linux/mips
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>linux/mips64
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>linux/mips64le
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>linux/mipsle
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>linux/ppc64
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>linux/ppc64le
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>linux/riscv64
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>linux/s390x
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>&lt;h3 id="处理所有架构">处理所有架构&lt;/h3>
&lt;p>为我测试的所有体系结构生成二进制文件，就像从我的 x86 笔记本电脑编写一个微小的 shell 脚本一样简单：&lt;/p>
&lt;div class="highlight">&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;">&lt;code class="language-bash" data-lang="bash">&lt;span style="display:flex;">&lt;span>&lt;span style="color:#75715e">#!/usr/bin/bash
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#75715e">&lt;/span>archs&lt;span style="color:#f92672">=(&lt;/span>amd64 arm64 ppc64le ppc64 s390x&lt;span style="color:#f92672">)&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#66d9ef">for&lt;/span> arch in &lt;span style="color:#e6db74">${&lt;/span>archs[@]&lt;span style="color:#e6db74">}&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#66d9ef">do&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> env GOOS&lt;span style="color:#f92672">=&lt;/span>linux GOARCH&lt;span style="color:#f92672">=&lt;/span>&lt;span style="color:#e6db74">${&lt;/span>arch&lt;span style="color:#e6db74">}&lt;/span> go build -o prepnode_&lt;span style="color:#e6db74">${&lt;/span>arch&lt;span style="color:#e6db74">}&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#66d9ef">done&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>$ file prepnode_*
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>prepnode_amd64: ELF 64-bit LSB executable, x86-64, version &lt;span style="color:#ae81ff">1&lt;/span> &lt;span style="color:#f92672">(&lt;/span>SYSV&lt;span style="color:#f92672">)&lt;/span>, statically linked, Go BuildID&lt;span style="color:#f92672">=&lt;/span>y03MzCXoZERH-0EwAAYI/p909FDnk7xEUo2LdHIyo/V2ABa7X_rLkPNHaFqUQ6/5p_q8MZiR2WYkA5CzJiF, not stripped
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>prepnode_arm64: ELF 64-bit LSB executable, ARM aarch64, version &lt;span style="color:#ae81ff">1&lt;/span> &lt;span style="color:#f92672">(&lt;/span>SYSV&lt;span style="color:#f92672">)&lt;/span>, statically linked, Go BuildID&lt;span style="color:#f92672">=&lt;/span>q-H-CCtLv__jVOcdcOpA/CywRwDz9LN2Wk_fWeJHt/K4-3P5tU2mzlWJa0noGN/SEev9TJFyvHdKZnPaZgb, not stripped
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>prepnode_ppc64: ELF 64-bit MSB executable, 64-bit PowerPC or cisco 7500, version &lt;span style="color:#ae81ff">1&lt;/span> &lt;span style="color:#f92672">(&lt;/span>SYSV&lt;span style="color:#f92672">)&lt;/span>, statically linked, Go BuildID&lt;span style="color:#f92672">=&lt;/span>DMWfc1QwOGIq2hxEzL_u/UE-9CIvkIMeNC_ocW4ry/r-7NcMATXatoXJQz3yUO/xzfiDIBuUxbuiyaw5Goq, not stripped
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>prepnode_ppc64le: ELF 64-bit LSB executable, 64-bit PowerPC or cisco 7500, version &lt;span style="color:#ae81ff">1&lt;/span> &lt;span style="color:#f92672">(&lt;/span>SYSV&lt;span style="color:#f92672">)&lt;/span>, statically linked, Go BuildID&lt;span style="color:#f92672">=&lt;/span>C6qCjxwO9s63FJKDrv3f/xCJa4E6LPVpEZqmbF6B4/Mu6T_OR-dx-vLavn1Gyq/AWR1pK1cLz9YzLSFt5eU, not stripped
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>prepnode_s390x: ELF 64-bit MSB executable, IBM S/390, version &lt;span style="color:#ae81ff">1&lt;/span> &lt;span style="color:#f92672">(&lt;/span>SYSV&lt;span style="color:#f92672">)&lt;/span>, statically linked, Go BuildID&lt;span style="color:#f92672">=&lt;/span>faC_HDe1_iVq2XhpPD3d/7TIv0rulE4RZybgJVmPz/o_SZW_0iS0EkJJZHANxx/zuZgo79Je7zAs3v6Lxuz, not stripped
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>&lt;p>现在，每当配置一台新机器时，我就运行以下 wget 命令下载特定体系结构的二进制文件，将可执行标志打开，然后运行：&lt;/p>
&lt;div class="highlight">&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;">&lt;code class="language-bash" data-lang="bash">&lt;span style="display:flex;">&lt;span>$ wget http://file.domain.com/&amp;lt;myuser&amp;gt;/bins/prepnode_&amp;lt;arch&amp;gt;
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>$ chmod +x ./prepnode_&amp;lt;arch&amp;gt;
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>$ ./prepnode_&amp;lt;arch&amp;gt;
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>&lt;h3 id="为什么">为什么？&lt;/h3>
&lt;p>你可能想知道，为什么我没有坚持使用 shell 脚本或将程序移植到 Python 而不是编译语言上来避免这些麻烦。所以有舍有得，那样的话我不会了解 Go 的交叉编译功能，以及程序在 CPU 上执行时的底层工作原理。在计算机中，总要考虑取舍，但绝不要让它们阻碍你的学习。&lt;/p>
&lt;h3 id="参考">参考&lt;/h3>
&lt;p>Cross-compiling made easy with Golang &lt;a href="https://opensource.com/article/21/1/go-cross-compiling">[1]&lt;/a>&lt;/p>
&lt;p>使用 Golang 的交叉编译 &lt;a href="https://linux.cn/article-13385-1.html">[2]&lt;/a>&lt;/p></description></item><item><title>Linux/Mac 使用 GNU Screen 的小技巧</title><link>https://blog.baicai.me/article/2021/linux_screen/</link><pubDate>Thu, 13 May 2021 12:50:05 +0800</pubDate><author>admin@baicai.me (白菜)</author><guid>https://blog.baicai.me/article/2021/linux_screen/</guid><description>&lt;blockquote>
&lt;p>学习基本的 GNU Screen 终端复用技术，然后下载我们的终端命令备忘录，以便你能够熟悉常用的快捷方式。&lt;/p>&lt;/blockquote>
&lt;p>对于一般用户而言，命令行终端窗口可能是令人困惑和神秘的。但随着你对 Linux 终端的进一步了解，你很快就会意识到它的高效和强大。不过，也不需要很长时间，你就会想让终端变得更加高效，除了将更多的终端放到你的终端，还有什么高好的方法能够提升你的终端效率呢？&lt;/p>
&lt;h3 id="终端复用">终端复用&lt;/h3>
&lt;p>终端的许多优点之一是它是一个集中控制的界面。它是一个能让你访问数百个应用程序的窗口，而你与每一个应用程序进行交互所需要的只是一个键盘。但是，现代计算机几乎总是有多余的处理能力，而且现代计算机专家喜欢多任务处理，导致一个窗口处理数百个应用程序的能力是相当有限的。&lt;/p>
&lt;p>解决这一问题的常见答案是终端复用：即将虚拟终端叠放在一起，然后在它们之间移动的能力。通过终端复用器，你保持了集中控制，但是当你进行多任务时，你能够进行终端切换。更好的是，你能够在终端中拆分屏幕，使得在同一时间显示多个屏幕窗口。&lt;/p>
&lt;h3 id="选择合适的复用器">选择合适的复用器&lt;/h3>
&lt;p>一些终端提供类似的功能，有标签式界面和分割式视图，但也有细微的差别。首先，这些终端的功能依赖于图形化的桌面环境。其次，许多图形化的终端功能需要鼠标交互或使用不方便的键盘快捷键。终端复用器的功能在文本控制台上和在图形桌面上一样好用，而且键位绑定是针对常见的终端序列设计的，很方便。&lt;/p>
&lt;p>现有两种流行的复用器：tmux 和 GNU Screen。尽管你与它们互动的方式略有不同，但它们做同样的事情，而且大多具有相同的功能。这篇文章是 GNU Screen 的入门指南。关于 tmux 的相关介绍，请阅读 Kevin Sonney 的 tmux 介绍。&lt;/p>
&lt;h3 id="使用-gnu-screen">使用 GNU Screen&lt;/h3>
&lt;p>GNU Screen 的基本用法很简单，通过 &lt;code>screen&lt;/code> 命令启动，你将进入 Screen 会话的第 0 个窗口。在你决定需要一个新的终端提示符前，你可能很难注意到有什么变化。&lt;/p>
&lt;p>当一个终端窗口被某项活动占用（比如，你启动了文本编辑器 &lt;strong>Vim&lt;/strong> 或 &lt;strong>Jove&lt;/strong> 或者你在处理音视频，或运行批处理任务），你可以新建一个窗口。要打开一个新的窗口，按 &lt;code>Ctrl+A&lt;/code>，释放，然后按 &lt;code>c&lt;/code>。这将在你现有窗口的基础上创建一个新的窗口。&lt;/p>
&lt;p>你会知道当前你是在一个新的窗口中，因为你的终端除了默认的提示符外，似乎没有任何东西。当然，你的另一个终端仍然存在，它只是躲在新窗口的后面。要遍历打开的窗口，按 &lt;code>Ctrl+A&lt;/code>，释放，然后按 &lt;code>n&lt;/code>（表示下一个）或按 &lt;code>p&lt;/code>（表示上一个）。在只打开两个窗口的情况下， &lt;code>n&lt;/code> 和 &lt;code>p&lt;/code> 的功能是一样的，但你可以随时打开更多的窗口（&lt;code>Ctrl+A&lt;/code>，然后 &lt;code>c&lt;/code> ），并在它们之间切换。&lt;/p>
&lt;h3 id="分屏">分屏&lt;/h3>
&lt;p>GNU Screen 的默认行为更像移动设备的屏幕，而不是桌面：你一次只能看到一个窗口。如果你因为喜欢多任务而使用 GNU Screen ，那么只关注一个窗口可能看起来是一种退步。幸运的是，GNU Screen 可以让你把终端分成窗口中的窗口。&lt;/p>
&lt;p>要创建一个水平分割窗口，按 &lt;code>Ctrl+A&lt;/code>，然后按 &lt;code>s&lt;/code> 。这将把一个窗口置于另一个窗口之上，就像窗格一样。然而，在你告诉它要显示什么之前，分割的空间是没有用途的。因此，在创建一个分割窗后，你可以用 &lt;code>Ctrl+A&lt;/code> ，然后用 &lt;code>Tab&lt;/code> 移动到分割窗中。一旦进入，使用 &lt;code>Ctrl+A&lt;/code> 然后 &lt;code>n&lt;/code> 浏览所有可用的窗口，直到你想显示的内容出现在分割窗格中。&lt;/p>
&lt;p>你也可以按 &lt;code>Ctrl+A&lt;/code> 然后按 &lt;code>|&lt;/code> （这是一个管道字符，在大多数键盘上通过按下 &lt;code>shift&lt;/code> 键加上 &lt;code>\&lt;/code>）创建垂直分割窗口。&lt;/p>
&lt;h3 id="自定义-gnu-screen">自定义 GNU Screen&lt;/h3>
&lt;p>GNU Screen 使用基于 &lt;code>Ctrl+A&lt;/code> 的快捷键。根据你的习惯，这可能会让你感觉非常自然，也可能非常不方便，因为你可能会用 &lt;code>Ctrl+A&lt;/code> 来移动到一行的开头。无论怎样，GNU Screen 允许通过 &lt;code>.screenrc&lt;/code> 配置文件进行各种定制。你可以用这个来改变触发键的绑定（称为 “转义” 键绑定）。&lt;/p>
&lt;p>&lt;code>escape ^jJ&lt;/code>&lt;/p>
&lt;p>你还可以添加一个状态行，以帮助你在 Screen 会话中保持自己不迷失。&lt;/p>
&lt;div class="highlight">&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;">&lt;code class="language-bash" data-lang="bash">&lt;span style="display:flex;">&lt;span> &lt;span style="color:#75715e"># status bar, with current window highlighted&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> hardstatus alwayslastline
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> hardstatus string &lt;span style="color:#e6db74">&amp;#39;%{= kG}[%{G}%H%? %1`%?%{g}][%= %{= kw}%-w%{+b yk} %n*%t%?(%u)%? %{-}%+w %=%{g}][%{B}%m/%d %{W}%C%A%{g}]&amp;#39;&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#75715e"># enable 256 colors&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> attrcolor b &lt;span style="color:#e6db74">&amp;#34;.I&amp;#34;&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> termcapinfo xterm &lt;span style="color:#e6db74">&amp;#39;Co#256:AB=\E[48;5;%dm:AF=\E[38;5;%dm&amp;#39;&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> defbce on
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>&lt;p>在有多个窗口打开的会话中，有一个时刻提醒哪些窗口具有焦点活动，哪些窗口有后台活动的提醒器特别有用。它类似一种终端的任务管理器。&lt;/p>
&lt;h3 id="备忘单">备忘单&lt;/h3>
&lt;p>当你学习 GNU Screen 的使用方法时，需要记住很多新的键盘命令。有些命令你马上就能记住，但那些你不常使用的命令可能就很难记住了。你可以按 &lt;code>Ctrl+A&lt;/code> 然后再按 &lt;code>?&lt;/code> 来访问 GNU Screen 的帮助界面。&lt;/p>
&lt;p>学习 GNU Screen 是提高你使用你最喜欢的 终端模拟器 的效率和敏捷性的一个好方法。请试一试吧！&lt;/p>
&lt;h3 id="参考">参考&lt;/h3>
&lt;p>Linux tips for using GNU Screen &lt;a href="https://opensource.com/article/21/4/gnu-screen-cheat-sheet">[1]&lt;/a>&lt;/p>
&lt;p>使用 GNU Screen 的小技巧 &lt;a href="https://linux.cn/article-13387-1.html">[2]&lt;/a>&lt;/p></description></item><item><title>使用 cron 调度自动化任务</title><link>https://blog.baicai.me/article/2021/linux_cron/</link><pubDate>Wed, 12 May 2021 18:59:21 +0800</pubDate><author>admin@baicai.me (白菜)</author><guid>https://blog.baicai.me/article/2021/linux_cron/</guid><description>&lt;blockquote>
&lt;p>cron 是一个调度守护进程，它以指定的时间间隔执行任务，这些任务称为 corn 作业，主要用于自动执行系统维护或管理任务。例如，你可以设置一个 cron 作业来自动执行重复的任务，比如备份数据库或数据，使用最新的安全补丁更新系统，检查磁盘空间使用情况，发送电子邮件等等。 cron 作业可以按分钟、小时、日、月、星期或它们的任意组合运行。&lt;/p>&lt;/blockquote>
&lt;h1 id="cron-的一些优点">cron 的一些优点&lt;/h1>
&lt;p>以下是使用 cron 作业的一些优点：&lt;/p>
&lt;pre>&lt;code>你可以更好地控制作业的运行时间。例如，你可以精确到分钟、小时、天等。
它消除了为循环任务逻辑而去写代码的需要，当你不再需要执行任务时，可以直接关闭它。
作业在不执行时不会占用内存，因此你可以节省内存分配。
如果一个作业执行失败并由于某种原因退出，它将在适当的时间再次运行。
&lt;/code>&lt;/pre>
&lt;h1 id="安装-cron-守护进程">安装 cron 守护进程&lt;/h1>
&lt;p>幸运的是，Fedora Linux 预先配置了运行重要的系统任务来保持系统更新，有几个实用程序可以运行任务例如 cron、anacron、at 和 batch 。本文只关注 cron 实用程序的安装。cron 和 cronie 包一起安装，cronie 包也提供 cron 服务。&lt;/p>
&lt;h3 id="要确定软件包是否已经存在使用-rpm-命令">要确定软件包是否已经存在，使用 rpm 命令：&lt;/h3>
&lt;p>&lt;code>$ rpm -q cronie Cronie-1.5.2-4.el8.x86_64&lt;/code>&lt;/p>
&lt;p>如果安装了 cronie ，它将返回 cronie 包的全名。如果你的系统中没有安装，则会显示未安装。&lt;/p>
&lt;h3 id="使用以下命令安装">使用以下命令安装：&lt;/h3>
&lt;p>&lt;code>$ dnf install cronie&lt;/code>&lt;/p>
&lt;h3 id="运行-cron-守护进程">运行 cron 守护进程&lt;/h3>
&lt;p>cron 作业由 crond 服务来执行，它会读取配置文件中的信息。在将作业添加到配置文件之前，必须启动 crond 服务，或者安装它。什么是 crond 呢？crond 是 cron 守护程序的简称。要确定 crond 服务是否正在运行，输入以下命令：&lt;/p>
&lt;p>&lt;code>$ systemctl status crond.service&lt;/code>&lt;/p>
&lt;pre>&lt;code>● crond.service - Command Scheduler
Loaded: loaded (/usr/lib/systemd/system/crond.service; enabled; vendor pre&amp;gt;
Active: active (running) since Sat 2021-03-20 14:12:35 PDT; 1 day 21h ago
Main PID: 1110 (crond)
&lt;/code>&lt;/pre>
&lt;p>如果你没有看到类似的内容 Active: active (running) since…，你需要启动 crond 守护进程。要在当前会话中运行 crond 服务，输入以下命令：&lt;/p>
&lt;p>&lt;code>$ systemctl run crond.service&lt;/code>&lt;/p>
&lt;p>将其配置为开机自启动，输入以下命令：&lt;/p>
&lt;p>&lt;code>$ systemctl enable crond.service&lt;/code>&lt;/p>
&lt;p>如果出于某种原因，你希望停止 crond 服务，按以下方式使用 stop 命令：&lt;/p>
&lt;p>&lt;code>$ systemctl stop crond.service&lt;/code>&lt;/p>
&lt;p>要重新启动它，只需使用 restart 命令：&lt;/p>
&lt;p>&lt;code>$ systemctl restart crond.service&lt;/code>&lt;/p>
&lt;h1 id="定义一个-cron-作业">定义一个 cron 作业&lt;/h1>
&lt;h3 id="cron-配置">cron 配置&lt;/h3>
&lt;p>以下是一个 cron 作业的配置细节示例。它定义了一个简单的 cron 作业，将 git master 分支的最新更改拉取到克隆的仓库中：&lt;/p>
&lt;p>&lt;code>*/59 * * * * username cd /home/username/project/design &amp;amp;&amp;amp; git pull origin master&lt;/code>&lt;/p>
&lt;p>主要有两部分：&lt;/p>
&lt;pre>&lt;code>第一部分是 */59 * * * *。这表明计时器设置为第 59 分钟执行一次。
该行的其余部分是命令，因为它将从命令行运行。 在此示例中，命令本身包含三个部分：
作业将以用户 username 的身份运行
它将切换到目录 /home/username/project/design
运行 git 命令拉取 master 分支中的最新更改
&lt;/code>&lt;/pre>
&lt;h3 id="时间语法">时间语法&lt;/h3>
&lt;p>如上所述，时间信息是 cron 作业字符串的第一部分，如上所属。它决定了 cron 作业运行的频率和时间。它按以下顺序包括 5 个部分：&lt;/p>
&lt;ul>
&lt;li>分钟&lt;/li>
&lt;li>小时&lt;/li>
&lt;li>一个月中的某天&lt;/li>
&lt;li>月份&lt;/li>
&lt;li>一周中的某天&lt;/li>
&lt;/ul>
&lt;p>下面是一种更图形化的方式来解释语法：&lt;/p>
&lt;pre>&lt;code>.--------------- 分钟 (0 - 59)
| .------------- 小时 (0 - 23)
| | .---------- 一月中的某天 (1 - 31)
| | | .------- 月份 (1 - 12) 或 jan、feb、mar、apr …
| | | | .---- 一周中的某天 (0-6) (周日=0 或 7)
| | | | | 或 sun、mon、tue、wed、thr、fri、sat
| | | | |
* * * * * user-name command-to-be-executed
&lt;/code>&lt;/pre>
&lt;h3 id="星号的使用">星号的使用&lt;/h3>
&lt;p>星号（*）可以用来替代数字，表示该位置的所有可能值。例如，分钟位置上的星号会使它每分钟运行一次。以下示例可能有助于更好地理解语法。&lt;/p>
&lt;p>这个 cron 作业将每分钟运行一次：&lt;/p>
&lt;p>&lt;code>* * * * [command]&lt;/code>&lt;/p>
&lt;p>斜杠表示分钟的间隔数。下面的示例将每小时运行 12 次，即每 5 分钟运行一次：&lt;/p>
&lt;p>&lt;code>*/5 * * * * [command]&lt;/code>&lt;/p>
&lt;p>下一个示例将每月的第二天午夜（例如 1 月 2 日凌晨 12:00，2 月 2 日凌晨 12:00 等等）：&lt;/p>
&lt;p>&lt;code>0 0 2 * * [command]&lt;/code>&lt;/p>
&lt;p>&lt;em>关于 cron 时间格式，还有更多格式符号，此处没有展开&lt;/em>&lt;/p>
&lt;h3 id="使用-crontab-创建一个-cron-作业">使用 crontab 创建一个 cron 作业&lt;/h3>
&lt;p>cron 作业会在后台运行，它会不断检查 /etc/crontab 文件和 /etc/cron.*/ 以及 /var/spool/cron/ 目录。每个用户在 /var/spool/cron/ 中都有一个唯一的 crontab 文件。&lt;/p>
&lt;p>不应该直接编辑这些 cron 文件。crontab 命令是用于创建、编辑、安装、卸载和列出 cron 作业的方法。&lt;/p>
&lt;p>更酷的是，在创建新文件或编辑现有文件后，你无需重新启动 cron。&lt;/p>
&lt;p>&lt;code>$ crontab -e&lt;/code>&lt;/p>
&lt;p>这将打开你现有的 crontab 文件，或者创建一个。调用 crontab -e 时，默认情况下会使用 vi 编辑器。注意：要使用 Nano 编辑 crontab 文件，可以设置 EDITOR=nano 环境变量。&lt;/p>
&lt;p>使用 -l 选项列出所有 cron 作业。如果需要，使用 -u 选项指定一个用户。&lt;/p>
&lt;p>&lt;code>$ crontab -l&lt;/code>&lt;/p>
&lt;p>&lt;code>$ crontab -u username -l&lt;/code>&lt;/p>
&lt;p>使用以下命令删除所有 cron 作业：&lt;/p>
&lt;p>&lt;code>$ crontab -r&lt;/code>&lt;/p>
&lt;p>要删除特定用户的作业，你必须以 root 用户身份运行以下命令：&lt;/p>
&lt;p>&lt;code>$ crontab -r -u username&lt;/code>&lt;/p>
&lt;p>cron 作业看起来可能只是系统管理员的工具，但它实际上与许多 Web 应用程序和用户任务有关。&lt;/p>
&lt;h1 id="参考">参考&lt;/h1>
&lt;p>Fedora Linux 文档的 &lt;a href="https://docs.fedoraproject.org/en-US/Fedora/12/html/Deployment_Guide/ch-autotasks.html">[1]&lt;/a>&lt;/p>
&lt;p>使用 cron 调度任务 &lt;a href="https://linux.cn/article-13383-1.html">[2]&lt;/a>&lt;/p></description></item><item><title>about me</title><link>https://blog.baicai.me/about/</link><pubDate>Tue, 11 May 2021 18:46:34 +0800</pubDate><author>admin@baicai.me (白菜)</author><guid>https://blog.baicai.me/about/</guid><description>&lt;h3 id="关于我">关于我&lt;/h3>
&lt;p>一个勤奋的代码搬运工。&lt;/p>
&lt;h3 id="为什么建立个人博客">为什么建立个人博客？&lt;/h3>
&lt;p>宣传自己，这是一个信息爆炸、人人自我营销的时代，不懂得宣传自己，就得不到机会的垂青。&lt;/p>
&lt;p>个人觉得IT从业者就应该有自己的博客网站，记录与分享自己的经验，收集有价值的文章。&lt;/p>
&lt;p>凭借互联网的媒介，结交志同道合的朋友，为未来的事业做准备。&lt;/p>
&lt;h3 id="关于本站">关于本站&lt;/h3>
&lt;p>Log something useless, but interesting!&lt;/p>
&lt;p>学习日记，点滴记录。&lt;/p>
&lt;p>也会收集和分享互联网上比较经典且具有价值的文章。&lt;/p>
&lt;h3 id="站长是谁">站长是谁：&lt;/h3>
&lt;p>昵称：白菜&lt;/p>
&lt;h3 id="我的主页">我的主页&lt;/h3>
&lt;p>&lt;a href="https://blog.baicai.me">https://blog.baicai.me&lt;/a>&lt;/p>
&lt;h3 id="未来发展">未来发展：&lt;/h3>
&lt;p>未来很长，且慢慢耕耘。&lt;/p>
&lt;h3 id="白菜的博客小站历程">白菜的博客小站历程：&lt;/h3>
&lt;pre>&lt;code>2023年9月2日 通过github action自动构建发布到静态仓库(github page)。
&lt;/code>&lt;/pre>
&lt;h3 id="特别感谢">特别感谢&lt;/h3>
&lt;p>非常感谢每一位走进本站的同学对我们的大力支持，你们的走进是我坚持的动力！&lt;/p>
&lt;p>如果不介意,请把本站分享给您的同学朋友！&lt;/p>
&lt;p>我会一直努力，不求最好，只求更好！&lt;/p></description></item><item><title>Hello world</title><link>https://blog.baicai.me/article/2021/hello_world/</link><pubDate>Tue, 11 May 2021 14:00:54 +0800</pubDate><author>admin@baicai.me (白菜)</author><guid>https://blog.baicai.me/article/2021/hello_world/</guid><description>&lt;h1 id="hello-world">Hello World!&lt;/h1>
&lt;pre>&lt;code>^_^
&lt;/code>&lt;/pre></description></item></channel></rss>