<?xml version="1.0" encoding="UTF-8"?><rss xmlns:dc="http://purl.org/dc/elements/1.1/" xmlns:content="http://purl.org/rss/1.0/modules/content/" xmlns:atom="http://www.w3.org/2005/Atom" version="2.0"><channel><title><![CDATA[Carry の Blog]]></title><description><![CDATA[💻学习📝记录🔗分享
好记性不如烂笔头，沉下心来，认真总结，打造自己的知识库。]]></description><link>https://www.ranisa.cn</link><generator>RSS for Node</generator><lastBuildDate>Wed, 29 Jul 2026 13:13:40 GMT</lastBuildDate><atom:link href="https://www.ranisa.cn/rss.xml" rel="self" type="application/rss+xml"/><copyright><![CDATA[Carry の Blog]]></copyright><language><![CDATA[zh-CN]]></language><item><title><![CDATA[实用linux命令-nc]]></title><description><![CDATA[<hr>
<p>title: 实用linux命令-nc
date: 2022-03-10 02:52:51
permalink: /pages/523c20/
categories:</p>
<ul>
<li>Linux笔记</li>
<li>工作笔记
tags:</li>
<li>Linux</li>
<li>运维</li>
</ul>
<hr>
<p>::: tip 版本说明
本文写于 2022-03。&lt;br&gt;<code>nc</code> 命令用法多年未变，经 2026-07 复核仍适用。
:::</p>
<p><strong>nc传输文件</strong></p>
<pre><code class="language-bash">#发送文件
nc -l 1234 &lt; logstash-7.8.1.rpm
#接受文件
nc 10.0.0.62 1234 &gt; logstash-7.8.1.rpm

#发送文件夹
tar zcvf - test/ | nc 10.0.181.23 1234
#接受文件夹
nc -l 1234 | tar zxvf -
</code></pre>
<hr>
<p><strong>nc网络调试工具</strong></p>
<p><code>nc</code>（Netcat）不仅可以用于文件传输，还可以在网络调试中发挥重要作用。以下是一些常见的调试用法：</p>
<ol>
<li>
<p><strong>测试端口是否开放</strong></p>
<pre><code class="language-bash">nc -zv 10.0.0.62 80
</code></pre>
<p>说明：</p>
<ul>
<li><code>-z</code>：只扫描端口，不发送数据。</li>
<li><code>-v</code>：启用详细输出。</li>
<li>如果端口开放，会显示“成功连接”；如果端口关闭，会显示“连接失败”。</li>
</ul>
</li>
<li>
<p><strong>模拟服务器监听端口</strong></p>
<pre><code class="language-bash">nc -l 8080
</code></pre>
<p>说明：</p>
<ul>
<li><code>-l</code>：监听指定端口。</li>
<li>可以用来模拟一个简单的服务器，接收来自客户端的数据。</li>
</ul>
</li>
<li>
<p><strong>发送消息到远程服务器</strong></p>
<pre><code class="language-bash">echo &quot;Hello, Server!&quot; | nc 10.0.0.62 8080
</code></pre>
<p>说明：</p>
<ul>
<li><code>echo</code>命令将消息发送到指定的服务器和端口。</li>
<li>可用于测试服务器的接收功能。</li>
</ul>
</li>
<li>
<p><strong>创建简易聊天服务</strong>
在一台机器上运行：</p>
<pre><code class="language-bash">nc -l 12345
</code></pre>
<p>在另一台机器上运行：</p>
<pre><code class="language-bash">nc 10.0.0.62 12345
</code></pre>
<p>说明：</p>
<ul>
<li>两台机器可以通过输入消息进行实时聊天。</li>
</ul>
</li>
</ol>
<hr>
<p><strong>nc高级用法</strong></p>
<ol>
<li>
<p><strong>探测开放端口范围</strong></p>
<pre><code class="language-bash">nc -zv 10.0.0.62 20-100
</code></pre>
<p>说明：</p>
<ul>
<li>探测目标机器指定范围内的开放端口。</li>
</ul>
</li>
<li>
<p><strong>传输加密数据</strong>
使用<code>openssl</code>结合<code>nc</code>实现加密传输：</p>
<pre><code class="language-bash"># 发送端
tar zcvf - test/ | openssl enc -aes-256-cbc -salt -out - | nc 10.0.0.62 1234
# 接收端
nc -l 1234 | openssl enc -d -aes-256-cbc -salt -in - | tar zxvf -
</code></pre>
<p>说明：</p>
<ul>
<li><code>openssl enc</code>：使用AES-256加密数据。</li>
<li>传输过程中保证数据的安全性。</li>
</ul>
</li>
<li>
<p><strong>文件传输进度显示</strong>
使用<code>pv</code>显示传输进度：</p>
<pre><code class="language-bash"># 发送端
tar zcvf - test/ | pv | nc 10.0.0.62 1234
# 接收端
nc -l 1234 | pv | tar zxvf -
</code></pre>
<p>说明：</p>
<ul>
<li><code>pv</code>：显示数据流的传输进度。</li>
</ul>
</li>
</ol>
<hr>
<p><strong>nc注意事项</strong></p>
<ol>
<li>
<p><strong>安全性</strong></p>
<ul>
<li><code>nc</code>默认不加密数据，传输敏感信息时需结合加密工具（如<code>openssl</code>）。</li>
<li>避免在公网环境中直接使用<code>nc</code>传输数据。</li>
</ul>
</li>
<li>
<p><strong>权限问题</strong></p>
<ul>
<li>使用低端口（如80、443）时可能需要<code>sudo</code>权限。</li>
</ul>
</li>
<li>
<p><strong>替代工具</strong></p>
<ul>
<li>如果需要更高级的功能，可以使用<code>ncat</code>（<code>nc</code>的增强版）或其他网络工具如<code>scp</code>、<code>rsync</code>。</li>
</ul>
</li>
</ol>
<hr>
]]></description><link>https://www.ranisa.cn/pages/523c20/</link><guid isPermaLink="true">https://www.ranisa.cn/pages/523c20/</guid><pubDate>Wed, 29 Jul 2026 00:00:00 GMT</pubDate></item><item><title><![CDATA[实用linux命令-ss]]></title><description><![CDATA[<hr>
<p>title: 实用linux命令-ss
date: 2025-03-30 07:42:15
permalink: /pages/523c22/
categories:</p>
<ul>
<li>Linux笔记</li>
<li>工作笔记
tags:</li>
<li>Linux</li>
<li>运维</li>
</ul>
<hr>
<p><strong>ss命令简介</strong></p>
<p><code>ss</code>（Socket Statistics）是一个用于显示网络套接字信息的强大工具，它是<code>netstat</code>命令的现代替代品。<code>ss</code>命令速度更快，功能更强大，可以显示更多的网络连接信息。它能查看TCP、UDP、DCCP、RAW等类型的套接字连接。</p>
<hr>
<p><strong>ss常见用法</strong></p>
<ol>
<li>
<p><strong>查看所有网络连接</strong></p>
<pre><code class="language-bash">ss
</code></pre>
<p>说明：</p>
<ul>
<li>默认显示已建立的非监听TCP连接。</li>
</ul>
</li>
<li>
<p><strong>查看所有监听端口</strong></p>
<pre><code class="language-bash">ss -l
</code></pre>
<p>说明：</p>
<ul>
<li><code>-l</code>选项显示所有处于监听状态的套接字。</li>
</ul>
</li>
<li>
<p><strong>查看TCP连接</strong></p>
<pre><code class="language-bash">ss -t
</code></pre>
<p>说明：</p>
<ul>
<li><code>-t</code>选项只显示TCP连接。</li>
<li>可以与<code>-a</code>组合使用：<code>ss -ta</code>显示所有TCP连接（包括监听状态）。</li>
</ul>
</li>
<li>
<p><strong>查看UDP连接</strong></p>
<pre><code class="language-bash">ss -u
</code></pre>
<p>说明：</p>
<ul>
<li><code>-u</code>选项只显示UDP连接。</li>
<li>可以与<code>-a</code>组合使用：<code>ss -ua</code>显示所有UDP连接。</li>
</ul>
</li>
<li>
<p><strong>查看指定端口的连接</strong></p>
<pre><code class="language-bash">ss -t src/dst :&lt;端口号&gt;
</code></pre>
<p>说明：</p>
<ul>
<li><code>src</code>表示源端口，<code>dst</code>表示目标端口。</li>
<li>例如：<code>ss -t dst :80</code>显示目标端口为80的所有TCP连接。</li>
</ul>
</li>
<li>
<p><strong>显示进程信息</strong></p>
<pre><code class="language-bash">ss -p
</code></pre>
<p>说明：</p>
<ul>
<li><code>-p</code>选项显示使用套接字的进程信息。</li>
<li>需要root权限才能查看所有进程。</li>
</ul>
</li>
</ol>
<hr>
<p><strong>ss高级用法</strong></p>
<ol>
<li>
<p><strong>按状态过滤连接</strong></p>
<pre><code class="language-bash">ss state &lt;状态&gt; 
</code></pre>
<p>说明：</p>
<ul>
<li>常见状态包括：established、syn-sent、syn-recv、fin-wait-1等。</li>
<li>例如：<code>ss state established</code>显示所有已建立的连接。</li>
</ul>
</li>
<li>
<p><strong>显示详细统计信息</strong></p>
<pre><code class="language-bash">ss -i
</code></pre>
<p>说明：</p>
<ul>
<li><code>-i</code>选项显示TCP内部信息，如拥塞窗口、重传计数器等。</li>
</ul>
</li>
<li>
<p><strong>按地址过滤</strong></p>
<pre><code class="language-bash">ss dst &lt;IP地址&gt;
</code></pre>
<p>说明：</p>
<ul>
<li>过滤特定目标IP地址的连接。</li>
<li>例如：<code>ss dst 192.168.1.1</code>显示所有连接到该IP的套接字。</li>
</ul>
</li>
<li>
<p><strong>结合条件表达式</strong></p>
<pre><code class="language-bash">ss -t '( dport = :http or dport = :https )'
</code></pre>
<p>说明：</p>
<ul>
<li>使用表达式组合多个条件，查找连接到HTTP或HTTPS端口的TCP连接。</li>
</ul>
</li>
<li>
<p><strong>查看内存使用情况</strong></p>
<pre><code class="language-bash">ss -m
</code></pre>
<p>说明：</p>
<ul>
<li><code>-m</code>选项显示套接字的内存使用情况。</li>
</ul>
</li>
<li>
<p><strong>实时监控网络连接</strong></p>
<pre><code class="language-bash">watch -n 1 'ss -t'
</code></pre>
<p>说明：</p>
<ul>
<li>每秒刷新一次，实时监控TCP连接状态。</li>
</ul>
</li>
</ol>
<hr>
<p><strong>ss与netstat的比较</strong></p>
<ol>
<li>
<p><strong>性能优势</strong></p>
<ul>
<li><code>ss</code>命令直接从内核空间获取信息，速度比<code>netstat</code>快很多。</li>
<li>在有大量连接的系统上，<code>ss</code>的优势尤为明显。</li>
</ul>
</li>
<li>
<p><strong>功能对比</strong></p>
<ul>
<li><code>ss</code>提供更多的过滤选项和更详细的连接信息。</li>
<li><code>ss</code>可以显示更多的TCP状态信息，如TCP内部队列。</li>
</ul>
</li>
<li>
<p><strong>语法差异</strong></p>
<ul>
<li><code>netstat</code>: <code>netstat -tuln</code>（显示所有监听的TCP和UDP端口）</li>
<li><code>ss</code>: <code>ss -tuln</code>（相同功能，但速度更快）</li>
</ul>
</li>
</ol>
<hr>
<p><strong>ss注意事项</strong></p>
<ol>
<li>
<p><strong>权限要求</strong></p>
<ul>
<li>查看所有连接的详细信息（特别是与进程相关的信息）需要root权限。</li>
</ul>
</li>
<li>
<p><strong>输出格式</strong></p>
<ul>
<li>默认输出可能较为紧凑，可使用<code>-r</code>选项解析主机名，使输出更易读。</li>
</ul>
</li>
<li>
<p><strong>与其他工具配合</strong></p>
<ul>
<li>可与<code>grep</code>、<code>awk</code>等命令结合使用，进一步过滤和处理输出结果。</li>
</ul>
<pre><code class="language-bash">ss -t | grep ESTAB | wc -l  # 统计已建立的TCP连接数
</code></pre>
</li>
</ol>
<hr>
]]></description><link>https://www.ranisa.cn/pages/523c22/</link><guid isPermaLink="true">https://www.ranisa.cn/pages/523c22/</guid><pubDate>Wed, 29 Jul 2026 00:00:00 GMT</pubDate></item><item><title><![CDATA[实用linux命令-lsof]]></title><description><![CDATA[<hr>
<p>title: 实用linux命令-lsof
date: 2025-03-30 07:30:05
permalink: /pages/523c21/
categories:</p>
<ul>
<li>Linux笔记</li>
<li>工作笔记
tags:</li>
<li>Linux</li>
<li>运维</li>
</ul>
<hr>
<p><strong>lsof命令简介</strong></p>
<p><code>lsof</code>（List Open Files）是一个非常强大的工具，用于显示当前系统中被打开的文件信息。由于在Linux中几乎所有内容都是文件（包括普通文件、目录、套接字、管道、设备等），<code>lsof</code>的作用非常广泛，可用于系统监控、故障排查和安全审计等场景。</p>
<hr>
<p><strong>lsof常见用法</strong></p>
<ol>
<li>
<p><strong>查看所有打开的文件</strong></p>
<pre><code class="language-bash">lsof
</code></pre>
<p>说明：</p>
<ul>
<li>不带参数时，显示所有进程打开的所有文件。</li>
<li>输出可能非常多，通常需要结合过滤命令使用。</li>
</ul>
</li>
<li>
<p><strong>查看被某个进程打开的文件</strong></p>
<pre><code class="language-bash">lsof -p &lt;PID&gt;
</code></pre>
<p>说明：</p>
<ul>
<li><code>&lt;PID&gt;</code>：指定进程ID。</li>
<li>列出该进程打开的所有文件，包括普通文件、目录、库文件等。</li>
</ul>
</li>
<li>
<p><strong>查看某个文件被哪些进程打开</strong></p>
<pre><code class="language-bash">lsof &lt;文件路径&gt;
</code></pre>
<p>说明：</p>
<ul>
<li>显示打开该文件的所有进程信息。</li>
<li>对于排查文件锁定或无法删除文件的情况很有用。</li>
</ul>
</li>
<li>
<p><strong>查看某个端口被哪个进程占用</strong></p>
<pre><code class="language-bash">lsof -i:&lt;端口号&gt;
</code></pre>
<p>说明：</p>
<ul>
<li><code>&lt;端口号&gt;</code>：指定端口号。</li>
<li>常用于排查端口占用问题，如确认服务是否正在运行。</li>
</ul>
</li>
<li>
<p><strong>查看所有网络连接</strong></p>
<pre><code class="language-bash">lsof -i
</code></pre>
<p>说明：</p>
<ul>
<li>显示所有与网络相关的文件，包括TCP、UDP连接。</li>
<li>可以看到每个连接的本地地址、远程地址、状态等信息。</li>
</ul>
</li>
<li>
<p><strong>列出某用户打开的文件</strong></p>
<pre><code class="language-bash">lsof -u &lt;用户名&gt;
</code></pre>
<p>说明：</p>
<ul>
<li><code>&lt;用户名&gt;</code>：指定用户名。</li>
<li>列出该用户打开的所有文件，可用于监控用户活动。</li>
</ul>
</li>
</ol>
<hr>
<p><strong>lsof高级用法</strong></p>
<ol>
<li>
<p><strong>查看特定类型的文件</strong></p>
<pre><code class="language-bash">lsof -d &lt;文件描述符&gt;
</code></pre>
<p>说明：</p>
<ul>
<li><code>&lt;文件描述符&gt;</code>可以是数字或名称，如<code>cwd</code>（当前工作目录）、<code>txt</code>（程序代码）、<code>mem</code>（内存映射文件）。</li>
<li>例如：<code>lsof -d cwd</code>查看所有进程的当前工作目录。</li>
</ul>
</li>
<li>
<p><strong>监控文件的实时变化</strong></p>
<pre><code class="language-bash">watch -n 1 'lsof &lt;文件路径&gt;'
</code></pre>
<p>说明：</p>
<ul>
<li>每秒钟刷新一次，实时监控文件的打开情况。</li>
<li>对于排查文件访问问题非常有用。</li>
</ul>
</li>
<li>
<p><strong>查看某进程的网络连接</strong></p>
<pre><code class="language-bash">lsof -p &lt;PID&gt; -i
</code></pre>
<p>说明：</p>
<ul>
<li>结合<code>-p</code>和<code>-i</code>选项，显示指定进程的所有网络连接。</li>
<li>可以精确了解某应用程序的网络活动。</li>
</ul>
</li>
<li>
<p><strong>按协议过滤网络连接</strong></p>
<pre><code class="language-bash">lsof -i &lt;协议&gt;
</code></pre>
<p>说明：</p>
<ul>
<li><code>&lt;协议&gt;</code>可以是<code>tcp</code>或<code>udp</code>。</li>
<li>例如：<code>lsof -i tcp</code>只显示TCP连接。</li>
</ul>
</li>
<li>
<p><strong>查看特定网络地址的连接</strong></p>
<pre><code class="language-bash">lsof -i@&lt;主机名或IP&gt;
</code></pre>
<p>说明：</p>
<ul>
<li>过滤显示与特定主机相关的连接。</li>
<li>例如：<code>lsof -i@192.168.1.1</code>显示与该IP相关的所有连接。</li>
</ul>
</li>
<li>
<p><strong>杀死占用某文件的进程</strong></p>
<pre><code class="language-bash">kill -9 $(lsof -t &lt;文件路径&gt;)
</code></pre>
<p>说明：</p>
<ul>
<li><code>-t</code>选项只输出进程ID，结合<code>kill</code>命令可以快速终止占用文件的进程。</li>
<li>在无法删除或修改文件时特别有用。</li>
</ul>
</li>
</ol>
<hr>
<p><strong>lsof与其他工具的配合</strong></p>
<ol>
<li>
<p><strong>与grep结合使用</strong></p>
<pre><code class="language-bash">lsof | grep &lt;关键词&gt;
</code></pre>
<p>说明：</p>
<ul>
<li>通过关键词过滤<code>lsof</code>的输出结果，提高查找效率。</li>
<li>例如：<code>lsof | grep '/var/log'</code>查找打开日志目录文件的进程。</li>
</ul>
</li>
<li>
<p><strong>与网络工具对比</strong></p>
<ul>
<li><code>lsof -i</code>与<code>netstat</code>、<code>ss</code>命令功能有重叠，但<code>lsof</code>提供了更多与进程相关的信息。</li>
<li>对于网络连接排查，可以根据具体需求选择最合适的工具。</li>
</ul>
</li>
<li>
<p><strong>与文件系统工具结合</strong></p>
<pre><code class="language-bash">lsof +D &lt;目录路径&gt;
</code></pre>
<p>说明：</p>
<ul>
<li>递归显示指定目录下被打开的所有文件。</li>
<li>例如：<code>lsof +D /var/www</code>查看Web目录下所有被访问的文件。</li>
</ul>
</li>
</ol>
<hr>
<p><strong>lsof注意事项</strong></p>
<ol>
<li>
<p><strong>权限要求</strong></p>
<ul>
<li>普通用户只能查看自己拥有权限的进程和文件信息。</li>
<li>使用<code>sudo</code>或root用户可以查看系统中所有的文件打开情况。</li>
</ul>
</li>
<li>
<p><strong>性能影响</strong></p>
<ul>
<li><code>lsof</code>需要扫描整个系统的文件表，在大型系统上可能会消耗较多资源。</li>
<li>建议在必要时使用，并尽可能使用过滤条件限制输出范围。</li>
</ul>
</li>
<li>
<p><strong>输出格式</strong></p>
<ul>
<li><code>lsof</code>的默认输出包含多列信息，可使用<code>-F</code>选项生成更易于脚本处理的格式。</li>
<li>使用<code>-l</code>选项可以显示用户ID而非用户名，提高处理速度。</li>
</ul>
</li>
</ol>
<hr>
]]></description><link>https://www.ranisa.cn/pages/523c21/</link><guid isPermaLink="true">https://www.ranisa.cn/pages/523c21/</guid><pubDate>Wed, 29 Jul 2026 00:00:00 GMT</pubDate></item><item><title><![CDATA[Bash 备忘清单]]></title><description><![CDATA[<hr>
<p>title: Bash 备忘清单
date: 2022-03-17 11:21:42
permalink: /pages/b11f9q/
categories:</p>
<ul>
<li>Linux笔记</li>
<li>工作笔记
tags:</li>
<li>Linux</li>
<li>运维</li>
</ul>
<hr>
<p>::: tip 版本说明
本文写于 2022-03。&lt;br&gt;Bash 语法长期稳定，经 2026-07 复核仍适用。
:::</p>
<p>这是开始使用 linux bash shell 脚本的快速参考备忘单。</p>
<h2>入门</h2>
<h3>hello.sh</h3>
<pre><code class="language-bash">#!/bin/bash
VAR=&quot;world&quot;
echo &quot;Hello $VAR!&quot; # =&gt; Hello world!
</code></pre>
<p>执行脚本</p>
<pre><code class="language-shell">$ bash hello.sh
</code></pre>
<h3>变量</h3>
<pre><code class="language-bash">NAME=&quot;John&quot;
echo ${NAME}    # =&gt; John (变量)
echo $NAME      # =&gt; John (变量)
echo &quot;$NAME&quot;    # =&gt; John (变量)
echo '$NAME'    # =&gt; $NAME (字符串原样输出)
echo &quot;${NAME}!&quot; # =&gt; John! (变量)
NAME = &quot;John&quot;   # =&gt; Error (注意不能有空格)
</code></pre>
<h3>注释</h3>
<pre><code class="language-shell"># 这是一个内联 Bash 注释。

: '
这是一个
非常整洁的
bash 注释
'
</code></pre>
<p>多行注释使用 <code>:'</code> 打开和 <code>'</code> 关闭</p>
<h3>参数</h3>
<p>&lt;!--rehype:wrap-class=row-span-2--&gt;</p>
<table>
<thead>
<tr>
<th style="text-align:left">表示</th>
<th>描述</th>
</tr>
</thead>
<tbody>
<tr>
<td style="text-align:left"><code>$1</code> … <code>$9</code></td>
<td>参数 1 ... 9</td>
</tr>
<tr>
<td style="text-align:left"><code>$0</code></td>
<td>脚本本身的名称</td>
</tr>
<tr>
<td style="text-align:left"><code>$1</code></td>
<td>第一个参数</td>
</tr>
<tr>
<td style="text-align:left"><code>${10}</code></td>
<td>位置参数 10</td>
</tr>
<tr>
<td style="text-align:left"><code>$#</code></td>
<td>参数数量</td>
</tr>
<tr>
<td style="text-align:left"><code>$$</code></td>
<td>shell 的进程 id</td>
</tr>
<tr>
<td style="text-align:left"><code>$*</code></td>
<td>所有参数</td>
</tr>
<tr>
<td style="text-align:left"><code>$@</code></td>
<td>所有参数，从第一个开始</td>
</tr>
<tr>
<td style="text-align:left"><code>$-</code></td>
<td>当前选项</td>
</tr>
<tr>
<td style="text-align:left"><code>$_</code></td>
<td>上一个命令的最后一个参数</td>
</tr>
</tbody>
</table>
<p>见：<a href="http://wiki.bash-hackers.org/syntax/shellvars#special_parameters_and_shell_variables">特殊参数</a></p>
<h3>函数</h3>
<pre><code class="language-bash">get_name() {
    echo &quot;John&quot;
}
echo &quot;You are $(get_name)&quot;
</code></pre>
<p>见：<a href="#bash-%E5%87%BD%E6%95%B0">函数</a></p>
<h3>条件句</h3>
<pre><code class="language-bash">if [[ -z &quot;$string&quot; ]]; then
    echo &quot;String is empty&quot;
elif [[ -n &quot;$string&quot; ]]; then
    echo &quot;String is not empty&quot;
fi
</code></pre>
<p>见：<a href="#bash-%E6%9D%A1%E4%BB%B6%E5%8F%A5">条件句</a></p>
<h3>大括号扩展</h3>
<pre><code class="language-shell">echo {A,B}.js
</code></pre>
<hr>
<table>
<thead>
<tr>
<th style="text-align:left">表示</th>
<th>描述</th>
</tr>
</thead>
<tbody>
<tr>
<td style="text-align:left"><code>{A,B}</code></td>
<td>与 <code>A B</code> 相同</td>
</tr>
<tr>
<td style="text-align:left"><code>{A,B}.js</code></td>
<td>与 <code>A.js B.js</code> 相同</td>
</tr>
<tr>
<td style="text-align:left"><code>{1..5}</code></td>
<td>与 <code>1 2 3 4 5</code> 相同</td>
</tr>
</tbody>
</table>
<p>见：<a href="http://wiki.bash-hackers.org/syntax/expansion/brace">大括号扩展</a></p>
<h3>Shell 执行</h3>
<pre><code class="language-bash"># =&gt; I'm in /当前/的/路径
echo &quot;I'm in $(PWD)&quot;
# Same as:
echo &quot;I'm in `pwd`&quot;
</code></pre>
<p>见：<a href="http://wiki.bash-hackers.org/syntax/expansion/cmdsubst">命令替换</a></p>
<h2>Bash 参数扩展</h2>
<h3>语法</h3>
<p>&lt;!--rehype:wrap-class=row-span-2--&gt;</p>
<table>
<thead>
<tr>
<th style="text-align:left">代码</th>
<th>描述</th>
</tr>
</thead>
<tbody>
<tr>
<td style="text-align:left"><code>${FOO%suffix}</code></td>
<td>删除后缀</td>
</tr>
<tr>
<td style="text-align:left"><code>${FOO#prefix}</code></td>
<td>删除前缀</td>
</tr>
<tr>
<td style="text-align:left"><code>${FOO%%suffix}</code></td>
<td>去掉长后缀</td>
</tr>
<tr>
<td style="text-align:left"><code>${FOO##prefix}</code></td>
<td>删除长前缀</td>
</tr>
<tr>
<td style="text-align:left"><code>${FOO/from/to}</code></td>
<td>替换第一个匹配项</td>
</tr>
<tr>
<td style="text-align:left"><code>${FOO//from/to}</code></td>
<td>全部替换</td>
</tr>
<tr>
<td style="text-align:left"><code>${FOO/%from/to}</code></td>
<td>替换后缀</td>
</tr>
<tr>
<td style="text-align:left"><code>${FOO/#from/to}</code></td>
<td>替换前缀</td>
</tr>
</tbody>
</table>
<h4>子字符串</h4>
<table>
<thead>
<tr>
<th style="text-align:left">表示</th>
<th>描述</th>
</tr>
</thead>
<tbody>
<tr>
<td style="text-align:left"><code>${FOO:0:3}</code></td>
<td>子串 <em>(位置，长度)</em></td>
</tr>
<tr>
<td style="text-align:left"><code>${FOO:(-3):3}</code></td>
<td>从右边开始的子串</td>
</tr>
</tbody>
</table>
<h4>Length</h4>
<table>
<thead>
<tr>
<th style="text-align:left">表示</th>
<th>描述</th>
</tr>
</thead>
<tbody>
<tr>
<td style="text-align:left"><code>${#FOO}</code></td>
<td><code>$FOO</code> 的长度</td>
</tr>
</tbody>
</table>
<h4>默认值</h4>
<table>
<thead>
<tr>
<th style="text-align:left">表示</th>
<th>描述</th>
</tr>
</thead>
<tbody>
<tr>
<td style="text-align:left"><code>${FOO:-val}</code></td>
<td><code>$FOO</code>，如果未设置，则为 <code>val</code></td>
</tr>
<tr>
<td style="text-align:left"><code>${FOO:=val}</code></td>
<td>如果未设置，则将 <code>$FOO</code> 设置为 <code>val</code></td>
</tr>
<tr>
<td style="text-align:left"><code>${FOO:+val}</code></td>
<td><code>val</code> 如果设置了<code>$FOO</code></td>
</tr>
<tr>
<td style="text-align:left"><code>${FOO:?message}</code></td>
<td>如果 <code>$FOO</code> 未设置，则显示消息并退出</td>
</tr>
</tbody>
</table>
<h3>替代 Substitution</h3>
<pre><code class="language-bash">echo ${food:-Cake}  #=&gt; $food or &quot;Cake&quot;
</code></pre>
<pre><code class="language-bash">STR=&quot;/path/to/foo.cpp&quot;
echo ${STR%.cpp}    # /path/to/foo
echo ${STR%.cpp}.o  # /path/to/foo.o
echo ${STR%/*}      # /path/to
echo ${STR##*.}     # cpp (extension)
echo ${STR##*/}     # foo.cpp (basepath)
echo ${STR#*/}      # path/to/foo.cpp
echo ${STR##*/}     # foo.cpp
echo ${STR/foo/bar} # /path/to/bar.cpp
</code></pre>
<h3>切片 Slicing</h3>
<pre><code class="language-bash">name=&quot;John&quot;
echo ${name}           # =&gt; John
echo ${name:0:2}       # =&gt; Jo
echo ${name::2}        # =&gt; Jo
echo ${name::-1}       # =&gt; Joh
echo ${name:(-1)}      # =&gt; n
echo ${name:(-2)}      # =&gt; hn
echo ${name:(-2):2}    # =&gt; hn

length=2
echo ${name:0:length}  # =&gt; Jo
</code></pre>
<p>见：<a href="http://wiki.bash-hackers.org/syntax/pe">参数扩展</a></p>
<h3>基本路径和目录路径</h3>
<pre><code class="language-bash">SRC=&quot;/path/to/foo.cpp&quot;
</code></pre>
<pre><code class="language-bash">BASEPATH=${SRC##*/}   
echo $BASEPATH  # =&gt; &quot;foo.cpp&quot;

DIRPATH=${SRC%$BASEPATH}
echo $DIRPATH   # =&gt; &quot;/path/to/&quot;
</code></pre>
<h3>Transform</h3>
<pre><code class="language-bash">STR=&quot;HELLO WORLD!&quot;
echo ${STR,}      # =&gt; hELLO WORLD!
echo ${STR,,}     # =&gt; hello world!

STR=&quot;hello world!&quot;
echo ${STR^}      # =&gt; Hello world!
echo ${STR^^}     # =&gt; HELLO WORLD!

ARR=(hello World)
echo &quot;${ARR[@],}&quot; # =&gt; hello world
echo &quot;${ARR[@]^}&quot; # =&gt; Hello World
</code></pre>
<h2>Bash 数组</h2>
<h3>定义数组</h3>
<pre><code class="language-bash">Fruits=('Apple' 'Banana' 'Orange')

Fruits[0]=&quot;Apple&quot;
Fruits[1]=&quot;Banana&quot;
Fruits[2]=&quot;Orange&quot;

ARRAY1=(foo{1..2}) # =&gt; foo1 foo2
ARRAY2=({A..D})    # =&gt; A B C D

# 合并 =&gt; foo1 foo2 A B C D
ARRAY3=(${ARRAY1[@]} ${ARRAY2[@]})

# 声明构造
declare -a Numbers=(1 2 3)
Numbers+=(4 5) # 附加 =&gt; 1 2 3 4 5
</code></pre>
<h3>索引</h3>
<table>
<thead>
<tr>
<th style="text-align:left">:-</th>
<th>-</th>
</tr>
</thead>
<tbody>
<tr>
<td style="text-align:left"><code>${Fruits[0]}</code></td>
<td>第一个元素</td>
</tr>
<tr>
<td style="text-align:left"><code>${Fruits[-1]}</code></td>
<td>最后一个元素</td>
</tr>
<tr>
<td style="text-align:left"><code>${Fruits[*]}</code></td>
<td>所有元素</td>
</tr>
<tr>
<td style="text-align:left"><code>${Fruits[@]}</code></td>
<td>所有元素</td>
</tr>
<tr>
<td style="text-align:left"><code>${#Fruits[@]}</code></td>
<td>总数</td>
</tr>
<tr>
<td style="text-align:left"><code>${#Fruits}</code></td>
<td>第一节长度</td>
</tr>
<tr>
<td style="text-align:left"><code>${#Fruits[3]}</code></td>
<td>第n个长度</td>
</tr>
<tr>
<td style="text-align:left"><code>${Fruits[@]:3:2}</code></td>
<td>范围</td>
</tr>
<tr>
<td style="text-align:left"><code>${!Fruits[@]}</code></td>
<td>所有 Key</td>
</tr>
</tbody>
</table>
<h3>迭代 Iteration</h3>
<pre><code class="language-bash">Fruits=('Apple' 'Banana' 'Orange')
for e in &quot;${Fruits[@]}&quot;; do
    echo $e
done
</code></pre>
<h4>With index</h4>
<pre><code class="language-bash">for i in &quot;${!Fruits[@]}&quot;; do
  printf &quot;%s\t%s\n&quot; &quot;$i&quot; &quot;${Fruits[$i]}&quot;
done
</code></pre>
<h3>操作</h3>
<p>&lt;!--rehype:wrap-class=col-span-2--&gt;</p>
<pre><code class="language-bash">Fruits=(&quot;${Fruits[@]}&quot; &quot;Watermelon&quot;)         # 添加
Fruits+=('Watermelon')                       # 也是添加
Fruits=( ${Fruits[@]/Ap*/} )                 # 通过正则表达式匹配删除
unset Fruits[2]                              # 删除一项
Fruits=(&quot;${Fruits[@]}&quot;)                      # 复制
Fruits=(&quot;${Fruits[@]}&quot; &quot;${Veggies[@]}&quot;)      # 连接
lines=(`cat &quot;logfile&quot;`)                      # 从文件中读取
</code></pre>
<h3>数组作为参数</h3>
<pre><code class="language-bash">function extract()
{
  local -n myarray=$1
  local idx=$2
  echo &quot;${myarray[$idx]}&quot;
}
Fruits=('Apple' 'Banana' 'Orange')
extract Fruits 2     # =&gt; Orangle
</code></pre>
<h2>Bash 字典</h2>
<h3>定义</h3>
<pre><code class="language-bash">declare -A sounds
</code></pre>
<pre><code class="language-bash">sounds[dog]=&quot;bark&quot;
sounds[cow]=&quot;moo&quot;
sounds[bird]=&quot;tweet&quot;
sounds[wolf]=&quot;howl&quot;
</code></pre>
<h3>使用字典</h3>
<pre><code class="language-bash">echo ${sounds[dog]} # Dog's sound
echo ${sounds[@]}   # All values
echo ${!sounds[@]}  # All keys
echo ${#sounds[@]}  # Number of elements
unset sounds[dog]   # Delete dog
</code></pre>
<h3>迭代</h3>
<pre><code class="language-bash">for val in &quot;${sounds[@]}&quot;; do
    echo $val
done
</code></pre>
<hr>
<pre><code class="language-bash">for key in &quot;${!sounds[@]}&quot;; do
    echo $key
done
</code></pre>
<h2>Bash 条件句</h2>
<h3>整数条件</h3>
<table>
<thead>
<tr>
<th style="text-align:left">条件</th>
<th>描述</th>
</tr>
</thead>
<tbody>
<tr>
<td style="text-align:left"><code>[[ NUM -eq NUM ]]</code></td>
<td>等于 &lt;yel&gt;Eq&lt;/yel&gt;ual</td>
</tr>
<tr>
<td style="text-align:left"><code>[[ NUM -ne NUM ]]</code></td>
<td>不等于 &lt;yel&gt;N&lt;/yel&gt;ot &lt;yel&gt;e&lt;/yel&gt;qual</td>
</tr>
<tr>
<td style="text-align:left"><code>[[ NUM -lt NUM ]]</code></td>
<td>小于 &lt;yel&gt;L&lt;/yel&gt;ess &lt;yel&gt;t&lt;/yel&gt;han</td>
</tr>
<tr>
<td style="text-align:left"><code>[[ NUM -le NUM ]]</code></td>
<td>小于等于 &lt;yel&gt;L&lt;/yel&gt;ess than or &lt;yel&gt;e&lt;/yel&gt;qual</td>
</tr>
<tr>
<td style="text-align:left"><code>[[ NUM -gt NUM ]]</code></td>
<td>大于 &lt;yel&gt;G&lt;/yel&gt;reater &lt;yel&gt;t&lt;/yel&gt;han</td>
</tr>
<tr>
<td style="text-align:left"><code>[[ NUM -ge NUM ]]</code></td>
<td>大于等于 &lt;yel&gt;G&lt;/yel&gt;reater than or &lt;yel&gt;e&lt;/yel&gt;qual</td>
</tr>
<tr>
<td style="text-align:left"><code>(( NUM &lt; NUM ))</code></td>
<td>小于</td>
</tr>
<tr>
<td style="text-align:left"><code>(( NUM &lt;= NUM ))</code></td>
<td>小于或等于</td>
</tr>
<tr>
<td style="text-align:left"><code>(( NUM &gt; NUM ))</code></td>
<td>比...更大</td>
</tr>
<tr>
<td style="text-align:left"><code>(( NUM &gt;= NUM ))</code></td>
<td>大于等于</td>
</tr>
</tbody>
</table>
<h3>字符串条件</h3>
<table>
<thead>
<tr>
<th style="text-align:left">条件</th>
<th>描述</th>
</tr>
</thead>
<tbody>
<tr>
<td style="text-align:left"><code>[[ -z STR ]]</code></td>
<td>空字符串</td>
</tr>
<tr>
<td style="text-align:left"><code>[[ -n STR ]]</code></td>
<td>&lt;yel&gt;非&lt;/yel&gt;空字符串</td>
</tr>
<tr>
<td style="text-align:left"><code>[[ STR == STR ]]</code></td>
<td>相等</td>
</tr>
<tr>
<td style="text-align:left"><code>[[ STR = STR ]]</code></td>
<td>相等(同上)</td>
</tr>
<tr>
<td style="text-align:left"><code>[[ STR &lt; STR ]]</code></td>
<td>小于 <em>(ASCII)</em></td>
</tr>
<tr>
<td style="text-align:left"><code>[[ STR &gt; STR ]]</code></td>
<td>大于 <em>(ASCII)</em></td>
</tr>
<tr>
<td style="text-align:left"><code>[[ STR != STR ]]</code></td>
<td>不相等</td>
</tr>
<tr>
<td style="text-align:left"><code>[[ STR =~ STR ]]</code></td>
<td>正则表达式</td>
</tr>
</tbody>
</table>
<h3>例子</h3>
<p>&lt;!--rehype:wrap-class=row-span-3--&gt;</p>
<h4>字符串</h4>
<pre><code class="language-bash">if [[ -z &quot;$string&quot; ]]; then
    echo &quot;String is empty&quot;
elif [[ -n &quot;$string&quot; ]]; then
    echo &quot;String is not empty&quot;
else
    echo &quot;This never happens&quot;
fi
</code></pre>
<h4>组合</h4>
<pre><code class="language-bash">if [[ X &amp;&amp; Y ]]; then
    ...
fi
</code></pre>
<h4>相等</h4>
<pre><code class="language-bash">if [[ &quot;$A&quot; == &quot;$B&quot; ]]; then
    ...
fi
</code></pre>
<h4>正则表达式</h4>
<pre><code class="language-bash">if [[ '1. abc' =~ ([a-z]+) ]]; then
    echo ${BASH_REMATCH[1]}
fi
</code></pre>
<h4>小于</h4>
<pre><code class="language-bash">if (( $a &lt; $b )); then
   echo &quot;$a is smaller than $b&quot;
fi
</code></pre>
<h4>存在</h4>
<pre><code class="language-bash">if [[ -e &quot;file.txt&quot; ]]; then
    echo &quot;file exists&quot;
fi
</code></pre>
<h3>文件条件</h3>
<p>&lt;!--rehype:wrap-class=row-span-2--&gt;</p>
<table>
<thead>
<tr>
<th style="text-align:left">条件</th>
<th>描述</th>
</tr>
</thead>
<tbody>
<tr>
<td style="text-align:left"><code>[[ -e FILE ]]</code></td>
<td>存在</td>
</tr>
<tr>
<td style="text-align:left"><code>[[ -d FILE ]]</code></td>
<td>目录</td>
</tr>
<tr>
<td style="text-align:left"><code>[[ -f FILE ]]</code></td>
<td>文件</td>
</tr>
<tr>
<td style="text-align:left"><code>[[ -h FILE ]]</code></td>
<td>符号链接</td>
</tr>
<tr>
<td style="text-align:left"><code>[[ -s FILE ]]</code></td>
<td>大小 &gt; 0 字节</td>
</tr>
<tr>
<td style="text-align:left"><code>[[ -r FILE ]]</code></td>
<td>可读</td>
</tr>
<tr>
<td style="text-align:left"><code>[[ -w FILE ]]</code></td>
<td>可写</td>
</tr>
<tr>
<td style="text-align:left"><code>[[ -x FILE ]]</code></td>
<td>可执行文件</td>
</tr>
<tr>
<td style="text-align:left"><code>[[ f1 -nt f2 ]]</code></td>
<td>f1 比 f2 新</td>
</tr>
<tr>
<td style="text-align:left"><code>[[ f1 -ot f2 ]]</code></td>
<td>f2 比 f1 新</td>
</tr>
<tr>
<td style="text-align:left"><code>[[ f1 -ef f2 ]]</code></td>
<td>相同的文件</td>
</tr>
</tbody>
</table>
<h3>更多条件</h3>
<table>
<thead>
<tr>
<th style="text-align:left">条件</th>
<th>描述</th>
</tr>
</thead>
<tbody>
<tr>
<td style="text-align:left"><code>[[ -o noclobber ]]</code></td>
<td>如果启用 OPTION</td>
</tr>
<tr>
<td style="text-align:left"><code>[[ ! EXPR ]]</code></td>
<td>不是 Not</td>
</tr>
<tr>
<td style="text-align:left"><code>[[ X &amp;&amp; Y ]]</code></td>
<td>和 And</td>
</tr>
<tr>
<td style="text-align:left"><code>[[ X \|\| Y ]]</code></td>
<td>或者 Or</td>
</tr>
</tbody>
</table>
<h3>逻辑和，或</h3>
<pre><code class="language-bash">if [ &quot;$1&quot; = 'y' -a $2 -gt 0 ]; then
    echo &quot;yes&quot;
fi
if [ &quot;$1&quot; = 'n' -o $2 -lt 0 ]; then
    echo &quot;no&quot;
fi
</code></pre>
<h2>Bash 循环</h2>
<h3>基本 for 循环</h3>
<pre><code class="language-bash">for i in /etc/rc.*; do
    echo $i
done
</code></pre>
<h3>类似 C 的 for 循环</h3>
<pre><code class="language-bash">for ((i = 0 ; i &lt; 100 ; i++)); do
    echo $i
done
</code></pre>
<h3>范围</h3>
<p>&lt;!--rehype:wrap-class=row-span-2--&gt;</p>
<pre><code class="language-bash">for i in {1..5}; do
    echo &quot;Welcome $i&quot;
done
</code></pre>
<h4>步长</h4>
<pre><code class="language-bash">for i in {5..50..5}; do
    echo &quot;Welcome $i&quot;
done
</code></pre>
<h3>自动递增</h3>
<pre><code class="language-bash">i=1
while [[ $i -lt 4 ]]; do
    echo &quot;Number: $i&quot;
    ((i++))
done
</code></pre>
<h3>自动递减</h3>
<pre><code class="language-bash">i=3
while [[ $i -gt 0 ]]; do
    echo &quot;Number: $i&quot;
    ((i--))
done
</code></pre>
<h3>Continue</h3>
<pre><code class="language-bash">for number in $(seq 1 3); do
    if [[ $number == 2 ]]; then
        continue;
    fi
    echo &quot;$number&quot;
done
</code></pre>
<h3>Break</h3>
<pre><code class="language-bash">for number in $(seq 1 3); do
    if [[ $number == 2 ]]; then
        # Skip entire rest of loop.
        break;
    fi
    # This will only print 1
    echo &quot;$number&quot;
done
</code></pre>
<h3>Until</h3>
<pre><code class="language-bash">count=0
until [ $count -gt 10 ]; do
    echo &quot;$count&quot;
    ((count++))
done
</code></pre>
<h3>死循环</h3>
<pre><code class="language-bash">while true; do
    # here is some code.
done
</code></pre>
<h3>死循环(简写)</h3>
<pre><code class="language-bash">while :; do
    # here is some code.
done
</code></pre>
<h3>读取文件的每一行</h3>
<pre><code class="language-bash">cat file.txt | while read line; do
    echo $line
done
</code></pre>
<h2>Bash 函数</h2>
<h3>定义函数</h3>
<pre><code class="language-bash">myfunc() {
  echo &quot;hello $1&quot;
}
</code></pre>
<pre><code class="language-bash"># 同上(替代语法)
function myfunc() {
  echo &quot;hello $1&quot;
}
</code></pre>
<pre><code class="language-bash">myfunc &quot;John&quot;
</code></pre>
<h3>返回值</h3>
<pre><code class="language-bash">myfunc() {
    local myresult='some value'
    echo $myresult
}
</code></pre>
<pre><code class="language-bash">result=&quot;$(myfunc)&quot;
</code></pre>
<h3>抛出错误</h3>
<pre><code class="language-bash">myfunc() {
    return 1
}
</code></pre>
<pre><code class="language-bash">if myfunc; then
    echo &quot;success&quot;
else
    echo &quot;failure&quot;
fi
</code></pre>
<h2>Bash 选项</h2>
<p>&lt;!--rehype:body-class=cols-2--&gt;</p>
<h3>选项</h3>
<pre><code class="language-bash"># 避免覆盖文件
# (echo &quot;hi&quot; &gt; foo)
set -o noclobber

# 用于出错时退出
# 避免级联错误
set -o errexit   

# 揭示隐藏的失败
set -o pipefail  

# 公开未设置的变量
set -o nounset
</code></pre>
<h3>全局选项</h3>
<pre><code class="language-bash"># 不匹配的 glob 被删除
# ('*.foo' =&gt; '')
shopt -s nullglob   

# 不匹配的 glob 抛出错误
shopt -s failglob  

# 不区分大小写的球体
shopt -s nocaseglob 

# 通配符匹配点文件
# (&quot;*.sh&quot; =&gt; &quot;.foo.sh&quot;)
shopt -s dotglob    

# 允许 ** 进行递归匹配
# ('lib/**/*.rb' =&gt; 'lib/a/b/c.rb')
shopt -s globstar   
</code></pre>
<h2>Bash 历史</h2>
<p>&lt;!--rehype:body-class=cols-2--&gt;</p>
<h3>命令</h3>
<table>
<thead>
<tr>
<th style="text-align:left">命令</th>
<th>描述</th>
</tr>
</thead>
<tbody>
<tr>
<td style="text-align:left"><code>history</code></td>
<td>显示历史</td>
</tr>
<tr>
<td style="text-align:left"><code>sudo !!</code></td>
<td>使用 sudo 运行上一个命令</td>
</tr>
<tr>
<td style="text-align:left"><code>shopt -s histverify</code></td>
<td>不要立即执行扩展结果</td>
</tr>
</tbody>
</table>
<h3>表达式</h3>
<table>
<thead>
<tr>
<th style="text-align:left">表达式</th>
<th>描述</th>
</tr>
</thead>
<tbody>
<tr>
<td style="text-align:left"><code>!$</code></td>
<td>展开最新命令的最后一个参数</td>
</tr>
<tr>
<td style="text-align:left"><code>!*</code></td>
<td>展开最新命令的所有参数</td>
</tr>
<tr>
<td style="text-align:left"><code>!-n</code></td>
<td>展开第 <code>n</code> 个最近的命令</td>
</tr>
<tr>
<td style="text-align:left"><code>!n</code></td>
<td>展开历史中的第 <code>n</code> 个命令</td>
</tr>
<tr>
<td style="text-align:left"><code>!&lt;command&gt;</code></td>
<td>展开最近调用的命令 <code>&lt;command&gt;</code></td>
</tr>
</tbody>
</table>
<h3>操作</h3>
<table>
<thead>
<tr>
<th style="text-align:left">代码</th>
<th>描述</th>
</tr>
</thead>
<tbody>
<tr>
<td style="text-align:left"><code>!!</code></td>
<td>再次执行最后一条命令</td>
</tr>
<tr>
<td style="text-align:left"><code>!!:s/&lt;FROM&gt;/&lt;TO&gt;/</code></td>
<td>在最近的命令中将第一次出现的 <code>&lt;FROM&gt;</code> 替换为 <code>&lt;TO&gt;</code></td>
</tr>
<tr>
<td style="text-align:left"><code>!!:gs/&lt;FROM&gt;/&lt;TO&gt;/</code></td>
<td>在最近的命令中将所有出现的 <code>&lt;FROM&gt;</code> 替换为 <code>&lt;TO&gt;</code></td>
</tr>
<tr>
<td style="text-align:left"><code>!$:t</code></td>
<td>仅从最近命令的最后一个参数扩展基本名称</td>
</tr>
<tr>
<td style="text-align:left"><code>!$:h</code></td>
<td>仅从最近命令的最后一个参数展开目录</td>
</tr>
</tbody>
</table>
<p><code>!!</code> 和 <code>!$</code> 可以替换为任何有效的扩展。</p>
<h3>切片 Slices</h3>
<table>
<thead>
<tr>
<th style="text-align:left">代码</th>
<th>描述</th>
</tr>
</thead>
<tbody>
<tr>
<td style="text-align:left"><code>!!:n</code></td>
<td>仅扩展最近命令中的第 <code>n</code> 个标记(命令为 <code>0</code>；第一个参数为 <code>1</code>)</td>
</tr>
<tr>
<td style="text-align:left"><code>!^</code></td>
<td>从最近的命令展开第一个参数</td>
</tr>
<tr>
<td style="text-align:left"><code>!$</code></td>
<td>从最近的命令中展开最后一个标记</td>
</tr>
<tr>
<td style="text-align:left"><code>!!:n-m</code></td>
<td>从最近的命令扩展令牌范围</td>
</tr>
<tr>
<td style="text-align:left"><code>!!:n-$</code></td>
<td>从最近的命令中将第 <code>n</code> 个标记展开到最后</td>
</tr>
</tbody>
</table>
<p><code>!!</code> 可以替换为任何有效的扩展，即 <code>!cat</code>、<code>!-2</code>、<code>!42</code> 等。</p>
<h2>杂项</h2>
<h3>数值计算</h3>
<pre><code class="language-bash">$((a + 200))      # Add 200 to $a
</code></pre>
<pre><code class="language-bash">$(($RANDOM%200))  # Random number 0..199
</code></pre>
<h3>子 shell</h3>
<pre><code class="language-bash">(cd somedir; echo &quot;I'm now in $PWD&quot;)
pwd # still in first directory
</code></pre>
<h3>检查命令</h3>
<pre><code class="language-bash">command -V cd
#=&gt; &quot;cd is a function/alias/whatever&quot;
</code></pre>
<h3>重定向</h3>
<p>&lt;!--rehype:wrap-class=row-span-2 col-span-2--&gt;</p>
<pre><code class="language-bash">python hello.py &gt; output.txt   # 标准输出到(文件)
python hello.py &gt;&gt; output.txt  # 标准输出到(文件)，追加
python hello.py 2&gt; error.log   # 标准错误到(文件)
python hello.py 2&gt;&amp;1           # 标准错误到标准输出
python hello.py 2&gt;/dev/null    # 标准错误到(空null)
python hello.py &amp;&gt;/dev/null    # 标准输出和标准错误到(空null)
</code></pre>
<pre><code class="language-bash">python hello.py &lt; foo.txt      # 将 foo.txt 提供给 python 的标准输入
</code></pre>
<h3>来源相对</h3>
<pre><code class="language-bash">source &quot;${0%/*}/../share/foo.sh&quot;
</code></pre>
<h3>脚本目录</h3>
<pre><code class="language-bash">DIR=&quot;${0%/*}&quot;
</code></pre>
<h3>Case/switch</h3>
<pre><code class="language-bash">case &quot;$1&quot; in
    start | up)
    vagrant up
    ;;
    *)
    echo &quot;Usage: $0 {start|stop|ssh}&quot;
    ;;
esac
</code></pre>
<h3>陷阱错误</h3>
<p>&lt;!--rehype:wrap-class=col-span-2--&gt;</p>
<pre><code class="language-bash">trap 'echo Error at about $LINENO' ERR
</code></pre>
<p>或者</p>
<pre><code class="language-bash">traperr() {
    echo &quot;ERROR: ${BASH_SOURCE[1]} at about ${BASH_LINENO[0]}&quot;
}
set -o errtrace
trap traperr ERR
</code></pre>
<h3>printf</h3>
<pre><code class="language-bash">printf &quot;Hello %s, I'm %s&quot; Sven Olga
#=&gt; &quot;Hello Sven, I'm Olga

printf &quot;1 + 1 = %d&quot; 2
#=&gt; &quot;1 + 1 = 2&quot;

printf &quot;Print a float: %f&quot; 2
#=&gt; &quot;Print a float: 2.000000&quot;
</code></pre>
<h3>获取选项</h3>
<p>&lt;!--rehype:wrap-class=col-span-2--&gt;</p>
<pre><code class="language-bash">while [[ &quot;$1&quot; =~ ^- &amp;&amp; ! &quot;$1&quot; == &quot;--&quot; ]]; do case $1 in
    -V | --version )
    echo $version
    exit
    ;;
    -s | --string )
    shift; string=$1
    ;;
    -f | --flag )
    flag=1
    ;;
esac; shift; done
if [[ &quot;$1&quot; == '--' ]]; then shift; fi
</code></pre>
<h3>检查命令的结果</h3>
<pre><code class="language-bash">if ping -c 1 google.com; then
    echo &quot;看来您的互联网连接正常&quot;
fi
</code></pre>
<h3>grep 检查</h3>
<pre><code class="language-bash">if grep -q 'foo' ~/.bash_history; then
    echo &quot;您过去似乎输入过“foo”&quot;
fi
</code></pre>
<h3>写入文件</h3>
<p>&lt;!--rehype:wrap-class=row-span-6--&gt;</p>
<table>
<thead>
<tr>
<th style="text-align:left">:--</th>
<th>--</th>
</tr>
</thead>
<tbody>
<tr>
<td style="text-align:left"><code>cat</code></td>
<td>用于显示文本文件内容，全部输出</td>
</tr>
<tr>
<td style="text-align:left"><code>EOF</code></td>
<td><code>end of file</code>，表示文本结束符</td>
</tr>
</tbody>
</table>
<hr>
<pre><code class="language-bash">cat &gt; output.txt &lt;&lt;EOF
this is test eof
this is test eof2
EOF
</code></pre>
<p>输出 <code>cat output.txt</code></p>
<pre><code>this is test eof
this is test eof2
</code></pre>
<p>追加内容</p>
<pre><code class="language-bash">cat &gt;&gt;2.txt &lt;&lt;EOF
456
789
EOF
</code></pre>
<p><code>$</code> 等特殊字符时，须利用转义字符 <code>\</code></p>
<pre><code class="language-bash">cat &gt; file &lt;&lt;EOF
export ORACLE_SID=yqpt 
export PATH=\$PATH:\$ORACLE_HOME/bin  
EOF
</code></pre>
<p>取消变量替换，<code>EOF</code> 被加上双引号或者单引号，即可取消变量的替换</p>
<pre><code class="language-bash">cat &lt;&lt; &quot;EOF&quot; &gt; output.sh
echo &quot;This is output&quot;
echo $1
EOF
</code></pre>
<p>所有TAB键将全部忽略[不能是空格]</p>
<pre><code class="language-bash">cat &lt;&lt; -EOF
        echo &quot;This is output&quot;
EOF
</code></pre>
<h3>特殊变量</h3>
<p>&lt;!--rehype:wrap-class=row-span-2--&gt;</p>
<table>
<thead>
<tr>
<th style="text-align:left">表达式</th>
<th>描述</th>
</tr>
</thead>
<tbody>
<tr>
<td style="text-align:left"><code>$?</code></td>
<td>最后一个任务的退出状态</td>
</tr>
<tr>
<td style="text-align:left"><code>$!</code></td>
<td>最后一个后台任务的 PID</td>
</tr>
<tr>
<td style="text-align:left"><code>$$</code></td>
<td>shell PID</td>
</tr>
<tr>
<td style="text-align:left"><code>$0</code></td>
<td>shell 脚本的文件名</td>
</tr>
</tbody>
</table>
<p>见<a href="http://wiki.bash-hackers.org/syntax/shellvars#special_parameters_and_shell_variables">特殊参数</a>。</p>
<h3>反斜杠转义</h3>
<p>&lt;!--rehype:wrap-class=row-span-2--&gt;</p>
<ul>
<li> </li>
<li>!</li>
<li>&quot;</li>
<li>#</li>
<li>&amp;</li>
<li>'</li>
<li>(</li>
<li>)</li>
<li>,</li>
<li>;</li>
<li>&lt;</li>
<li>&gt;</li>
<li>[</li>
<li>|</li>
<li>\</li>
<li>]</li>
<li>^</li>
<li>{</li>
<li>}</li>
<li>`</li>
<li>$</li>
<li>*</li>
<li>?
&lt;!--rehype:className=cols-4 style-none--&gt;</li>
</ul>
<p>使用 <code>\</code> 转义这些特殊字符</p>
<h3>Heredoc</h3>
<pre><code class="language-sh">cat &lt;&lt;END
hello world
END
</code></pre>
<h3>转到上一个目录</h3>
<pre><code class="language-bash">pwd # /home/user/foo
cd bar/
pwd # /home/user/foo/bar
cd -
pwd # /home/user/foo
</code></pre>
<h3>读取输入</h3>
<pre><code class="language-bash">echo -n &quot;Proceed? [y/n]: &quot;
read ans
echo $ans
</code></pre>
<pre><code class="language-bash">read -n 1 ans    # 只有一个字符
</code></pre>
<h3>条件执行</h3>
<pre><code class="language-bash">git commit &amp;&amp; git push
git commit || echo &quot;Commit failed&quot;
</code></pre>
<h3>严格模式</h3>
<pre><code class="language-bash">set -euo pipefail
IFS=$'\n\t'
</code></pre>
<p>参见：<a href="http://redsymbol.net/articles/unofficial-bash-strict-mode/">非官方 bash 严格模式</a></p>
<h3>可选参数</h3>
<pre><code class="language-bash">args=(&quot;$@&quot;)
args+=(foo)
args+=(bar)
echo &quot;${args[@]}&quot;
</code></pre>
<p>将参数放入数组中，然后追加</p>
<h3>调试模式</h3>
<p>启用调试模式，会把脚本中的每条命令的执行情况打印出来。它可以在整个会话或脚本上运行，也可以在脚本内以编程方式启用。</p>
<p>以调试模式运行脚本(整个脚本都会打印调试信息)：</p>
<pre><code class="language-bash">$ bash -x myscript.sh
</code></pre>
<p>在bash脚本中打开调试(针对部分内容打印调试信息)。</p>
<pre><code class="language-bash">#!/bin/bash
set -x   # Enable debugging
# some code here
set +x   # Disable debugging output.
</code></pre>
<h2>Bash 颜色</h2>
<h3>颜色着色语法示例</h3>
<p>&lt;!--rehype:wrap-class=row-span-2--&gt;</p>
<p>您可以通过为其输出着色来使您的 BASH 脚本更漂亮，使用以下模板编写彩色文本：</p>
<pre><code class="language-bash">echo -e &quot;\e[COLORm文字变色了\e[0m&quot;
</code></pre>
<h4>示例</h4>
<pre><code class="language-bash">$ echo -e &quot;\e[31m命令行中显示红色文字\e[0m&quot;
</code></pre>
<p>&lt;red&gt;命令行中显示红色文字&lt;/red&gt;</p>
<pre><code>$ echo -e &quot;\e[42m绿色背景\e[0m&quot;
</code></pre>
<p><code>绿色背景</code>&lt;!--rehype:style=background:green;color: black;--&gt;</p>
<table>
<thead>
<tr>
<th style="text-align:left">Option</th>
<th>Description</th>
</tr>
</thead>
<tbody>
<tr>
<td style="text-align:left"><code>-e</code></td>
<td>启用反斜杠转义的解释</td>
</tr>
<tr>
<td style="text-align:left"><code>\e[</code> 或 <code>\x1b[</code> 或 <code>\033[</code></td>
<td>开始颜色修改</td>
</tr>
<tr>
<td style="text-align:left"><code>COLORm</code></td>
<td>颜色代码 + <code>m</code> 在末尾</td>
</tr>
<tr>
<td style="text-align:left"><code>\e[0m</code> 或 <code>\x1b[0m</code> 或 <code>\033[0m</code></td>
<td>结束颜色修改</td>
</tr>
</tbody>
</table>
<p>&lt;!--rehype:className=left-align--&gt;</p>
<p><code>0x1b</code> 字面上称为 <code>ESC</code></p>
<h4>示例</h4>
<pre><code class="language-bash">$ echo -e &quot;\e[3m下划线文本\e[0m&quot;
</code></pre>
<p><code>下划线文本</code>&lt;!--rehype:style=text-decoration: underline;color: inherit;--&gt;</p>
<pre><code class="language-bash">$ echo -e &quot;\e[1;33;4;44m粗体下划线蓝色背景黄色文字的文本\e[0m&quot;
</code></pre>
<p>&lt;!--rehype:className=wrap-text--&gt;</p>
<p><code>粗体下划线蓝色背景黄色文字的文本</code>&lt;!--rehype:style=text-decoration: underline;color: inherit;font-weight: bold;color: #cdcd00;background: #0000ee;--&gt;</p>
<pre><code class="language-bash">\e[         # 启用转义
1;33;4;44   # 参数 (1;33;4;44)
m           # 设置图形模式
</code></pre>
<h4>样式</h4>
<table>
<thead>
<tr>
<th style="text-align:left">:-</th>
<th>--</th>
<th>--</th>
</tr>
</thead>
<tbody>
<tr>
<td style="text-align:left"><code>0</code></td>
<td>普通字符(复位或正常)</td>
<td>关闭所有属性</td>
</tr>
<tr>
<td style="text-align:left"><code>1</code></td>
<td><strong>粗体</strong>字</td>
<td></td>
</tr>
<tr>
<td style="text-align:left"><code>2</code></td>
<td>弱化(降低强度)</td>
<td>未广泛支持</td>
</tr>
<tr>
<td style="text-align:left"><code>3</code></td>
<td>斜体</td>
<td>未广泛支持有时为反相显示</td>
</tr>
<tr>
<td style="text-align:left"><code>4</code></td>
<td>下划线</td>
<td></td>
</tr>
<tr>
<td style="text-align:left"><code>5</code></td>
<td>缓慢闪烁</td>
<td></td>
</tr>
<tr>
<td style="text-align:left"><code>6</code></td>
<td>快速闪烁</td>
<td></td>
</tr>
<tr>
<td style="text-align:left"><code>7</code></td>
<td>反显</td>
<td></td>
</tr>
<tr>
<td style="text-align:left"><code>8</code></td>
<td>隐藏</td>
<td>未广泛支持。</td>
</tr>
<tr>
<td style="text-align:left"><code>9</code></td>
<td>划除</td>
<td></td>
</tr>
</tbody>
</table>
<p>&lt;!--rehype:className=left-align--&gt;</p>
<h3>ANSI — 颜色转义码</h3>
<table>
<thead>
<tr>
<th style="text-align:left">颜色</th>
<th>前景色</th>
<th>背景色</th>
<th>示例</th>
</tr>
</thead>
<tbody>
<tr>
<td style="text-align:left"><code>Black</code> 黑色</td>
<td>30</td>
<td>40</td>
<td>``&lt;!--rehype:style=background:#000;padding:0.2rem 1.2rem;border: 1px solid #333;--&gt;</td>
</tr>
<tr>
<td style="text-align:left"><code>Red</code> 红色</td>
<td>31</td>
<td>41</td>
<td>``&lt;!--rehype:style=background:#c23621;padding:0.2rem 1.2rem;border: 1px solid #333;--&gt;</td>
</tr>
<tr>
<td style="text-align:left"><code>Green</code> 绿色</td>
<td>32</td>
<td>42</td>
<td>``&lt;!--rehype:style=background:#25bc26;padding:0.2rem 1.2rem;border: 1px solid #333;--&gt;</td>
</tr>
<tr>
<td style="text-align:left"><code>Yellow</code> 黄色</td>
<td>33</td>
<td>43</td>
<td>``&lt;!--rehype:style=background:#cdcd00;padding:0.2rem 1.2rem;border: 1px solid #333;--&gt;</td>
</tr>
<tr>
<td style="text-align:left"><code>Blue</code> 蓝色</td>
<td>34</td>
<td>44</td>
<td>``&lt;!--rehype:style=background:#0000ee;padding:0.2rem 1.2rem;border: 1px solid #333;--&gt;</td>
</tr>
<tr>
<td style="text-align:left"><code>Purple</code> 紫色</td>
<td>35</td>
<td>45</td>
<td>``&lt;!--rehype:style=background:#cd00cd;padding:0.2rem 1.2rem;border: 1px solid #333;--&gt;</td>
</tr>
<tr>
<td style="text-align:left"><code>Cyan</code> 青色</td>
<td>36</td>
<td>46</td>
<td>``&lt;!--rehype:style=background:#00AAAA;padding:0.2rem 1.2rem;border: 1px solid #333;--&gt;</td>
</tr>
<tr>
<td style="text-align:left"><code>White</code> 白色</td>
<td>37</td>
<td>47</td>
<td>``&lt;!--rehype:style=background:#e5e5e5;padding:0.2rem 1.2rem;border: 1px solid #333;--&gt;</td>
</tr>
</tbody>
</table>
<p>&lt;!--rehype:className=show-header left-align--&gt;</p>
<h3>ANSI — 颜色转义码(亮色)</h3>
<table>
<thead>
<tr>
<th style="text-align:left">颜色</th>
<th>前景色</th>
<th>背景色</th>
<th>示例</th>
</tr>
</thead>
<tbody>
<tr>
<td style="text-align:left"><code>Bright Black(Gray)</code> 灰色</td>
<td>90</td>
<td>100</td>
<td>``&lt;!--rehype:style=background:#555555;padding:0.2rem 1.2rem;border: 1px solid #333;--&gt;</td>
</tr>
<tr>
<td style="text-align:left"><code>Bright Red</code> 亮红色</td>
<td>91</td>
<td>101</td>
<td>``&lt;!--rehype:style=background:#FF5555;padding:0.2rem 1.2rem;border: 1px solid #333;--&gt;</td>
</tr>
<tr>
<td style="text-align:left"><code>Bright Green</code> 亮绿色</td>
<td>92</td>
<td>102</td>
<td>``&lt;!--rehype:style=background:#55FF55;padding:0.2rem 1.2rem;border: 1px solid #333;--&gt;</td>
</tr>
<tr>
<td style="text-align:left"><code>Bright Yellow</code> 亮黄色</td>
<td>93</td>
<td>103</td>
<td>``&lt;!--rehype:style=background:#FFFF55;padding:0.2rem 1.2rem;border: 1px solid #333;--&gt;</td>
</tr>
<tr>
<td style="text-align:left"><code>Bright Blue</code> 亮蓝色</td>
<td>94</td>
<td>104</td>
<td>``&lt;!--rehype:style=background:#5555FF;padding:0.2rem 1.2rem;border: 1px solid #333;--&gt;</td>
</tr>
<tr>
<td style="text-align:left"><code>Bright Magenta</code> 亮紫色</td>
<td>95</td>
<td>105</td>
<td>``&lt;!--rehype:style=background:#FF55FF;padding:0.2rem 1.2rem;border: 1px solid #333;--&gt;</td>
</tr>
<tr>
<td style="text-align:left"><code>Bright Cyan</code> 亮青色</td>
<td>96</td>
<td>106</td>
<td>``&lt;!--rehype:style=background:#55FFFF;padding:0.2rem 1.2rem;border: 1px solid #333;--&gt;</td>
</tr>
<tr>
<td style="text-align:left"><code>Bright White</code> 浅灰</td>
<td>97</td>
<td>107</td>
<td>``&lt;!--rehype:style=background:#ffffff;padding:0.2rem 1.2rem;border: 1px solid #333;--&gt;</td>
</tr>
</tbody>
</table>
<p>&lt;!--rehype:className=show-header left-align--&gt;</p>
<h3>可用功能</h3>
<p>&lt;!--rehype:wrap-class=col-span-2--&gt;</p>
<table>
<thead>
<tr>
<th style="text-align:left">:-</th>
<th>--</th>
<th>--</th>
</tr>
</thead>
<tbody>
<tr>
<td style="text-align:left"><code>n</code> A</td>
<td>光标上移</td>
<td>光标向指定的方向移动 <code>n</code>(默认1)格</td>
</tr>
<tr>
<td style="text-align:left"><code>n</code> B</td>
<td>光标下移</td>
<td>光标向指定的方向移动 <code>n</code>(默认1)格</td>
</tr>
<tr>
<td style="text-align:left"><code>n</code> C</td>
<td>光标前移</td>
<td>光标向指定的方向移动 <code>n</code>(默认1)格</td>
</tr>
<tr>
<td style="text-align:left"><code>n</code> D</td>
<td>光标后移</td>
<td>光标向指定的方向移动 <code>n</code>(默认1)格</td>
</tr>
<tr>
<td style="text-align:left"><code>n</code> E</td>
<td>光标移到下一行</td>
<td>光标移动到下面第 <code>n</code>(默认1)行的开头(非ANSI.SYS)</td>
</tr>
<tr>
<td style="text-align:left"><code>n</code> F</td>
<td>光标移到上一行</td>
<td>光标移动到上面第 <code>n</code>(默认1)行的开头(非ANSI.SYS)</td>
</tr>
<tr>
<td style="text-align:left"><code>n</code> G</td>
<td>光标水平绝对</td>
<td>光标移动到第 <code>n</code>(默认1)列(非ANSI.SYS)</td>
</tr>
<tr>
<td style="text-align:left"><code>n</code>;<code>m</code> H</td>
<td>光标位置</td>
<td>光标移动到第 <code>n</code>行、第 <code>m</code> 列。值从1开始，且默认为1(左上角)</td>
</tr>
<tr>
<td style="text-align:left"><code>n</code> J</td>
<td>ED – 擦除显示</td>
<td>清除屏幕的部分区域</td>
</tr>
<tr>
<td style="text-align:left"><code>n</code> K</td>
<td>EL – 擦除行</td>
<td>清除行内的部分区域</td>
</tr>
<tr>
<td style="text-align:left"><code>n</code> S</td>
<td>SU – 向上滚动</td>
<td>整页向上滚动 <code>n</code>(默认1)行。新行添加到底部 (非ANSI.SYS)</td>
</tr>
<tr>
<td style="text-align:left"><code>n</code> T</td>
<td>SD – 向下滚动</td>
<td>整页向下滚动 <code>n</code>(默认1)行。新行添加到顶部 (非ANSI.SYS)</td>
</tr>
<tr>
<td style="text-align:left"><code>n</code>;<code>m</code>f</td>
<td>HVP – 水平垂直位置</td>
<td>同CUP</td>
</tr>
<tr>
<td style="text-align:left"><code>n</code> <code>m</code></td>
<td>SGR – 选择图形再现</td>
<td>设置SGR参数，包括文字颜色</td>
</tr>
<tr>
<td style="text-align:left"><code>5i</code></td>
<td>打开辅助端口</td>
<td>启用辅助串行端口，通常用于本地串行打印机</td>
</tr>
<tr>
<td style="text-align:left"><code>4i</code></td>
<td>关闭辅助端口</td>
<td>禁用辅助串行端口，通常用于本地串行打印机</td>
</tr>
<tr>
<td style="text-align:left"><code>6n</code></td>
<td>DSR – 设备状态报告</td>
<td>以 <code>ESC[n;mR</code> (就像在键盘上输入)向应用程序报告光标位置(CPR)，其中 <code>n</code>是行， <code>m</code> 是列</td>
</tr>
<tr>
<td style="text-align:left"><code>s</code></td>
<td>SCP – 保存光标位置</td>
<td>保存光标的当前位置</td>
</tr>
<tr>
<td style="text-align:left"><code>u</code></td>
<td>RCP – 恢复光标位置</td>
<td>恢复保存的光标位置</td>
</tr>
</tbody>
</table>
<h2>另见</h2>
<ul>
<li><a href="https://jaywcjlove.github.io/shell-tutorial">Shell 教程</a> <em>(jaywcjlove.github.io)</em></li>
<li><a href="https://devhints.io/bash">Devhints</a> <em>(devhints.io)</em></li>
<li><a href="http://wiki.bash-hackers.org/">Bash-hackers wiki</a> <em>(bash-hackers.org)</em></li>
<li><a href="http://wiki.bash-hackers.org/syntax/shellvars">Shell vars</a> <em>(bash-hackers.org)</em></li>
<li><a href="https://learnxinyminutes.com/docs/bash/">Learn bash in y minutes</a> <em>(learnxinyminutes.com)</em></li>
<li><a href="http://mywiki.wooledge.org/BashGuide">Bash Guide</a> <em>(mywiki.wooledge.org)</em></li>
<li><a href="https://www.shellcheck.net/">ShellCheck</a> <em>(shellcheck.net)</em></li>
<li><a href="https://devmanual.gentoo.org/tools-reference/bash/index.html">shell - Standard Shell</a> <em>(devmanual.gentoo.org)</em></li>
<li><a href="https://zh.wikipedia.org/wiki/ANSI%E8%BD%AC%E4%B9%89%E5%BA%8F%E5%88%97">ANSI 转义序列</a> <em>(zh.wikipedia.org)</em></li>
</ul>
<p><img src="/img/inline/bash-notes.png" alt="shell"></p>
]]></description><link>https://www.ranisa.cn/pages/b11f9q/</link><guid isPermaLink="true">https://www.ranisa.cn/pages/b11f9q/</guid><pubDate>Wed, 29 Jul 2026 00:00:00 GMT</pubDate></item><item><title><![CDATA[Ansible 备忘清单]]></title><description><![CDATA[<hr>
<p>title: Ansible 备忘清单
date: 2022-03-17 11:21:42
permalink: /pages/b11f9e/
categories:</p>
<ul>
<li>Linux笔记</li>
<li>工作笔记
tags:</li>
<li>Linux</li>
<li>运维</li>
</ul>
<hr>
<p>::: tip 版本说明
本文写于 2022-03。&lt;br&gt;Ansible 核心模块与 playbook 语法未变，经 2026-07 复核仍适用；具体模块参数如有弃用，请以 <code>ansible-doc &lt;module&gt;</code> 为准核对。
:::</p>
<p>此快速参考备忘单提供了使用 <a href="https://ansible.com">Ansible</a> 的各种方法。</p>
<h2>入门</h2>
<h3>安装</h3>
<table>
<thead>
<tr>
<th style="text-align:left">安装命令</th>
<th>环境</th>
</tr>
</thead>
<tbody>
<tr>
<td style="text-align:left"><code>brew install ansible</code></td>
<td>macos</td>
</tr>
<tr>
<td style="text-align:left"><code>yum install -y ansible</code></td>
<td>centos</td>
</tr>
<tr>
<td style="text-align:left"><code>pip install ansible</code></td>
<td>python</td>
</tr>
</tbody>
</table>
<hr>
<ul>
<li><a href="https://docs.ansible.com">Ansible 官方文档</a></li>
</ul>
<h3>配置位置</h3>
<table>
<thead>
<tr>
<th style="text-align:left">文件路径</th>
<th>说明</th>
</tr>
</thead>
<tbody>
<tr>
<td style="text-align:left"><code>/etc/ansible/ansible.cfg</code></td>
<td>系统范围的配置</td>
</tr>
<tr>
<td style="text-align:left"><code>~/ansible.cfg</code></td>
<td>用户特定的配置</td>
</tr>
<tr>
<td style="text-align:left"><code>$pwd/ansible.cfg</code></td>
<td>当前目录下的配置</td>
</tr>
</tbody>
</table>
<h3>Inventory文件(hosts列表)</h3>
<h4>静态Inventory</h4>
<p><code>/etc/ansible/hosts</code></p>
<pre><code class="language-INI">mail.example.com

[webservers]
foo.example.com
bar.example.com
</code></pre>
<h3>Inventory 主机组使用多个IP和域名</h3>
<pre><code>[web]
172.18.12.5[1:4]
[webservers]
www[01:50].example.com
</code></pre>
<h3>Inventory 主机组使用子主机组</h3>
<pre><code class="language-ini">[usa:children]
southeast
northeast
southwest
northwest
</code></pre>
<h3>给多台主机设置变量</h3>
<p><code>group variables</code>
如果组中的所有主机共享一个变量值，则可以一次将该变量应用于整个组</p>
<pre><code class="language-ini">[atlanta]
host1
host2

[atlanta:vars]
ntp_server=ntp.atlanta.example.com
proxy=proxy.atlanta.example.com

</code></pre>
<h2>命令行(ad-hoc)</h2>
<h3>ansible</h3>
<p>检查Inventory是否生效</p>
<pre><code class="language-shell">$ ansible all --list-hosts
</code></pre>
<p>ping所有目标</p>
<pre><code class="language-shell">$ ansible all -m ping
</code></pre>
<p>ping本地(不使用SSH连接)</p>
<pre><code class="language-shell">$ ansible all -i localhost, -e '{&quot;ansible_connection&quot;: &quot;local&quot;}' -m ping
</code></pre>
<p>&lt;!--rehype:className=wrap-text --&gt;
本地执行命令</p>
<pre><code class="language-shell">$ ansible all -i localhost, -e '{&quot;ansible_connection&quot;: &quot;local&quot;}' -a 'hostname'
</code></pre>
<p>&lt;!--rehype:className=wrap-text --&gt;
获取本地主机的信息</p>
<pre><code class="language-shell">$ ansible all -i localhost, -e '{&quot;ansible_connection&quot;: &quot;local&quot;}' -m setup
</code></pre>
<p>&lt;!--rehype:className=wrap-text --&gt;
获取远程到本地</p>
<pre><code class="language-shell">$ ansible target -m fetch -a &quot;src=/tmp/seq dest=/tmp/seq&quot;
</code></pre>
<p>&lt;!--rehype:className=wrap-text --&gt;
拷贝本地到远程</p>
<pre><code class="language-shell">$ ansible target -m copy -a &quot;src=/tmp/seq dest=/tmp/seq&quot;
</code></pre>
<p>&lt;!--rehype:className=wrap-text --&gt;</p>
<h3>Ansible 命令帮助</h3>
<p>&lt;!--rehype:wrap-class=col-span-2 row-span-3--&gt;</p>
<pre><code class="language-bash">$ ansible
$ ansible &lt;host-pattern&gt; [options]
</code></pre>
<hr>
<table>
<thead>
<tr>
<th style="text-align:left">:-</th>
<th>-</th>
</tr>
</thead>
<tbody>
<tr>
<td style="text-align:left"><code>-a MODULE_ARGS</code>, <code>--args=MODULE_ARGS</code></td>
<td>模块参数</td>
</tr>
<tr>
<td style="text-align:left"><code>--ask-vault-pass</code></td>
<td>询问保险库密码</td>
</tr>
<tr>
<td style="text-align:left"><code>-B SECONDS</code>, <code>--background=SECONDS</code></td>
<td>异步运行，X 秒后失败 (默认=N/A)</td>
</tr>
<tr>
<td style="text-align:left"><code>-C</code>, <code>--check</code></td>
<td>不要做任何改变；相反，尝试预测可能发生的一些变化</td>
</tr>
<tr>
<td style="text-align:left"><code>-D</code>, <code>--diff</code></td>
<td>更改(小)文件和模板时，显示这些文件中的差异； 与 <code>--check</code> 配合使用效果很好</td>
</tr>
<tr>
<td style="text-align:left"><code>-e EXTRA_VARS</code>, <code>--extra-vars=EXTRA_VARS</code></td>
<td>将附加变量设置为 key=value 或 YAML/JSON</td>
</tr>
<tr>
<td style="text-align:left"><code>-f FORKS</code>, <code>--forks=FORKS</code></td>
<td>指定要使用的并行进程数 (default=5)</td>
</tr>
<tr>
<td style="text-align:left"><code>-h</code>, <code>--help</code></td>
<td>显示此帮助信息并退出</td>
</tr>
<tr>
<td style="text-align:left"><code>-i INVENTORY</code>, <code>--inventory-file=INVENTORY</code></td>
<td>指定清单主机路径(默认=/etc/ansible/hosts)或逗号分隔的主机列表</td>
</tr>
<tr>
<td style="text-align:left"><code>-l SUBSET</code>, <code>--limit=SUBSET</code></td>
<td>进一步将选定主机限制为其他模式</td>
</tr>
<tr>
<td style="text-align:left"><code>--list-hosts</code></td>
<td>输出匹配主机列表；不执行任何其他操作</td>
</tr>
<tr>
<td style="text-align:left"><code>-m MODULE_NAME</code>, <code>--module-name=MODULE_NAME</code></td>
<td>要执行的模块名称 (default=command)</td>
</tr>
<tr>
<td style="text-align:left"><code>-M MODULE_PATH</code>, <code>--module-path=MODULE_PATH</code></td>
<td>指定模块库的路径 (default=None)</td>
</tr>
<tr>
<td style="text-align:left"><code>--new-vault-password-file=NEW_VAULT_PASSWORD_FILE</code></td>
<td>用于重新生成密钥的新保管库密码文件</td>
</tr>
<tr>
<td style="text-align:left"><code>-o</code>, <code>--one-line</code></td>
<td>压缩输出</td>
</tr>
<tr>
<td style="text-align:left"><code>--output=OUTPUT_FILE</code></td>
<td>用于加密或解密的输出文件名； 使用 - 用于标准输出</td>
</tr>
<tr>
<td style="text-align:left"><code>-P POLL_INTERVAL</code>, <code>--poll=POLL_INTERVAL</code></td>
<td>如果使用 -B 则设置轮询间隔(default=15)</td>
</tr>
<tr>
<td style="text-align:left"><code>--syntax-check</code></td>
<td>对 playbook 执行语法检查，但不要执行它</td>
</tr>
<tr>
<td style="text-align:left"><code>-t TREE</code>, <code>--tree=TREE</code></td>
<td>将输出记录到此目录</td>
</tr>
<tr>
<td style="text-align:left"><code>--vault-password-file=VAULT_PASSWORD_FILE</code></td>
<td>保险库密码文件</td>
</tr>
<tr>
<td style="text-align:left"><code>-v</code>, <code>--verbose</code></td>
<td>详细模式(-vvv 更多，-vvvv 启用连接调试)</td>
</tr>
<tr>
<td style="text-align:left"><code>--version</code></td>
<td>显示程序的版本号并退出</td>
</tr>
</tbody>
</table>
<p>控制谁以及如何连接到主机，连接选项：</p>
<table>
<thead>
<tr>
<th style="text-align:left">:-</th>
<th>-</th>
</tr>
</thead>
<tbody>
<tr>
<td style="text-align:left"><code>-k</code>, <code>--ask-pass</code></td>
<td>询问连接密码</td>
</tr>
<tr>
<td style="text-align:left"><code>--private-key=PRIVATE_KEY_FILE</code>, <code>--key-file=PRIVATE_KEY_FILE</code></td>
<td>使用此文件来验证连接</td>
</tr>
<tr>
<td style="text-align:left"><code>-u REMOTE_USER</code>, <code>--user=REMOTE_USER</code></td>
<td>以此用户身份连接(default=None)</td>
</tr>
<tr>
<td style="text-align:left"><code>-c CONNECTION</code>, <code>--connection=CONNECTION</code></td>
<td>要使用的连接类型 (default=smart)</td>
</tr>
<tr>
<td style="text-align:left"><code>-T TIMEOUT</code>, <code>--timeout=TIMEOUT</code></td>
<td>以秒为单位覆盖连接超时 (default=10)</td>
</tr>
<tr>
<td style="text-align:left"><code>--ssh-common-args=SSH_COMMON_ARGS</code></td>
<td>指定要传递给 sftp/scp/ssh 的常用参数 (e.g. ProxyCommand)</td>
</tr>
<tr>
<td style="text-align:left"><code>--sftp-extra-args=SFTP_EXTRA_ARGS</code></td>
<td>指定仅传递给 sftp 的额外参数 (e.g. -f, -l)</td>
</tr>
<tr>
<td style="text-align:left"><code>--scp-extra-args=SCP_EXTRA_ARGS</code></td>
<td>指定仅传递给 <code>scp</code> 的额外参数 (e.g. -l)</td>
</tr>
<tr>
<td style="text-align:left"><code>--ssh-extra-args=SSH_EXTRA_ARGS</code></td>
<td>指定仅传递给 <code>ssh</code> 的额外参数 (e.g. -R)</td>
</tr>
</tbody>
</table>
<p>控制您成为目标主机上的用户的方式和用户，特权升级选项：</p>
<table>
<thead>
<tr>
<th style="text-align:left">:-</th>
<th>-</th>
</tr>
</thead>
<tbody>
<tr>
<td style="text-align:left"><code>-s</code>, <code>--sudo</code></td>
<td>使用 sudo (nopasswd) 运行操作(已弃用，使用 become)</td>
</tr>
<tr>
<td style="text-align:left"><code>-U SUDO_USER</code>, <code>--sudo-user=SUDO_USER</code></td>
<td>所需的 sudo 用户(默认=root)(已弃用，使用 become)</td>
</tr>
<tr>
<td style="text-align:left"><code>-S</code>, <code>--su</code></td>
<td>使用 su 运行操作(已弃用，使用 become)</td>
</tr>
<tr>
<td style="text-align:left"><code>-R SU_USER</code>, <code>--su-user=SU_USER</code></td>
<td>以该用户身份使用 su 运行操作(默认 = root)(已弃用，使用 become)</td>
</tr>
<tr>
<td style="text-align:left"><code>-b</code>, <code>--become</code></td>
<td>使用 become 运行操作(不暗示密码提示)</td>
</tr>
<tr>
<td style="text-align:left"><code>--become-method=BECOME_METHOD</code></td>
<td>要使用的权限提升方法(默认=sudo)，有效选择：[ sudo</td>
</tr>
<tr>
<td style="text-align:left"><code>--become-user=BECOME_USER</code></td>
<td>以该用户身份运行操作(默认=root)</td>
</tr>
<tr>
<td style="text-align:left"><code>--ask-sudo-pass</code></td>
<td>询问 sudo 密码(已弃用，使用 become)</td>
</tr>
<tr>
<td style="text-align:left"><code>--ask-su-pass</code></td>
<td>询问 su 密码(已弃用，使用 become)</td>
</tr>
<tr>
<td style="text-align:left"><code>-K</code>, <code>--ask-become-pass</code></td>
<td>要求提权密码</td>
</tr>
</tbody>
</table>
<h3>Ansible Galaxy 工具</h3>
<pre><code class="language-bash">$ ansible-galaxy [delete|import|info|init|install|list|login|remove|search|setup] [--help] [options] ...
</code></pre>
<p>&lt;!--rehype:className=wrap-text--&gt;</p>
<hr>
<table>
<thead>
<tr>
<th style="text-align:left">:-</th>
<th>-</th>
</tr>
</thead>
<tbody>
<tr>
<td style="text-align:left"><code>-h</code>, <code>--help</code></td>
<td>显示此帮助信息并退出</td>
</tr>
<tr>
<td style="text-align:left"><code>-v</code>, <code>--verbose</code></td>
<td>详细模式(-vvv 更多，-vvvv 启用连接调试)</td>
</tr>
<tr>
<td style="text-align:left"><code>--version</code></td>
<td>显示程序的版本号并退出</td>
</tr>
</tbody>
</table>
<p>&lt;!--rehype:className=style-list--&gt;</p>
<hr>
<pre><code class="language-bash">$ ansible-galaxy search --author &lt;AUTHOR&gt;
$ ansible-galaxy search --platforms &lt;PLATFORM&gt;
$ ansible-galaxy search --galaxy-tags &lt;TAG&gt;
$ ansible-galaxy info &lt;ROLE&gt;
$ ansible-galaxy install &lt;ROLE&gt; -p &lt;ROLE_DIRECTORY&gt;
$ ansible-galaxy install -r &lt;ROLE1&gt; &lt;ROLE2&gt; &lt;ROLE3&gt; ...
$ ansible-galaxy list
$ ansible-galaxy remove &lt;ROLE&gt;
$ ansible-galaxy init &lt;ROLE&gt;
$ ansible-galaxy init --offline &lt;ROLE&gt;
</code></pre>
<p>&lt;!--rehype:className=wrap-text--&gt;</p>
<h3>ansible-doc</h3>
<p>在本地访问文档</p>
<pre><code class="language-bash">$ ansible-doc
$ ansible-doc [options] [module...]
</code></pre>
<hr>
<table>
<thead>
<tr>
<th style="text-align:left">:-</th>
<th>-</th>
</tr>
</thead>
<tbody>
<tr>
<td style="text-align:left"><code>-h</code>, <code>--help</code></td>
<td>显示此帮助信息并退出</td>
</tr>
<tr>
<td style="text-align:left"><code>-l</code>, <code>--list</code></td>
<td>列出可用模块</td>
</tr>
<tr>
<td style="text-align:left"><code>-M MODULE_PATH</code>, <code>--module-path=MODULE_PATH</code></td>
<td>指定模块库的路径 (default=None)</td>
</tr>
<tr>
<td style="text-align:left"><code>-s</code>, <code>--snippet</code></td>
<td>显示指定模块的剧本片段</td>
</tr>
<tr>
<td style="text-align:left"><code>-v</code>, <code>--verbose</code></td>
<td>详细模式(-vvv 更多，-vvvv 启用连接调试)</td>
</tr>
<tr>
<td style="text-align:left"><code>--version</code></td>
<td>显示程序的版本号并退出</td>
</tr>
</tbody>
</table>
<p>&lt;!--rehype:className=style-list--&gt;</p>
<h3>ansible-vault</h3>
<pre><code class="language-bash">$ ansible-vault
$ ansible-vault [create|decrypt|edit|encrypt|rekey|view] [--help] [options] vaultfile.yml
</code></pre>
<hr>
<table>
<thead>
<tr>
<th style="text-align:left">:-</th>
<th>-</th>
</tr>
</thead>
<tbody>
<tr>
<td style="text-align:left"><code>--ask-vault-pass</code></td>
<td>询问保险库密码</td>
</tr>
<tr>
<td style="text-align:left"><code>-h</code>, <code>--help</code></td>
<td>显示此帮助信息并退出</td>
</tr>
<tr>
<td style="text-align:left"><code>--new-vault-password-file=NEW_VAULT_PASSWORD_FILE</code></td>
<td>用于重新生成密钥的新保管库密码文件</td>
</tr>
<tr>
<td style="text-align:left"><code>--output=OUTPUT_FILE</code></td>
<td>用于加密或解密的输出文件名； 使用 - 用于标准输出</td>
</tr>
<tr>
<td style="text-align:left"><code>--vault-password-file=VAULT_PASSWORD_FILE</code></td>
<td>保险库密码文件</td>
</tr>
<tr>
<td style="text-align:left"><code>-v</code>, <code>--verbose</code></td>
<td>详细模式(-vvv 更多，-vvvv 启用连接调试)</td>
</tr>
<tr>
<td style="text-align:left"><code>--version</code></td>
<td>显示程序的版本号并退出</td>
</tr>
</tbody>
</table>
<p>&lt;!--rehype:className=style-list--&gt;</p>
<h3>ansible-playbook</h3>
<p>&lt;!--rehype:wrap-class=row-span-2--&gt;</p>
<pre><code class="language-bash">$ ansible-playbook
$ ansible-playbook playbook.yml
</code></pre>
<hr>
<table>
<thead>
<tr>
<th style="text-align:left">:-</th>
<th>-</th>
</tr>
</thead>
<tbody>
<tr>
<td style="text-align:left"><code>--ask-vault-pass</code></td>
<td>询问保险库密码</td>
</tr>
<tr>
<td style="text-align:left"><code>-C</code>, <code>--check</code></td>
<td>不要做任何改变；相反，尝试预测可能发生的一些变化</td>
</tr>
<tr>
<td style="text-align:left"><code>-D</code>, <code>--diff</code></td>
<td>更改（小）文件和模板时，显示这些文件中的差异；与 <code>--check</code> 配合使用效果很好</td>
</tr>
<tr>
<td style="text-align:left"><code>-e EXTRA_VARS</code>, <code>--extra-vars=EXTRA_VARS</code></td>
<td>将附加变量设置为 key=value 或 YAML/JSON</td>
</tr>
<tr>
<td style="text-align:left"><code>--flush-cache</code></td>
<td>清除事实缓存</td>
</tr>
<tr>
<td style="text-align:left"><code>--force-handlers</code></td>
<td>即使任务失败也运行处理程序</td>
</tr>
<tr>
<td style="text-align:left"><code>-f FORKS</code>, <code>--forks=FORKS</code></td>
<td>指定要使用的并行进程数（默认值=5）</td>
</tr>
<tr>
<td style="text-align:left"><code>-h</code>, <code>--help</code></td>
<td>显示此帮助信息并退出</td>
</tr>
<tr>
<td style="text-align:left"><code>-i INVENTORY</code>, <code>--inventory-file=INVENTORY</code></td>
<td>指定清单主机路径（默认=/etc/ansible/hosts）或逗号分隔的主机列表</td>
</tr>
<tr>
<td style="text-align:left"><code>-l SUBSET</code>, <code>--limit=SUBSET</code></td>
<td>进一步将选定主机限制为其他模式</td>
</tr>
<tr>
<td style="text-align:left"><code>--list-hosts</code></td>
<td>输出匹配主机列表；不执行任何其他操作</td>
</tr>
<tr>
<td style="text-align:left"><code>--list-tags</code></td>
<td>列出所有可用的标签</td>
</tr>
<tr>
<td style="text-align:left"><code>--list-tasks</code></td>
<td>列出所有将要执行的任务</td>
</tr>
<tr>
<td style="text-align:left"><code>-M MODULE_PATH</code>, <code>--module-path=MODULE_PATH</code></td>
<td>指定模块库的路径（默认=无）</td>
</tr>
<tr>
<td style="text-align:left"><code>--new-vault-password-file=NEW_VAULT_PASSWORD_FILE</code></td>
<td>用于重新生成密钥的新保管库密码文件</td>
</tr>
<tr>
<td style="text-align:left"><code>--output=OUTPUT_FILE</code></td>
<td>用于加密或解密的输出文件名；使用 - 用于标准输出</td>
</tr>
<tr>
<td style="text-align:left"><code>--skip-tags=SKIP_TAGS</code></td>
<td>只运行标签与这些值不匹配的播放和任务</td>
</tr>
<tr>
<td style="text-align:left"><code>--start-at-task=START_AT_TASK</code></td>
<td>在匹配此名称的任务处启动剧本</td>
</tr>
<tr>
<td style="text-align:left"><code>--step</code></td>
<td>一步一步：在运行前确认每个任务</td>
</tr>
<tr>
<td style="text-align:left"><code>--syntax-check</code></td>
<td>对 playbook 执行语法检查，但不要执行它</td>
</tr>
<tr>
<td style="text-align:left"><code>-t TAGS</code>, <code>--tags=TAGS</code></td>
<td>只运行带有这些值标记的播放和任务</td>
</tr>
<tr>
<td style="text-align:left"><code>--vault-password-file=VAULT_PASSWORD_FILE</code></td>
<td>保险库密码文件</td>
</tr>
<tr>
<td style="text-align:left"><code>-v</code>, <code>--verbose</code></td>
<td>详细模式（-vvv 更多，-vvvv 启用连接调试）</td>
</tr>
<tr>
<td style="text-align:left"><code>--version</code></td>
<td>显示程序的版本号并退出</td>
</tr>
</tbody>
</table>
<p>&lt;!--rehype:className=style-list--&gt;</p>
<p>连接选项：</p>
<table>
<thead>
<tr>
<th style="text-align:left">:-</th>
<th>-</th>
</tr>
</thead>
<tbody>
<tr>
<td style="text-align:left"><code>-k</code>, <code>--ask-pass</code></td>
<td>询问连接密码</td>
</tr>
<tr>
<td style="text-align:left"><code>--private-key=PRIVATE_KEY_FILE</code>, <code>--key-file=PRIVATE_KEY_FILE</code></td>
<td>使用此文件来验证连接</td>
</tr>
<tr>
<td style="text-align:left"><code>-u REMOTE_USER</code>, <code>--user=REMOTE_USER</code></td>
<td>以此用户身份连接(默认=None)</td>
</tr>
<tr>
<td style="text-align:left"><code>-c CONNECTION</code>, <code>--connection=CONNECTION</code></td>
<td>要使用的连接类型(默认=smart)</td>
</tr>
<tr>
<td style="text-align:left"><code>-T TIMEOUT</code>, <code>--timeout=TIMEOUT</code></td>
<td>以秒为单位覆盖连接超时(默认值 = 10)</td>
</tr>
<tr>
<td style="text-align:left"><code>--ssh-common-args=SSH_COMMON_ARGS</code></td>
<td>指定要传递给 sftp/scp/ssh 的常用参数(例如 ProxyCommand)</td>
</tr>
<tr>
<td style="text-align:left"><code>--sftp-extra-args=SFTP_EXTRA_ARGS</code></td>
<td>指定仅传递给 sftp 的额外参数(例如 -f、-l)</td>
</tr>
<tr>
<td style="text-align:left"><code>--scp-extra-args=SCP_EXTRA_ARGS</code></td>
<td>指定仅传递给 scp 的额外参数(例如 -l)</td>
</tr>
<tr>
<td style="text-align:left"><code>--ssh-extra-args=SSH_EXTRA_ARGS</code></td>
<td>指定仅传递给 ssh 的额外参数(例如 -R)</td>
</tr>
</tbody>
</table>
<p>&lt;!--rehype:className=style-list--&gt;</p>
<p>特权升级选项：</p>
<table>
<thead>
<tr>
<th style="text-align:left">:-</th>
<th>-</th>
</tr>
</thead>
<tbody>
<tr>
<td style="text-align:left"><code>-s</code>, <code>--sudo</code></td>
<td>使用 sudo (nopasswd) 运行操作(已弃用，使用 become)</td>
</tr>
<tr>
<td style="text-align:left"><code>-U SUDO_USER</code>, <code>--sudo-user=SUDO_USER</code></td>
<td>所需的 sudo 用户(默认=root)(已弃用，使用become)</td>
</tr>
<tr>
<td style="text-align:left"><code>-S</code>, <code>--su</code></td>
<td>使用 su 运行操作(已弃用，使用 become)</td>
</tr>
<tr>
<td style="text-align:left"><code>-R SU_USER</code>, <code>--su-user=SU_USER</code></td>
<td>以该用户身份使用 su 运行操作(默认 = root)(已弃用，使用become)</td>
</tr>
<tr>
<td style="text-align:left"><code>-b</code>, <code>--become</code></td>
<td>使用 become 运行操作(不暗示密码提示)</td>
</tr>
<tr>
<td style="text-align:left"><code>--become-method=BECOME_METHOD</code></td>
<td>要使用的权限提升方法(默认=sudo)，有效选择：[ sudo | su | pbrun | pfexec | runas | doas | dzdo ]</td>
</tr>
<tr>
<td style="text-align:left"><code>--become-user=BECOME_USER</code></td>
<td>以该用户身份运行操作(默认=root)</td>
</tr>
<tr>
<td style="text-align:left"><code>--ask-sudo-pass</code></td>
<td>询问 sudo 密码(已弃用，使用 become)</td>
</tr>
<tr>
<td style="text-align:left"><code>--ask-su-pass</code></td>
<td>询问 su 密码(已弃用，使用 become)</td>
</tr>
<tr>
<td style="text-align:left"><code>-K</code>, <code>--ask-become-pass</code></td>
<td>要求提权密码</td>
</tr>
</tbody>
</table>
<p>&lt;!--rehype:className=style-list--&gt;</p>
<h3>ansible-pull</h3>
<p>&lt;!--rehype:wrap-class=row-span-2--&gt;</p>
<pre><code class="language-bash">$ ansible-pull 
$ ansible-pull -U &lt;repository&gt; [options]
</code></pre>
<hr>
<table>
<thead>
<tr>
<th style="text-align:left">:-</th>
<th>-</th>
</tr>
</thead>
<tbody>
<tr>
<td style="text-align:left"><code>--accept-host-key</code></td>
<td>如果尚未添加，则添加 repo url 的主机密钥</td>
</tr>
<tr>
<td style="text-align:left"><code>--ask-vault-pass</code></td>
<td>询问保险库密码</td>
</tr>
<tr>
<td style="text-align:left"><code>-C CHECKOUT</code>, <code>--checkout=CHECKOUT</code></td>
<td>分支/标签/提交结帐。默认为存储库模块的行为。</td>
</tr>
<tr>
<td style="text-align:left"><code>-d DEST</code>, <code>--directory=DEST</code></td>
<td>签出存储库的目录</td>
</tr>
<tr>
<td style="text-align:left"><code>-e EXTRA_VARS</code>, <code>--extra-vars=EXTRA_VARS</code></td>
<td>将附加变量设置为 key=value 或 YAML/JSON</td>
</tr>
<tr>
<td style="text-align:left"><code>-f</code>, <code>--force</code></td>
<td>即使无法更新存储库也运行 playbook</td>
</tr>
<tr>
<td style="text-align:left"><code>--full</code></td>
<td>做一个完整的克隆，而不是一个浅的</td>
</tr>
<tr>
<td style="text-align:left"><code>-h</code>, <code>--help</code></td>
<td>显示此帮助信息并退出</td>
</tr>
<tr>
<td style="text-align:left"><code>-i INVENTORY</code>, <code>--inventory-file=INVENTORY</code></td>
<td>指定清单主机路径(默认=/etc/ansible/hosts)或逗号分隔的主机列表</td>
</tr>
<tr>
<td style="text-align:left"><code>-l SUBSET</code>, <code>--limit=SUBSET</code></td>
<td>进一步将选定主机限制为其他模式</td>
</tr>
<tr>
<td style="text-align:left"><code>--list-hosts</code></td>
<td>输出匹配主机列表；不执行任何其他操作</td>
</tr>
<tr>
<td style="text-align:left"><code>-m MODULE_NAME</code>, <code>--module-name=MODULE_NAME</code></td>
<td>存储库模块名称，ansible 将使用它来签出 repo。默认是 git</td>
</tr>
<tr>
<td style="text-align:left"><code>-M MODULE_PATH</code>, <code>--module-path=MODULE_PATH</code></td>
<td>指定模块库的路径(默认=无)</td>
</tr>
<tr>
<td style="text-align:left"><code>--new-vault-password-file=NEW_VAULT_PASSWORD_FILE</code></td>
<td>用于重新生成密钥的新保管库密码文件</td>
</tr>
<tr>
<td style="text-align:left"><code>-o</code>, <code>--only-if-changed</code></td>
<td>仅在存储库已更新时才运行 playbook</td>
</tr>
<tr>
<td style="text-align:left"><code>--output=OUTPUT_FILE</code></td>
<td>用于加密或解密的输出文件名；使用 - 用于标准输出</td>
</tr>
<tr>
<td style="text-align:left"><code>--purge</code></td>
<td>剧本运行后清除结帐</td>
</tr>
<tr>
<td style="text-align:left"><code>--skip-tags=SKIP_TAGS</code></td>
<td>只运行标签与这些值不匹配的播放和任务</td>
</tr>
<tr>
<td style="text-align:left"><code>-s SLEEP</code>, <code>--sleep=SLEEP</code></td>
<td>在开始之前休眠随机间隔(在 0 到 n 秒之间)。这是分散 git 请求的有用方法</td>
</tr>
<tr>
<td style="text-align:left"><code>-t TAGS</code>, <code>--tags=TAGS</code></td>
<td>只运行带有这些值标记的播放和任务</td>
</tr>
<tr>
<td style="text-align:left"><code>-U URL</code>, <code>--url=URL</code></td>
<td>剧本存储库的 URL</td>
</tr>
<tr>
<td style="text-align:left"><code>--vault-password-file=VAULT_PASSWORD_FILE</code></td>
<td>保险库密码文件</td>
</tr>
<tr>
<td style="text-align:left"><code>-v</code>, <code>--verbose</code></td>
<td>详细模式(-vvv 更多，-vvvv 启用连接调试)</td>
</tr>
<tr>
<td style="text-align:left"><code>--verify-commit</code></td>
<td>验证签出提交的 GPG 签名，如果失败则中止运行 playbook。这就需要对应的VCS模块来支持这样的操作</td>
</tr>
<tr>
<td style="text-align:left"><code>--version</code></td>
<td>显示程序的版本号并退出</td>
</tr>
</tbody>
</table>
<p>&lt;!--rehype:className=style-list--&gt;</p>
<p>连接选项：</p>
<table>
<thead>
<tr>
<th style="text-align:left">:-</th>
<th>-</th>
</tr>
</thead>
<tbody>
<tr>
<td style="text-align:left"><code>-k</code>, <code>--ask-pass</code></td>
<td>询问连接密码</td>
</tr>
<tr>
<td style="text-align:left"><code>--private-key=PRIVATE_KEY_FILE</code>, <code>--key-file=PRIVATE_KEY_FILE</code></td>
<td>使用此文件来验证连接</td>
</tr>
<tr>
<td style="text-align:left"><code>-u REMOTE_USER</code>, <code>--user=REMOTE_USER</code></td>
<td>以此用户身份连接(默认=无)</td>
</tr>
<tr>
<td style="text-align:left"><code>-c CONNECTION</code>, <code>--connection=CONNECTION</code></td>
<td>要使用的连接类型(默认=智能)</td>
</tr>
<tr>
<td style="text-align:left"><code>-T TIMEOUT</code>, <code>--timeout=TIMEOUT</code></td>
<td>以秒为单位覆盖连接超时(默认值 = 10)</td>
</tr>
<tr>
<td style="text-align:left"><code>--ssh-common-args=SSH_COMMON_ARGS</code></td>
<td>指定要传递给 sftp/scp/ssh 的常用参数(例如 ProxyCommand)</td>
</tr>
<tr>
<td style="text-align:left"><code>--sftp-extra-args=SFTP_EXTRA_ARGS</code></td>
<td>指定仅传递给 sftp 的额外参数(例如 -f、-l)</td>
</tr>
<tr>
<td style="text-align:left"><code>--scp-extra-args=SCP_EXTRA_ARGS</code></td>
<td>指定仅传递给 scp 的额外参数(例如 -l)</td>
</tr>
<tr>
<td style="text-align:left"><code>--ssh-extra-args=SSH_EXTRA_ARGS</code></td>
<td>指定仅传递给 ssh 的额外参数(例如 -R)</td>
</tr>
</tbody>
</table>
<p>&lt;!--rehype:className=style-list--&gt;</p>
<p>特权升级选项：</p>
<table>
<thead>
<tr>
<th style="text-align:left">:-</th>
<th>-</th>
</tr>
</thead>
<tbody>
<tr>
<td style="text-align:left"><code>--ask-sudo-pass</code></td>
<td>询问 sudo 密码(已弃用，使用become)</td>
</tr>
<tr>
<td style="text-align:left"><code>--ask-su-pass</code></td>
<td>询问 su 密码(已弃用，使用become)</td>
</tr>
<tr>
<td style="text-align:left"><code>-K</code>, <code>--ask-become-pass</code></td>
<td>要求提权密码</td>
</tr>
</tbody>
</table>
<p>&lt;!--rehype:className=style-list--&gt;</p>
<p>&lt;!-- ### ansible-playbook --&gt;
&lt;!-- todo --&gt;</p>
<h2>另见</h2>
<ul>
<li><a href="https://docs.ansible.com/ansible/latest/getting_started/index.html">Getting started with Ansible</a></li>
<li><a href="https://docs.ansible.com/ansible/latest/user_guide/intro_adhoc.html">Introduction to ad hoc commands</a></li>
<li><a href="https://github.com/luckylittle/ansible-cheatsheet/blob/master/ansible-cheatsheet.txt">Ansible cheatsheet</a></li>
<li><a href="https://spacelift.io/blog/ansible-tutorial">Ansible Tutorial for Beginners: Ultimate Playbook &amp; Examples</a></li>
</ul>
<p><img src="/img/inline/ansible-notes.png" alt="ansible"></p>
]]></description><link>https://www.ranisa.cn/pages/b11f9e/</link><guid isPermaLink="true">https://www.ranisa.cn/pages/b11f9e/</guid><pubDate>Wed, 29 Jul 2026 00:00:00 GMT</pubDate></item><item><title><![CDATA[linux 文件的权限和属性]]></title><description><![CDATA[<hr>
<p>title: linux 文件的权限和属性
date: 2022-07-17 11:21:42
permalink: /pages/b08f91/
categories:</p>
<ul>
<li>Linux笔记</li>
<li>工作笔记
tags:</li>
<li>Linux</li>
<li>运维</li>
</ul>
<hr>
<p>::: tip 版本说明
本文写于 2022-07。&lt;br&gt;Linux 权限模型（rwx、特殊权限位、ACL）未变，经 2026-07 复核仍适用。
:::</p>
<p>权限表示方式通常使用三个八进制数字来表示，分别代表文件所有者、文件所属组和其他用户的权限。在一个八进制数字中，每个数字表示一个权限类别，由左至右分别是文件所有者、文件所属组和其他用户的权限。</p>
<p>其中，数字 <code>7</code> 表示二进制 <code>111</code>，即所有权限都被允许。对应到文件的权限表示上，数字 <code>7</code> 表示读取（<code>r</code>）、写入（<code>w</code>）和执行（<code>x</code>）权限都被允许。</p>
<p>具体来说，<code>744</code> 权限表示：</p>
<ul>
<li>文件所有者有读（<code>r</code>）、写（<code>w</code>）和执行（<code>x</code>）权限。</li>
<li>文件所属组有读（<code>r</code>）权限。</li>
<li>其他用户有读（<code>r</code>）权限。</li>
</ul>
<p>这意味着文件所有者可以读取、写入和执行该文件，文件所属组的成员可以读取，其他用户也可以读取。</p>
<p>权限数字与其对应的含义如下：</p>
<ul>
<li><code>0</code>：没有权限</li>
<li><code>1</code>：执行权限（<code>x</code>）</li>
<li><code>2</code>：写入权限（<code>w</code>）</li>
<li><code>3</code>：写入权限 + 执行权限（<code>w</code> + <code>x</code>）</li>
<li><code>4</code>：读取权限（<code>r</code>）</li>
<li><code>5</code>：读取权限 + 执行权限（<code>r</code> + <code>x</code>）</li>
<li><code>6</code>：读取权限 + 写入权限（<code>r</code> + <code>w</code>）</li>
<li><code>7</code>：读取权限 + 写入权限 + 执行权限（<code>r</code> + <code>w</code> + <code>x</code>）</li>
</ul>
<p><code>-rw-rw-r--</code> 表示一个文件的权限和属性。这是一个常见的 Unix/Linux 文件权限表示形式，它包含了文件的权限以及一些其他属性。每个字符代表一组权限和属性。</p>
<p>在 <code>-rw-rw-r--</code> 中：</p>
<ul>
<li>第一个字符 <code>-</code> 表示这是一个普通文件（不是目录、链接等）。</li>
<li>接下来的三个字符 <code>rw-</code> 表示文件所有者（user）拥有读取（<code>r</code>）和写入（<code>w</code>）权限，但没有执行权限（<code>-</code>）。</li>
<li>紧随其后的三个字符 <code>rw-</code> 表示文件所属组（group）的成员也拥有读取和写入权限，同样没有执行权限。</li>
<li>最后的三个字符 <code>r--</code> 表示其他用户（others）只有读取权限，没有写入和执行权限。</li>
</ul>
<p>综合起来，<code>-rw-rw-r--</code> 表示这个文件的权限如下：</p>
<ul>
<li>文件所有者可以读取和写入文件，但不能执行它。</li>
<li>文件所属组的成员也可以读取和写入文件，但不能执行。</li>
<li>其他用户只能读取文件，不能写入和执行。</li>
</ul>
<p>这是一个典型的示例，展示了在Unix/Linux系统中，文件权限是如何以字符形式表示的。</p>
]]></description><link>https://www.ranisa.cn/pages/b08f91/</link><guid isPermaLink="true">https://www.ranisa.cn/pages/b08f91/</guid><pubDate>Wed, 29 Jul 2026 00:00:00 GMT</pubDate></item><item><title><![CDATA[GPT分区使用 parted 扩展分区的操作流程]]></title><description><![CDATA[<hr>
<p>title: GPT分区使用 <code>parted</code> 扩展分区的操作流程
date: 2024-08-28 14:00:00
titleTag: 原创
permalink: /pages/expand-partition-with-parted/
categories:</p>
<ul>
<li>Linux笔记</li>
<li>工作笔记
tags:</li>
<li>parted</li>
<li>分区管理</li>
<li>XFS</li>
<li>文件系统扩展</li>
</ul>
<hr>
<h2>背景</h2>
<p>在 Linux 系统的日常运维中，扩展分区以适应增长的存储需求是非常常见的操作。本次任务中，我们遇到了以下情况：原有的 <code>/dev/sdb2</code> 分区使用 XFS 文件系统，并挂载在 <code>/data1</code> 目录下，大小为 300G。需求是将其扩展到 600G，而不影响原有数据。</p>
<p>最初尝试使用 <code>fdisk</code> 工具进行分区扩展，但由于该分区使用 GPT（GUID Partition Table），<code>fdisk</code> 给出了警告，并且最终操作失败。随后，我们转向了 <code>parted</code> 工具，成功完成了分区和文件系统的扩展操作。</p>
<h2>使用 <code>parted</code> 工具扩展 XFS 分区的步骤</h2>
<h3>1. 确保数据备份</h3>
<p>在进行任何涉及分区的操作之前，强烈建议对分区上的数据进行备份。虽然以下步骤不会删除数据，但在任何意外情况下，备份都是最后的保障。</p>
<h3>2. 卸载分区</h3>
<p>在开始调整分区大小之前，首先需要卸载 <code>/data1</code> 分区：</p>
<pre><code class="language-bash">sudo umount /data1
</code></pre>
<h3>3. 使用 <code>parted</code> 扩展分区</h3>
<p>启动 <code>parted</code> 工具并选择要操作的磁盘（这里为 <code>/dev/sdb</code>）：</p>
<pre><code class="language-bash">sudo parted /dev/sdb
</code></pre>
<p>在 <code>parted</code> 环境中执行以下步骤：</p>
<ol>
<li>
<p><strong>显示分区信息</strong>：使用 <code>print</code> 命令查看当前的分区信息，确认要扩展的分区（<code>/dev/sdb2</code>）的开始扇区。</p>
<pre><code class="language-bash">(parted) print
</code></pre>
</li>
<li>
<p><strong>调整分区大小</strong>：使用 <code>resizepart</code> 命令扩展分区。假设分区 2 的开始扇区为 <code>419428352</code>，并且我们希望将其扩展到磁盘的末尾。</p>
<pre><code class="language-bash">(parted) resizepart 2 100%
</code></pre>
<p>这里的 <code>100%</code> 表示我们希望分区占用磁盘的全部可用空间。</p>
</li>
<li>
<p><strong>退出 <code>parted</code></strong>：操作完成后，使用 <code>quit</code> 命令退出 <code>parted</code>。</p>
<pre><code class="language-bash">(parted) quit
</code></pre>
</li>
</ol>
<h3>4. 扩展 XFS 文件系统</h3>
<p>由于分区已经成功扩展，现在需要使用 <code>xfs_growfs</code> 命令来调整 XFS 文件系统的大小，以利用新增加的空间：</p>
<pre><code class="language-bash">sudo xfs_growfs /data1
</code></pre>
<p>这个命令会在线扩展挂载的文件系统，无需卸载。</p>
<h3>5. 验证扩展结果</h3>
<p>最后，使用 <code>df -h</code> 命令检查分区大小，确保文件系统已经成功扩展：</p>
<pre><code class="language-bash">df -h /data1
</code></pre>
<p>成功后，你应该看到 <code>/data1</code> 的总容量已经从 300G 增加到了 600G，并且有足够的可用空间。</p>
<h2>总结</h2>
<p>通过这次操作，我们了解到在使用 GPT 分区表时，<code>fdisk</code> 可能会存在不稳定的情况，尤其是在处理较大的磁盘时。而 <code>parted</code> 工具提供了更为稳定和灵活的分区管理方式，尤其是在需要调整分区大小的场景中。使用 <code>parted</code> 和 <code>xfs_growfs</code> 的组合，可以确保在不中断服务的情况下，平稳扩展 XFS 文件系统。</p>
]]></description><link>https://www.ranisa.cn/pages/expand-partition-with-parted/</link><guid isPermaLink="true">https://www.ranisa.cn/pages/expand-partition-with-parted/</guid><pubDate>Wed, 29 Jul 2026 00:00:00 GMT</pubDate></item><item><title><![CDATA[实用linux命令-sed]]></title><description><![CDATA[<hr>
<p>title: 实用linux命令-sed
titleTag: 原创
date: 2022-03-10 02:52:51
permalink: /pages/3a51f9/
categories:</p>
<ul>
<li>Linux笔记</li>
<li>工作笔记
tags:</li>
<li>Linux</li>
<li>运维</li>
</ul>
<hr>
<p>::: tip 版本说明
本文写于 2022-03。&lt;br&gt;<code>sed</code> 命令用法多年未变，经 2026-07 复核仍适用。
:::</p>
<p><strong>sed命令简介</strong></p>
<p><code>sed</code>（Stream Editor）是一个强大的文本处理工具，主要用于文本替换、删除、新增和选取等操作。它是一个面向行的文本处理工具，可以逐行处理文件内容而不需要打开文件。sed特别适合用于自动化脚本中进行文本转换。</p>
<hr>
<p><strong>sed基本语法</strong></p>
<pre><code class="language-bash">sed [选项] 'command' 输入文本
</code></pre>
<p>说明：</p>
<ul>
<li><code>选项</code>控制sed的行为</li>
<li><code>command</code>是要执行的操作</li>
<li><code>输入文本</code>是要处理的文件或标准输入</li>
</ul>
<hr>
<p><strong>sed常用选项</strong></p>
<ol>
<li>
<p><strong>安静模式</strong></p>
<pre><code class="language-bash">sed -n 'command' file
</code></pre>
<p>说明：</p>
<ul>
<li><code>-n</code>选项启用安静模式，默认情况下sed会打印所有行</li>
<li>使用此选项后，只有经过特殊处理的行才会被输出</li>
</ul>
</li>
<li>
<p><strong>直接编辑文件</strong></p>
<pre><code class="language-bash">sed -i 'command' file
</code></pre>
<p>说明：</p>
<ul>
<li><code>-i</code>选项直接修改文件内容，而不是输出到屏幕</li>
<li>建议在使用前先备份文件</li>
</ul>
</li>
<li>
<p><strong>多命令执行</strong></p>
<pre><code class="language-bash">sed -e 'command1' -e 'command2' file
</code></pre>
<p>说明：</p>
<ul>
<li><code>-e</code>选项允许在一次调用中执行多个命令</li>
</ul>
</li>
<li>
<p><strong>使用命令文件</strong></p>
<pre><code class="language-bash">sed -f script.sed file
</code></pre>
<p>说明：</p>
<ul>
<li><code>-f</code>选项从文件中读取sed命令，适合复杂操作</li>
</ul>
</li>
<li>
<p><strong>使用扩展正则表达式</strong></p>
<pre><code class="language-bash">sed -r 'command' file
</code></pre>
<p>说明：</p>
<ul>
<li><code>-r</code>选项启用扩展正则表达式语法</li>
</ul>
</li>
</ol>
<hr>
<p><strong>sed常用命令</strong></p>
<ol>
<li>
<p><strong>替换文本 (s命令)</strong></p>
<pre><code class="language-bash">sed 's/pattern/replacement/g' file
</code></pre>
<p>说明：</p>
<ul>
<li><code>s</code>表示替换</li>
<li><code>pattern</code>是要查找的模式</li>
<li><code>replacement</code>是替换的内容</li>
<li><code>g</code>表示全局替换（一行中所有匹配）</li>
<li>不加<code>g</code>只替换每行第一次匹配</li>
</ul>
</li>
<li>
<p><strong>删除行 (d命令)</strong></p>
<pre><code class="language-bash">sed '/pattern/d' file
</code></pre>
<p>说明：</p>
<ul>
<li>删除包含指定模式的行</li>
<li>例如：<code>sed '/^$/d' file</code> 删除所有空行</li>
</ul>
</li>
<li>
<p><strong>追加文本 (a命令)</strong></p>
<pre><code class="language-bash">sed '/pattern/a 新文本' file
</code></pre>
<p>说明：</p>
<ul>
<li>在匹配行后追加文本</li>
<li>新文本会出现在匹配行的下一行</li>
</ul>
</li>
<li>
<p><strong>插入文本 (i命令)</strong></p>
<pre><code class="language-bash">sed '/pattern/i 新文本' file
</code></pre>
<p>说明：</p>
<ul>
<li>在匹配行前插入文本</li>
<li>新文本会出现在匹配行的上一行</li>
</ul>
</li>
<li>
<p><strong>替换整行 (c命令)</strong></p>
<pre><code class="language-bash">sed '/pattern/c 新文本' file
</code></pre>
<p>说明：</p>
<ul>
<li>用新文本替换包含指定模式的整行</li>
</ul>
</li>
<li>
<p><strong>打印特定行 (p命令)</strong></p>
<pre><code class="language-bash">sed -n '/pattern/p' file
</code></pre>
<p>说明：</p>
<ul>
<li>只打印匹配指定模式的行</li>
<li>通常与<code>-n</code>选项一起使用</li>
</ul>
</li>
</ol>
<hr>
<p><strong>sed高级用法</strong></p>
<ol>
<li>
<p><strong>使用行号</strong></p>
<pre><code class="language-bash">sed '1,5d' file  # 删除1-5行
sed '3,7s/old/new/g' file  # 只替换3-7行
</code></pre>
<p>说明：</p>
<ul>
<li>可以使用行号指定操作范围</li>
<li><code>$</code>表示最后一行，如<code>5,$d</code>删除第5行到最后</li>
</ul>
</li>
<li>
<p><strong>使用正则表达式</strong></p>
<pre><code class="language-bash">sed '/^#/d' file  # 删除所有注释行（以#开头）
sed '/start/,/end/d' file  # 删除从start到end之间的所有行
</code></pre>
<p>说明：</p>
<ul>
<li>可以使用正则表达式匹配模式</li>
<li>可以指定范围模式</li>
</ul>
</li>
<li>
<p><strong>保留备份</strong></p>
<pre><code class="language-bash">sed -i.bak 's/old/new/g' file
</code></pre>
<p>说明：</p>
<ul>
<li><code>-i.bak</code>会在修改文件的同时创建一个后缀为.bak的备份文件</li>
</ul>
</li>
<li>
<p><strong>多个替换操作</strong></p>
<pre><code class="language-bash">sed 's/old1/new1/g; s/old2/new2/g' file
</code></pre>
<p>说明：</p>
<ul>
<li>使用分号分隔多个命令</li>
<li>也可以使用<code>-e</code>选项：<code>sed -e 's/old1/new1/g' -e 's/old2/new2/g' file</code></li>
</ul>
</li>
<li>
<p><strong>使用&amp;引用匹配文本</strong></p>
<pre><code class="language-bash">sed 's/hello/&amp;, world/g' file  # hello 替换为 hello, world
</code></pre>
<p>说明：</p>
<ul>
<li><code>&amp;</code>代表匹配的文本本身</li>
</ul>
</li>
<li>
<p><strong>使用捕获组</strong></p>
<pre><code class="language-bash">sed -r 's/(foo)-(bar)/\2-\1/g' file  # foo-bar 替换为 bar-foo
</code></pre>
<p>说明：</p>
<ul>
<li>使用<code>\1</code>, <code>\2</code>等引用捕获的组</li>
</ul>
</li>
</ol>
<hr>
<p><strong>实用sed示例</strong></p>
<ol>
<li>
<p><strong>替换带有关键字的整行</strong></p>
<pre><code class="language-bash"># 替换前先显示出来看一下
sed -n '/mykeywords/c xxxxxxxxxxxxxx' `grep -rl 'mykeywords'`

# -i直接替换
sed -i '/mykeywords/c xxxxxxxxxxxxxx' `grep -rl 'mykeywords'`
</code></pre>
<p>说明：</p>
<ul>
<li>结合<code>grep -r</code>查找包含关键字的文件</li>
<li>使用<code>c</code>命令替换整行内容</li>
</ul>
</li>
<li>
<p><strong>删除文件中的空行</strong></p>
<pre><code class="language-bash">sed -i '/^$/d' file
</code></pre>
<p>说明：</p>
<ul>
<li><code>^$</code>匹配空行（行首紧跟行尾）</li>
</ul>
</li>
<li>
<p><strong>在文件的每行前添加内容</strong></p>
<pre><code class="language-bash">sed 's/^/添加的前缀/' file
</code></pre>
<p>说明：</p>
<ul>
<li><code>^</code>匹配行首，在行首添加文本</li>
</ul>
</li>
<li>
<p><strong>在文件的每行后添加内容</strong></p>
<pre><code class="language-bash">sed 's/$/添加的后缀/' file
</code></pre>
<p>说明：</p>
<ul>
<li><code>$</code>匹配行尾，在行尾添加文本</li>
</ul>
</li>
<li>
<p><strong>只显示指定行范围</strong></p>
<pre><code class="language-bash">sed -n '10,20p' file  # 只显示10-20行
</code></pre>
<p>说明：</p>
<ul>
<li>结合<code>-n</code>和<code>p</code>命令，只打印指定范围的行</li>
</ul>
</li>
<li>
<p><strong>多个文件批量替换</strong></p>
<pre><code class="language-bash">sed -i 's/old/new/g' file1 file2 file3
</code></pre>
<p>说明：</p>
<ul>
<li>sed可以同时处理多个文件</li>
</ul>
</li>
</ol>
<hr>
<p><strong>sed与其他工具的配合</strong></p>
<ol>
<li>
<p><strong>与grep结合</strong></p>
<pre><code class="language-bash">grep &quot;pattern&quot; file | sed 's/foo/bar/g'
</code></pre>
<p>说明：</p>
<ul>
<li>先用grep过滤出包含特定模式的行</li>
<li>然后用sed进行处理</li>
</ul>
</li>
<li>
<p><strong>与awk结合</strong></p>
<pre><code class="language-bash">sed 's/pattern/replacement/g' file | awk '{print $1}'
</code></pre>
<p>说明：</p>
<ul>
<li>sed处理后的输出可以传递给awk进一步处理</li>
</ul>
</li>
<li>
<p><strong>在shell脚本中使用</strong></p>
<pre><code class="language-bash">for file in *.txt; do
    sed -i 's/old/new/g' &quot;$file&quot;
done
</code></pre>
<p>说明：</p>
<ul>
<li>在循环中批量处理多个文件</li>
</ul>
</li>
</ol>
<hr>
<p><strong>sed注意事项</strong></p>
<ol>
<li>
<p><strong>转义字符</strong></p>
<ul>
<li>在模式中使用特殊字符（如<code>/</code>, <code>.</code>, <code>*</code>等）需要转义</li>
<li>例如：<code>sed 's/\/path\/to\/file/\/new\/path/g' file</code></li>
</ul>
</li>
<li>
<p><strong>不同分隔符</strong></p>
<ul>
<li>可以使用不同的分隔符来避免大量转义</li>
<li>例如：<code>sed 's#/path/to/file#/new/path#g' file</code></li>
</ul>
</li>
<li>
<p><strong>大文件处理</strong></p>
<ul>
<li>sed是逐行处理的，对大文件也很高效</li>
<li>但大量复杂的替换操作可能会影响性能</li>
</ul>
</li>
<li>
<p><strong>备份重要文件</strong></p>
<ul>
<li>使用<code>-i</code>选项修改文件前，建议先备份</li>
<li>或使用<code>-i.bak</code>自动创建备份</li>
</ul>
</li>
</ol>
<hr>
]]></description><link>https://www.ranisa.cn/pages/3a51f9/</link><guid isPermaLink="true">https://www.ranisa.cn/pages/3a51f9/</guid><pubDate>Wed, 29 Jul 2026 00:00:00 GMT</pubDate></item><item><title><![CDATA[VSCode快捷键备忘录]]></title><description><![CDATA[<hr>
<p>title: VSCode快捷键备忘录
date: 2022-08-17 11:21:42
permalink: /pages/b11f9cc/
categories:</p>
<ul>
<li>Linux笔记</li>
<li>工作笔记
tags:</li>
<li>Linux</li>
<li>运维</li>
</ul>
<hr>
<p>::: tip 版本说明
本文写于 2022-08。&lt;br&gt;常用快捷键经 2026-07 复核基本仍适用，个别快捷键在新版本 VSCode 中可能已可自定义或有默认值调整，如遇不生效请以 <code>Ctrl+K Ctrl+S</code> 打开的快捷键设置页为准核对。
:::</p>
<h1>VSCode (Visual Studio Code) 快速参考备忘单显示了它的键盘快捷键和命令。</h1>
<h2>Windows</h2>
<h3>通用</h3>
<table>
<thead>
<tr>
<th>-</th>
<th>-</th>
</tr>
</thead>
<tbody>
<tr>
<td><code>Ctrl</code> <code>Shift</code> <code>P</code> <em>/</em> <code>F1</code></td>
<td>显示命令面板</td>
</tr>
<tr>
<td><code>Ctrl</code> <code>P</code></td>
<td>快速打开，转到文件</td>
</tr>
<tr>
<td><code>Ctrl</code> <code>Shift</code> <code>N</code></td>
<td>打开新窗口</td>
</tr>
<tr>
<td><code>Ctrl</code> <code>Shift</code> <code>W</code></td>
<td>关闭当前窗口</td>
</tr>
<tr>
<td><code>Ctrl</code> <code>,</code></td>
<td>打开用户设置</td>
</tr>
<tr>
<td><code>Ctrl</code> <code>K</code> <code>Ctrl</code> <code>S</code></td>
<td>打开键盘快捷键设置</td>
</tr>
</tbody>
</table>
<p>&lt;!--rehype:className=shortcuts--&gt;</p>
<h3>基本编辑</h3>
<p>&lt;!--rehype:wrap-style=grid-row: span 2/span 2;--&gt;</p>
<table>
<thead>
<tr>
<th>-</th>
<th>-</th>
</tr>
</thead>
<tbody>
<tr>
<td><code>Ctrl</code> <code>X</code></td>
<td>剪切行</td>
</tr>
<tr>
<td><code>Ctrl</code> <code>C</code></td>
<td>复制行</td>
</tr>
<tr>
<td><code>Alt</code> <code>↑</code> <em>/</em> <code>↓</code></td>
<td>向上/向下移动行</td>
</tr>
<tr>
<td><code>Shift</code> <code>Alt</code> <code>↓</code> <em>/</em> <code>↑</code></td>
<td>向上/向下复制行</td>
</tr>
<tr>
<td><code>Ctrl</code> <code>Shift</code> <code>K</code></td>
<td>删除行</td>
</tr>
<tr>
<td><code>Ctrl</code> <code>Enter</code></td>
<td>在下面插入行</td>
</tr>
<tr>
<td><code>Ctrl</code> <code>Shift</code> <code>Enter</code></td>
<td>在上面插入行</td>
</tr>
<tr>
<td><code>Ctrl</code> <code>Shift</code> <code>\</code></td>
<td>跳转到匹配的括号</td>
</tr>
<tr>
<td><code>Ctrl</code> <code>]</code> <em>/</em> <code>[</code></td>
<td>缩进/突出行</td>
</tr>
<tr>
<td><code>Home</code> <em>/</em> <code>End</code></td>
<td>转到行首/行尾</td>
</tr>
<tr>
<td><code>Ctrl</code> <code>Home</code></td>
<td>转到文件开头</td>
</tr>
<tr>
<td><code>Ctrl</code> <code>End</code></td>
<td>转到文件末尾</td>
</tr>
<tr>
<td><code>Ctrl</code> <code>↑</code> <em>/</em> <code>↓</code></td>
<td>向上/向下滚动行</td>
</tr>
<tr>
<td><code>Alt</code> <code>PgUp</code> <em>/</em> <code>PgDn</code></td>
<td>向上/向下滚动页面</td>
</tr>
<tr>
<td><code>Ctrl</code> <code>Shift</code> <code>[</code></td>
<td>折叠区域</td>
</tr>
<tr>
<td><code>Ctrl</code> <code>Shift</code> <code>]</code></td>
<td>展开区域</td>
</tr>
<tr>
<td><code>Ctrl</code> <code>K</code> <code>Ctrl</code> <code>[</code></td>
<td>折叠所有子区域</td>
</tr>
<tr>
<td><code>Ctrl</code> <code>K</code> <code>Ctrl</code> <code>]</code></td>
<td>展开所有子区域</td>
</tr>
<tr>
<td><code>Ctrl</code> <code>K</code> <code>Ctrl</code> <code>0</code></td>
<td>折叠所有区域</td>
</tr>
<tr>
<td><code>Ctrl</code> <code>K</code> <code>Ctrl</code> <code>J</code></td>
<td>展开所有区域</td>
</tr>
<tr>
<td><code>Ctrl</code> <code>K</code> <code>Ctrl</code> <code>C</code></td>
<td>添加行注释</td>
</tr>
<tr>
<td><code>Ctrl</code> <code>K</code> <code>Ctrl</code> <code>U</code></td>
<td>删除行注释</td>
</tr>
<tr>
<td><code>Ctrl</code> <code>/</code></td>
<td>切换行注释</td>
</tr>
<tr>
<td><code>Shift</code> <code>Alt</code> <code>A</code></td>
<td>切换块注释</td>
</tr>
<tr>
<td><code>Alt</code> <code>Z</code></td>
<td>切换自动换行</td>
</tr>
</tbody>
</table>
<p>&lt;!--rehype:className=shortcuts--&gt;</p>
<h3>导航</h3>
<table>
<thead>
<tr>
<th>-</th>
<th>-</th>
</tr>
</thead>
<tbody>
<tr>
<td><code>Ctrl</code> <code>T</code></td>
<td>显示所有符号</td>
</tr>
<tr>
<td><code>Ctrl</code> <code>G</code></td>
<td>跳转到指定行数</td>
</tr>
<tr>
<td><code>Ctrl</code> <code>P</code></td>
<td>转到文件</td>
</tr>
<tr>
<td><code>Ctrl</code> <code>Shift</code> <code>O</code></td>
<td>转到符号</td>
</tr>
<tr>
<td><code>Ctrl</code> <code>Shift</code> <code>M</code></td>
<td>显示问题面板</td>
</tr>
<tr>
<td><code>F8</code></td>
<td>转到下一个错误</td>
</tr>
<tr>
<td><code>Shift</code> <code>F8</code></td>
<td>转到上一个错误</td>
</tr>
<tr>
<td><code>Ctrl</code> <code>Shift</code> <code>Tab</code></td>
<td>浏览编辑组历史</td>
</tr>
<tr>
<td><code>Alt</code> <code>←</code> <em>/</em> <code>→</code></td>
<td>后退/前进</td>
</tr>
<tr>
<td><code>Ctrl</code> <code>M</code></td>
<td>切换按 Tab 移动焦点</td>
</tr>
</tbody>
</table>
<p>&lt;!--rehype:className=shortcuts--&gt;</p>
<h3>搜索和替换</h3>
<table>
<thead>
<tr>
<th>-</th>
<th>-</th>
</tr>
</thead>
<tbody>
<tr>
<td><code>Ctrl</code> <code>F</code></td>
<td>查找</td>
</tr>
<tr>
<td><code>Ctrl</code> <code>H</code></td>
<td>替换</td>
</tr>
<tr>
<td><code>F3</code> <em>/</em> <code>Shift</code> <code>F3</code></td>
<td>查找下一个/上一个</td>
</tr>
<tr>
<td><code>Alt</code> <code>Enter</code></td>
<td>选择所有出现的查找匹配项</td>
</tr>
<tr>
<td><code>Ctrl</code> <code>D</code></td>
<td>将所选内容设置为查找关键词</td>
</tr>
<tr>
<td><code>Ctrl</code> <code>K</code> <code>Ctrl</code> <code>D</code></td>
<td>将上一个选择移动到下一个查找匹配项</td>
</tr>
<tr>
<td><code>Alt</code> <code>C</code> <em>/</em> <code>R</code> <em>/</em> <code>W</code></td>
<td>切换区分大小写/正则表达式/全字匹配</td>
</tr>
</tbody>
</table>
<p>&lt;!--rehype:className=shortcuts--&gt;</p>
<h3>多光标和选择</h3>
<table>
<thead>
<tr>
<th>-</th>
<th>-</th>
</tr>
</thead>
<tbody>
<tr>
<td><code>Alt</code> <code>Click</code></td>
<td>插入光标</td>
</tr>
<tr>
<td><code>Ctrl</code> <code>Alt</code> <code>↑</code> <em>/</em> <code>↓</code></td>
<td>在上方/下方插入光标</td>
</tr>
<tr>
<td><code>Ctrl</code> <code>U</code></td>
<td>撤消上一次光标操作</td>
</tr>
<tr>
<td><code>Shift</code> <code>Alt</code> <code>I</code></td>
<td>在选定的每一行的末尾插入光标</td>
</tr>
<tr>
<td><code>Ctrl</code> <code>I</code></td>
<td>选择当前行</td>
</tr>
<tr>
<td><code>Ctrl</code> <code>Shift</code> <code>L</code></td>
<td>选择当前选择的所有匹配项</td>
</tr>
<tr>
<td><code>Ctrl</code> <code>F2</code></td>
<td>选择当前单词的所有出现</td>
</tr>
<tr>
<td><code>Shift</code> <code>Alt</code> <code>→</code></td>
<td>展开选择</td>
</tr>
<tr>
<td><code>Shift</code> <code>Alt</code> <code>←</code></td>
<td>收起选择</td>
</tr>
<tr>
<td><code>Shift</code> <code>Alt</code> <code>&lt;Drag&gt;</code></td>
<td>列（框）选择</td>
</tr>
<tr>
<td><code>Ctrl</code> <code>Shift</code> <code>Alt</code> <code>&lt;Arrow&gt;</code></td>
<td>列（框）选择</td>
</tr>
<tr>
<td><code>Ctrl</code> <code>Shift</code> <code>Alt</code> <code>PgUp</code> <em>/</em> <code>PgDn</code></td>
<td>列（框）选择页上/下</td>
</tr>
</tbody>
</table>
<p>&lt;!--rehype:className=shortcuts--&gt;</p>
<h3>丰富的语言编辑</h3>
<table>
<thead>
<tr>
<th>-</th>
<th>-</th>
</tr>
</thead>
<tbody>
<tr>
<td><code>Ctrl</code> <code>&lt;Space&gt;</code> <code>Ctrl</code> <code>I</code></td>
<td>显示建议</td>
</tr>
<tr>
<td><code>Ctrl</code> <code>Shift</code> <code>&lt;Space&gt;</code></td>
<td>显示参数提示</td>
</tr>
<tr>
<td><code>Shift</code> <code>Alt</code> <code>F</code></td>
<td>格式化文档</td>
</tr>
<tr>
<td><code>Ctrl</code> <code>K</code> <code>Ctrl</code> <code>F</code></td>
<td>格式化所选区域</td>
</tr>
<tr>
<td><code>F12</code></td>
<td>转到定义</td>
</tr>
<tr>
<td><code>Alt</code> <code>F12</code></td>
<td>速览定义</td>
</tr>
<tr>
<td><code>Ctrl</code> <code>K</code> <code>F12</code></td>
<td>在侧边栏中打开定义</td>
</tr>
<tr>
<td><code>Ctrl</code> <code>.</code></td>
<td>快速修复</td>
</tr>
<tr>
<td><code>Shift</code> <code>F12</code></td>
<td>显示引用</td>
</tr>
<tr>
<td><code>F2</code></td>
<td>重命名符号</td>
</tr>
<tr>
<td><code>Ctrl</code> <code>K</code> <code>Ctrl</code> <code>X</code></td>
<td>删除尾随空格</td>
</tr>
<tr>
<td><code>Ctrl</code> <code>K</code> <code>M</code></td>
<td>更改文件语言</td>
</tr>
</tbody>
</table>
<p>&lt;!--rehype:className=shortcuts--&gt;</p>
<h3>编辑管理</h3>
<table>
<thead>
<tr>
<th>-</th>
<th>-</th>
</tr>
</thead>
<tbody>
<tr>
<td><code>Ctrl</code> <code>F4</code> <code>Ctrl</code> <code>W</code></td>
<td>关闭编辑器</td>
</tr>
<tr>
<td><code>Ctrl</code> <code>K</code> <code>F</code></td>
<td>关闭文件夹</td>
</tr>
<tr>
<td><code>Ctrl</code> <code>\</code></td>
<td>拆分编辑器</td>
</tr>
<tr>
<td><code>Ctrl</code> <code>1</code> <em>/</em> <code>2</code> <em>/</em> <code>3</code></td>
<td>将焦点切换到第一/二/三编辑组</td>
</tr>
<tr>
<td><code>Ctrl</code> <code>K</code> <code>Ctrl</code> <code>←</code> <em>/</em> <code>→</code></td>
<td>将焦点切换到上/下一个编辑组</td>
</tr>
<tr>
<td><code>Ctrl</code> <code>Shift</code> <code>PgUp</code> <em>/</em> <code>PgDn</code></td>
<td>向左/向右移动编辑器</td>
</tr>
<tr>
<td><code>Ctrl</code> <code>K</code> <code>←</code> <em>/</em> <code>→</code></td>
<td>移动活动编辑器组</td>
</tr>
</tbody>
</table>
<p>&lt;!--rehype:className=shortcuts--&gt;</p>
<h3>文件管理</h3>
<table>
<thead>
<tr>
<th>-</th>
<th>-</th>
</tr>
</thead>
<tbody>
<tr>
<td><code>Ctrl</code> <code>N</code></td>
<td>新建文件</td>
</tr>
<tr>
<td><code>Ctrl</code> <code>O</code></td>
<td>打开文件</td>
</tr>
<tr>
<td><code>Ctrl</code> <code>S</code></td>
<td>保存</td>
</tr>
<tr>
<td><code>Ctrl</code> <code>Shift</code> <code>S</code></td>
<td>另存为</td>
</tr>
<tr>
<td><code>Ctrl</code> <code>K</code> <code>S</code></td>
<td>保存所有</td>
</tr>
<tr>
<td><code>Ctrl</code> <code>F4</code></td>
<td>关闭</td>
</tr>
<tr>
<td><code>Ctrl</code> <code>K</code> <code>Ctrl</code> <code>W</code></td>
<td>关闭所有</td>
</tr>
<tr>
<td><code>Ctrl</code> <code>Shift</code> <code>T</code></td>
<td>重新打开关闭的编辑器</td>
</tr>
<tr>
<td><code>Ctrl</code> <code>K</code> <code>Enter</code></td>
<td>保持预览模式编辑器打开</td>
</tr>
<tr>
<td><code>Ctrl</code> <code>Tab</code></td>
<td>打开下一项</td>
</tr>
<tr>
<td><code>Ctrl</code> <code>Shift</code> <code>Tab</code></td>
<td>打开上一项</td>
</tr>
<tr>
<td><code>Ctrl</code> <code>K</code> <code>P</code></td>
<td>复制活动文件的路径</td>
</tr>
<tr>
<td><code>Ctrl</code> <code>K</code> <code>R</code></td>
<td>在资源管理器中显示活动文件</td>
</tr>
<tr>
<td><code>Ctrl</code> <code>K</code> <code>O</code></td>
<td>在新窗口/实例中显示活动文件</td>
</tr>
</tbody>
</table>
<p>&lt;!--rehype:className=shortcuts--&gt;</p>
<h3>展示</h3>
<table>
<thead>
<tr>
<th>-</th>
<th>-</th>
</tr>
</thead>
<tbody>
<tr>
<td><code>F11</code></td>
<td>切换全屏</td>
</tr>
<tr>
<td><code>Shift</code> <code>Alt</code> <code>0</code></td>
<td>切换编辑器布局（水平/垂直）</td>
</tr>
<tr>
<td><code>Ctrl</code> <code>=</code> <em>/</em> <code>-</code></td>
<td>放大/缩小</td>
</tr>
<tr>
<td><code>Ctrl</code> <code>B</code></td>
<td>切换侧边栏可见性</td>
</tr>
<tr>
<td><code>Ctrl</code> <code>Shift</code> <code>E</code></td>
<td>显示资源管理器/切换焦点</td>
</tr>
<tr>
<td><code>Ctrl</code> <code>Shift</code> <code>F</code></td>
<td>显示搜索</td>
</tr>
<tr>
<td><code>Ctrl</code> <code>Shift</code> <code>G</code></td>
<td>显示源代码管理</td>
</tr>
<tr>
<td><code>Ctrl</code> <code>Shift</code> <code>D</code></td>
<td>显示调试</td>
</tr>
<tr>
<td><code>Ctrl</code> <code>Shift</code> <code>X</code></td>
<td>显示扩展</td>
</tr>
<tr>
<td><code>Ctrl</code> <code>Shift</code> <code>H</code></td>
<td>在文件中替换</td>
</tr>
<tr>
<td><code>Ctrl</code> <code>Shift</code> <code>J</code></td>
<td>切换搜索详细信息</td>
</tr>
<tr>
<td><code>Ctrl</code> <code>Shift</code> <code>U</code></td>
<td>显示输出面板</td>
</tr>
<tr>
<td><code>Ctrl</code> <code>Shift</code> <code>V</code></td>
<td>打开 Markdown 预览</td>
</tr>
<tr>
<td><code>Ctrl</code> <code>K</code> <code>V</code></td>
<td>打开 Markdown 预览到一边</td>
</tr>
<tr>
<td><code>Ctrl</code> <code>K</code> <code>Z</code></td>
<td>Zen 模式（Esc Esc 退出）</td>
</tr>
</tbody>
</table>
<p>&lt;!--rehype:className=shortcuts--&gt;</p>
<h3>调试</h3>
<table>
<thead>
<tr>
<th>-</th>
<th>-</th>
</tr>
</thead>
<tbody>
<tr>
<td><code>F9</code></td>
<td>切换断点</td>
</tr>
<tr>
<td><code>F5</code></td>
<td>开始/继续</td>
</tr>
<tr>
<td><code>Shift</code> <code>F5</code></td>
<td>停止</td>
</tr>
<tr>
<td><code>Shift</code> <code>F11</code> <em>/</em> <code>F11</code></td>
<td>单步调试/跳出</td>
</tr>
<tr>
<td><code>F10</code></td>
<td>单步跳过</td>
</tr>
<tr>
<td><code>Ctrl</code> <code>K</code> <code>Ctrl</code> <code>I</code></td>
<td>显示悬停</td>
</tr>
<tr>
<td><code>Ctrl</code> &lt;code&gt;`&lt;/code&gt;</td>
<td>显示综合终端</td>
</tr>
<tr>
<td><code>Ctrl</code> <code>Shift</code> &lt;code&gt;`&lt;/code&gt;</td>
<td>创建一个新终端</td>
</tr>
<tr>
<td><code>Ctrl</code> <code>C</code></td>
<td>复制所选内容</td>
</tr>
<tr>
<td><code>Ctrl</code> <code>V</code></td>
<td>粘贴到活动终端</td>
</tr>
<tr>
<td><code>Ctrl</code> <code>↑</code> <em>/</em> <code>↓</code></td>
<td>向上/向下滚动</td>
</tr>
<tr>
<td><code>Shift</code> <code>PgUp</code> <em>/</em> <code>PgDn</code></td>
<td>向上/向下滚动页面</td>
</tr>
<tr>
<td><code>Ctrl</code> <code>Home</code> <em>/</em> <code>End</code></td>
<td>滚动到顶部/底部</td>
</tr>
</tbody>
</table>
<p>&lt;!--rehype:className=shortcuts--&gt;
<img src="/img/inline/vscode-shortcuts.png" alt="img"></p>
]]></description><link>https://www.ranisa.cn/pages/b11f9cc/</link><guid isPermaLink="true">https://www.ranisa.cn/pages/b11f9cc/</guid><pubDate>Wed, 29 Jul 2026 00:00:00 GMT</pubDate></item><item><title><![CDATA[实用linux命令-curl]]></title><description><![CDATA[<hr>
<p>title: 实用linux命令-curl
titleTag: 原创
date: 2025-06-10 02:52:51
permalink: /pages/curl-command/
categories:</p>
<ul>
<li>Linux笔记</li>
<li>工作笔记
tags:</li>
<li>Linux</li>
<li>运维</li>
</ul>
<hr>
<p><strong>curl命令简介</strong></p>
<p><code>curl</code>是一个强大的命令行工具，用于进行数据传输。它支持多种协议，包括HTTP、HTTPS、FTP、FTPS、SCP、SFTP、TFTP、LDAP、SMB等。curl在网络测试、API调用、文件下载、网站测试等场景中非常实用。它的名称源于&quot;Client for URLs&quot;，意为URL客户端。</p>
<hr>
<p><strong>curl基本语法</strong></p>
<pre><code class="language-bash">curl [选项] [URL]
</code></pre>
<p>说明：</p>
<ul>
<li><code>选项</code>控制curl的行为</li>
<li><code>URL</code>是要访问的网址或资源</li>
</ul>
<hr>
<p><strong>curl常用选项</strong></p>
<ol>
<li>
<p><strong>输出保存至文件</strong></p>
<pre><code class="language-bash">curl -o filename.html https://example.com
</code></pre>
<p>说明：</p>
<ul>
<li><code>-o</code>选项将输出保存到指定文件</li>
<li>文件名由用户自定义</li>
</ul>
</li>
<li>
<p><strong>自动命名保存文件</strong></p>
<pre><code class="language-bash">curl -O https://example.com/file.zip
</code></pre>
<p>说明：</p>
<ul>
<li><code>-O</code>选项自动使用URL中的文件名保存输出</li>
<li>适合直接下载文件</li>
</ul>
</li>
<li>
<p><strong>显示详细进度信息</strong></p>
<pre><code class="language-bash">curl -v https://example.com
</code></pre>
<p>说明：</p>
<ul>
<li><code>-v</code>选项显示详细的连接和传输信息</li>
<li>对调试连接问题非常有用</li>
</ul>
</li>
<li>
<p><strong>静默模式</strong></p>
<pre><code class="language-bash">curl -s https://example.com
</code></pre>
<p>说明：</p>
<ul>
<li><code>-s</code>选项不显示进度信息或错误消息</li>
<li>适合用于脚本中</li>
</ul>
</li>
<li>
<p><strong>跟随重定向</strong></p>
<pre><code class="language-bash">curl -L https://example.com
</code></pre>
<p>说明：</p>
<ul>
<li><code>-L</code>选项自动跟随HTTP重定向</li>
<li>网站常用302/301重定向到新位置</li>
</ul>
</li>
<li>
<p><strong>设置请求头</strong></p>
<pre><code class="language-bash">curl -H &quot;Content-Type: application/json&quot; https://api.example.com
</code></pre>
<p>说明：</p>
<ul>
<li><code>-H</code>选项设置HTTP请求头</li>
<li>可以多次使用设置多个头部</li>
</ul>
</li>
<li>
<p><strong>超时设置</strong></p>
<pre><code class="language-bash">curl --connect-timeout 5 https://example.com
</code></pre>
<p>说明：</p>
<ul>
<li><code>--connect-timeout</code>设置连接超时时间（秒）</li>
<li>防止连接不可达时长时间等待</li>
</ul>
</li>
</ol>
<hr>
<p><strong>curl常用请求方法</strong></p>
<ol>
<li>
<p><strong>GET请求（默认）</strong></p>
<pre><code class="language-bash">curl https://api.example.com
</code></pre>
<p>说明：</p>
<ul>
<li>不指定方法时，默认使用GET请求</li>
<li>用于获取资源</li>
</ul>
</li>
<li>
<p><strong>POST请求</strong></p>
<pre><code class="language-bash">curl -X POST -d &quot;name=value&amp;foo=bar&quot; https://api.example.com
</code></pre>
<p>说明：</p>
<ul>
<li><code>-X POST</code>指定使用POST方法</li>
<li><code>-d</code>后跟要发送的数据</li>
<li>常用于表单提交</li>
</ul>
</li>
<li>
<p><strong>PUT请求</strong></p>
<pre><code class="language-bash">curl -X PUT -d &quot;content&quot; https://api.example.com/resource
</code></pre>
<p>说明：</p>
<ul>
<li>用于更新指定资源</li>
<li>通常用于RESTful API</li>
</ul>
</li>
<li>
<p><strong>DELETE请求</strong></p>
<pre><code class="language-bash">curl -X DELETE https://api.example.com/resource/123
</code></pre>
<p>说明：</p>
<ul>
<li>用于删除指定的资源</li>
<li>常用于API中删除操作</li>
</ul>
</li>
<li>
<p><strong>HEAD请求</strong></p>
<pre><code class="language-bash">curl -I https://example.com
</code></pre>
<p>说明：</p>
<ul>
<li><code>-I</code>发送HEAD请求，只获取HTTP头信息</li>
<li>用于检查资源是否存在或最后修改时间</li>
</ul>
</li>
</ol>
<hr>
<p><strong>curl数据传输</strong></p>
<ol>
<li>
<p><strong>发送表单数据</strong></p>
<pre><code class="language-bash">curl -d &quot;username=admin&amp;password=secret&quot; https://example.com/login
</code></pre>
<p>说明：</p>
<ul>
<li><code>-d</code>选项发送application/x-www-form-urlencoded格式数据</li>
<li>模拟HTML表单提交</li>
</ul>
</li>
<li>
<p><strong>发送JSON数据</strong></p>
<pre><code class="language-bash">curl -X POST -H &quot;Content-Type: application/json&quot; -d '{&quot;name&quot;:&quot;John&quot;,&quot;age&quot;:30}' https://api.example.com/users
</code></pre>
<p>说明：</p>
<ul>
<li>通过设置合适的Content-Type头和格式化的数据</li>
<li>常用于API通信</li>
</ul>
</li>
<li>
<p><strong>上传文件</strong></p>
<pre><code class="language-bash">curl -F &quot;file=@localfile.jpg&quot; https://example.com/upload
</code></pre>
<p>说明：</p>
<ul>
<li><code>-F</code>选项使用multipart/form-data格式上传文件</li>
<li><code>@</code>符号后面是要上传的本地文件路径</li>
</ul>
</li>
<li>
<p><strong>从文件读取数据发送</strong></p>
<pre><code class="language-bash">curl -d @data.json -H &quot;Content-Type: application/json&quot; https://api.example.com
</code></pre>
<p>说明：</p>
<ul>
<li>使用<code>@</code>符号从文件读取发送内容</li>
<li>适合大量或格式化数据</li>
</ul>
</li>
</ol>
<hr>
<p><strong>curl高级用法</strong></p>
<ol>
<li>
<p><strong>HTTP认证</strong></p>
<pre><code class="language-bash">curl -u username:password https://example.com/secure
</code></pre>
<p>说明：</p>
<ul>
<li><code>-u</code>选项提供HTTP基本认证凭据</li>
<li>也支持摘要认证和其他认证方式</li>
</ul>
</li>
<li>
<p><strong>使用Cookie</strong></p>
<pre><code class="language-bash">curl -b &quot;name=value&quot; https://example.com
</code></pre>
<p>说明：</p>
<ul>
<li><code>-b</code>选项发送Cookie</li>
<li>可以从文件读取Cookie：<code>-b cookie.txt</code></li>
</ul>
</li>
<li>
<p><strong>保存Cookie</strong></p>
<pre><code class="language-bash">curl -c cookie.txt https://example.com/login
</code></pre>
<p>说明：</p>
<ul>
<li><code>-c</code>选项保存服务器设置的Cookie</li>
<li>适合模拟会话保持</li>
</ul>
</li>
<li>
<p><strong>使用代理</strong></p>
<pre><code class="language-bash">curl -x proxy.example.com:8080 https://target.com
</code></pre>
<p>说明：</p>
<ul>
<li><code>-x</code>选项指定HTTP代理</li>
<li>也支持SOCKS代理</li>
</ul>
</li>
<li>
<p><strong>限制传输速率</strong></p>
<pre><code class="language-bash">curl --limit-rate 200K https://example.com/bigfile
</code></pre>
<p>说明：</p>
<ul>
<li>限制下载速度，避免占用过多带宽</li>
<li>可以指定K(KB/s)或M(MB/s)单位</li>
</ul>
</li>
<li>
<p><strong>继续中断的下载</strong></p>
<pre><code class="language-bash">curl -C - -O https://example.com/largefile.zip
</code></pre>
<p>说明：</p>
<ul>
<li><code>-C -</code>自动从断点继续下载</li>
<li>有助于恢复中断的大文件下载</li>
</ul>
</li>
</ol>
<hr>
<p><strong>实用curl示例</strong></p>
<ol>
<li>
<p><strong>测试网站响应时间</strong></p>
<pre><code class="language-bash">curl -s -w &quot;DNS解析时间: %{time_namelookup}s\n连接时间: %{time_connect}s\n总时间: %{time_total}s\n&quot; -o /dev/null https://example.com
</code></pre>
<p>说明：</p>
<ul>
<li><code>-w</code>选项可以输出格式化的统计信息</li>
<li><code>-o /dev/null</code>丢弃实际内容</li>
</ul>
</li>
<li>
<p><strong>测试API并格式化JSON响应</strong></p>
<pre><code class="language-bash">curl -s https://api.example.com | python -m json.tool
</code></pre>
<p>说明：</p>
<ul>
<li>结合Python的json.tool模块格式化输出</li>
<li>也可以使用jq工具：<code>curl -s URL | jq</code></li>
</ul>
</li>
<li>
<p><strong>下载多个文件</strong></p>
<pre><code class="language-bash">curl -O https://example.com/file1.txt -O https://example.com/file2.txt
</code></pre>
<p>说明：</p>
<ul>
<li>可以在一个命令中指定多个URL下载</li>
<li>每个URL需要单独的-O选项</li>
</ul>
</li>
<li>
<p><strong>模拟浏览器请求</strong></p>
<pre><code class="language-bash">curl -A &quot;Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36&quot; https://example.com
</code></pre>
<p>说明：</p>
<ul>
<li><code>-A</code>选项设置User-Agent头</li>
<li>对于检测浏览器的网站很有用</li>
</ul>
</li>
<li>
<p><strong>验证HTTPS证书</strong></p>
<pre><code class="language-bash">curl -v https://example.com 2&gt;&amp;1 | grep &quot;SSL certificate&quot;
</code></pre>
<p>说明：</p>
<ul>
<li>验证网站的SSL证书信息</li>
<li>对安全检查很有用</li>
</ul>
</li>
<li>
<p><strong>测试WebSocket连接</strong></p>
<pre><code class="language-bash">curl -N -H &quot;Connection: Upgrade&quot; -H &quot;Upgrade: websocket&quot; -H &quot;Sec-WebSocket-Key: SGVsbG8sIHdvcmxkIQ==&quot; https://ws.example.com
</code></pre>
<p>说明：</p>
<ul>
<li>简单测试WebSocket服务器端点</li>
<li><code>-N</code>禁用输出缓冲</li>
</ul>
</li>
</ol>
<hr>
<p><strong>curl与其他工具的配合</strong></p>
<ol>
<li>
<p><strong>与jq结合处理JSON</strong></p>
<pre><code class="language-bash">curl -s https://api.example.com/users | jq '.users[].name'
</code></pre>
<p>说明：</p>
<ul>
<li>使用jq提取或过滤JSON数据</li>
<li>对API返回数据的处理非常有用</li>
</ul>
</li>
<li>
<p><strong>与grep结合提取信息</strong></p>
<pre><code class="language-bash">curl -s https://example.com | grep -o '&lt;title&gt;.*&lt;/title&gt;'
</code></pre>
<p>说明：</p>
<ul>
<li>提取页面中的特定内容</li>
<li>可以快速检索关键信息</li>
</ul>
</li>
<li>
<p><strong>在脚本中使用</strong></p>
<pre><code class="language-bash">response=$(curl -s -w &quot;%{http_code}&quot; -o /tmp/output.txt https://api.example.com)
if [ &quot;$response&quot; -eq 200 ]; then
    echo &quot;请求成功&quot;
else
    echo &quot;请求失败，状态码: $response&quot;
fi
</code></pre>
<p>说明：</p>
<ul>
<li>在shell脚本中捕获HTTP状态码</li>
<li>基于状态码执行不同操作</li>
</ul>
</li>
</ol>
<hr>
<p><strong>curl注意事项</strong></p>
<ol>
<li>
<p><strong>安全考虑</strong></p>
<ul>
<li>在命令行使用密码时需谨慎，可能会记录在shell历史记录中</li>
<li>考虑使用<code>~/.netrc</code>文件或环境变量存储凭据</li>
</ul>
</li>
<li>
<p><strong>HTTP/2支持</strong></p>
<ul>
<li>使用<code>--http2</code>选项启用HTTP/2支持</li>
<li>部分版本的curl默认支持HTTP/2</li>
</ul>
</li>
<li>
<p><strong>重定向处理</strong></p>
<ul>
<li>默认情况下不跟随重定向，使用<code>-L</code>选项开启</li>
<li>可以用<code>--max-redirs</code>限制最大重定向次数</li>
</ul>
</li>
<li>
<p><strong>证书验证</strong></p>
<ul>
<li>默认验证HTTPS证书，可用<code>-k</code>选项禁用验证</li>
<li>生产环境应避免禁用证书验证</li>
</ul>
</li>
<li>
<p><strong>请求频率限制</strong></p>
<ul>
<li>频繁请求可能触发服务器的速率限制或IP封禁</li>
<li>考虑使用<code>--limit-rate</code>和适当的延迟</li>
</ul>
</li>
</ol>
<hr>
]]></description><link>https://www.ranisa.cn/pages/curl-command/</link><guid isPermaLink="true">https://www.ranisa.cn/pages/curl-command/</guid><pubDate>Wed, 29 Jul 2026 00:00:00 GMT</pubDate></item><item><title><![CDATA[Kubernetes核心概念详解：Namespace、Pod、Deployment、PV和PVC]]></title><description><![CDATA[<hr>
<p>title: Kubernetes核心概念详解：Namespace、Pod、Deployment、PV和PVC
date: 2023-06-27 10:00:00
titleTag: 原创
permalink: /pages/kubernetes-core-concepts/
categories:</p>
<ul>
<li>Linux笔记</li>
<li>K8S
tags:</li>
<li>Kubernetes</li>
<li>容器化</li>
<li>集群管理</li>
</ul>
<hr>
<h3>Kubernetes中的Namespace、Pod、Deployment、PV和PVC详解</h3>
<h4>Namespace</h4>
<p>Namespace（命名空间）用于在同一个Kubernetes集群中将资源进行逻辑上的隔离。它类似于Linux中的命名空间，可以在一个集群中创建多个命名空间，每个命名空间下可以有一组独立的资源。</p>
<ul>
<li><strong>创建命名空间</strong><pre><code class="language-sh">kubectl create namespace &lt;namespace-name&gt;
</code></pre>
</li>
<li><strong>查看所有命名空间</strong><pre><code class="language-sh">kubectl get namespaces
</code></pre>
</li>
<li><strong>删除命名空间</strong><pre><code class="language-sh">kubectl delete namespace &lt;namespace-name&gt;
</code></pre>
</li>
</ul>
<p>命名空间通常用于不同环境（如开发、测试、生产）或不同项目之间的资源隔离。</p>
<h4>Pod</h4>
<p>Pod是Kubernetes中最小的部署单元，包含一个或多个容器（通常是Docker容器）。Pod中的容器共享网络和存储，并且始终在同一个Node上调度和运行。</p>
<ul>
<li><strong>创建Pod（YAML文件）</strong><pre><code class="language-yaml">apiVersion: v1
kind: Pod
metadata:
  name: my-pod
  namespace: default
spec:
  containers:
  - name: my-container
    image: nginx
</code></pre>
<pre><code class="language-sh">kubectl apply -f pod.yaml
</code></pre>
</li>
<li><strong>查看所有Pod</strong><pre><code class="language-sh">kubectl get pods
</code></pre>
</li>
<li><strong>描述Pod</strong><pre><code class="language-sh">kubectl describe pod &lt;pod-name&gt;
</code></pre>
</li>
<li><strong>删除Pod</strong><pre><code class="language-sh">kubectl delete pod &lt;pod-name&gt;
</code></pre>
</li>
</ul>
<h4>Deployment</h4>
<p>Deployment是Kubernetes中用于管理Pod的声明式定义。它可以确保集群中始终有指定数量的Pod副本在运行，并且可以实现滚动更新和回滚。</p>
<ul>
<li><strong>创建Deployment（YAML文件）</strong><pre><code class="language-yaml">apiVersion: apps/v1
kind: Deployment
metadata:
  name: my-deployment
  namespace: default
spec:
  replicas: 3
  selector:
    matchLabels:
      app: my-app
  template:
    metadata:
      labels:
        app: my-app
    spec:
      containers:
      - name: my-container
        image: nginx
</code></pre>
<pre><code class="language-sh">kubectl apply -f deployment.yaml
</code></pre>
</li>
<li><strong>查看所有Deployments</strong><pre><code class="language-sh">kubectl get deployments
</code></pre>
</li>
<li><strong>描述Deployment</strong><pre><code class="language-sh">kubectl describe deployment &lt;deployment-name&gt;
</code></pre>
</li>
<li><strong>更新Deployment</strong><pre><code class="language-sh">kubectl apply -f deployment.yaml
</code></pre>
</li>
<li><strong>删除Deployment</strong><pre><code class="language-sh">kubectl delete deployment &lt;deployment-name&gt;
</code></pre>
</li>
</ul>
<h4>PV（Persistent Volume）</h4>
<p>Persistent Volume（持久卷）是Kubernetes集群中的一块存储，可以由管理员预先配置，也可以通过动态供应器自动创建。PV是一个集群资源，与Pod独立。</p>
<ul>
<li><strong>创建PV（YAML文件）</strong><pre><code class="language-yaml">apiVersion: v1
kind: PersistentVolume
metadata:
  name: my-pv
spec:
  capacity:
    storage: 1Gi
  accessModes:
    - ReadWriteOnce
  hostPath:
    path: &quot;/mnt/data&quot;
</code></pre>
<pre><code class="language-sh">kubectl apply -f pv.yaml
</code></pre>
</li>
<li><strong>查看所有PVs</strong><pre><code class="language-sh">kubectl get pv
</code></pre>
</li>
<li><strong>描述PV</strong><pre><code class="language-sh">kubectl describe pv &lt;pv-name&gt;
</code></pre>
</li>
<li><strong>删除PV</strong><pre><code class="language-sh">kubectl delete pv &lt;pv-name&gt;
</code></pre>
</li>
</ul>
<h4>PVC（Persistent Volume Claim）</h4>
<p>Persistent Volume Claim（持久卷声明）是用户请求PV资源的方式。PVC可以请求特定大小和访问模式的存储，Kubernetes会找到满足要求的PV并将其绑定到PVC上。</p>
<ul>
<li><strong>创建PVC（YAML文件）</strong><pre><code class="language-yaml">apiVersion: v1
kind: PersistentVolumeClaim
metadata:
  name: my-pvc
spec:
  accessModes:
    - ReadWriteOnce
  resources:
    requests:
      storage: 1Gi
</code></pre>
<pre><code class="language-sh">kubectl apply -f pvc.yaml
</code></pre>
</li>
<li><strong>查看所有PVCs</strong><pre><code class="language-sh">kubectl get pvc
</code></pre>
</li>
<li><strong>描述PVC</strong><pre><code class="language-sh">kubectl describe pvc &lt;pvc-name&gt;
</code></pre>
</li>
<li><strong>删除PVC</strong><pre><code class="language-sh">kubectl delete pvc &lt;pvc-name&gt;
</code></pre>
</li>
</ul>
<h3>总结</h3>
<ul>
<li><strong>Namespace</strong>：用于逻辑上隔离资源。</li>
<li><strong>Pod</strong>：Kubernetes中最小的部署单元，包含一个或多个容器。</li>
<li><strong>Deployment</strong>：用于管理Pod的声明式定义，支持滚动更新和回滚。</li>
<li><strong>PV（Persistent Volume）</strong>：集群中的存储资源，管理员预先配置或动态供应。</li>
<li><strong>PVC（Persistent Volume Claim）</strong>：用户请求PV资源的方式。</li>
</ul>
]]></description><link>https://www.ranisa.cn/pages/kubernetes-core-concepts/</link><guid isPermaLink="true">https://www.ranisa.cn/pages/kubernetes-core-concepts/</guid><pubDate>Wed, 29 Jul 2026 00:00:00 GMT</pubDate></item><item><title><![CDATA[kubectl常用命令]]></title><description><![CDATA[<hr>
<p>title: kubectl常用命令
titleTag: 原创
date: 2022-03-29 16:46:44
permalink: /pages/17f0e7/
categories:</p>
<ul>
<li>Linux笔记</li>
<li>K8S
tags:</li>
<li>K8S</li>
<li>Kubernetes</li>
<li>容器</li>
</ul>
<hr>
<p>::: tip 版本说明
本文写于 2022-03，基于 Kubernetes 1.20 左右。&lt;br&gt;在 1.31 上的差异：<code>kubectl</code> 基础命令（<code>get</code>/<code>describe</code>/<code>apply</code>/<code>logs</code> 等）语法未变；<code>kubectl</code> 客户端与 API Server 需遵循版本偏差策略（通常客户端可比服务端新/旧 1 个小版本），建议保持 <code>kubectl</code> 版本与集群版本接近以避免个别字段兼容性问题。
:::</p>
<p>Kubernetes（K8s）是一种用于自动化部署、扩展和管理容器化应用程序的开源系统。<code>kubectl</code>是Kubernetes的命令行工具，用于与Kubernetes集群进行交互。以下是一些常用的<code>kubectl</code>命令：</p>
<h3>集群信息</h3>
<ol>
<li>
<p><strong>获取集群信息</strong></p>
<pre><code class="language-sh">kubectl cluster-info
</code></pre>
</li>
<li>
<p><strong>查看所有命名空间</strong></p>
<pre><code class="language-sh">kubectl get namespaces
</code></pre>
</li>
<li>
<p><strong>查看当前上下文</strong></p>
<pre><code class="language-sh">kubectl config current-context
</code></pre>
</li>
<li>
<p><strong>切换上下文</strong></p>
<pre><code class="language-sh">kubectl config use-context &lt;context-name&gt;
</code></pre>
</li>
</ol>
<h3>命名空间</h3>
<ol>
<li>
<p><strong>查看命名空间中的资源</strong></p>
<pre><code class="language-sh">kubectl get all -n &lt;namespace&gt;
</code></pre>
</li>
<li>
<p><strong>创建命名空间</strong></p>
<pre><code class="language-sh">kubectl create namespace &lt;namespace-name&gt;
</code></pre>
</li>
<li>
<p><strong>删除命名空间</strong></p>
<pre><code class="language-sh">kubectl delete namespace &lt;namespace-name&gt;
</code></pre>
</li>
</ol>
<h3>Pod管理</h3>
<ol>
<li>
<p><strong>查看所有Pod</strong></p>
<pre><code class="language-sh">kubectl get pods
</code></pre>
</li>
<li>
<p><strong>查看特定命名空间中的Pod</strong></p>
<pre><code class="language-sh">kubectl get pods -n &lt;namespace&gt;
</code></pre>
</li>
<li>
<p><strong>描述Pod</strong></p>
<pre><code class="language-sh">kubectl describe pod &lt;pod-name&gt;
</code></pre>
</li>
<li>
<p><strong>删除Pod</strong></p>
<pre><code class="language-sh">kubectl delete pod &lt;pod-name&gt;
</code></pre>
</li>
<li>
<p><strong>实时查看Pod日志</strong></p>
<pre><code class="language-sh">kubectl logs -f &lt;pod-name&gt;
</code></pre>
</li>
</ol>
<h3>Deployment管理</h3>
<ol>
<li>
<p><strong>查看所有Deployments</strong></p>
<pre><code class="language-sh">kubectl get deployments
</code></pre>
</li>
<li>
<p><strong>查看特定命名空间中的Deployments</strong></p>
<pre><code class="language-sh">kubectl get deployments -n &lt;namespace&gt;
</code></pre>
</li>
<li>
<p><strong>描述Deployment</strong></p>
<pre><code class="language-sh">kubectl describe deployment &lt;deployment-name&gt;
</code></pre>
</li>
<li>
<p><strong>更新Deployment</strong></p>
<pre><code class="language-sh">kubectl apply -f &lt;deployment-file&gt;.yaml
</code></pre>
</li>
<li>
<p><strong>删除Deployment</strong></p>
<pre><code class="language-sh">kubectl delete deployment &lt;deployment-name&gt;
</code></pre>
</li>
</ol>
<h3>Service管理</h3>
<ol>
<li>
<p><strong>查看所有Services</strong></p>
<pre><code class="language-sh">kubectl get services
</code></pre>
</li>
<li>
<p><strong>查看特定命名空间中的Services</strong></p>
<pre><code class="language-sh">kubectl get services -n &lt;namespace&gt;
</code></pre>
</li>
<li>
<p><strong>描述Service</strong></p>
<pre><code class="language-sh">kubectl describe service &lt;service-name&gt;
</code></pre>
</li>
<li>
<p><strong>删除Service</strong></p>
<pre><code class="language-sh">kubectl delete service &lt;service-name&gt;
</code></pre>
</li>
</ol>
<h3>ConfigMap和Secret管理</h3>
<ol>
<li>
<p><strong>查看所有ConfigMaps</strong></p>
<pre><code class="language-sh">kubectl get configmaps
</code></pre>
</li>
<li>
<p><strong>查看所有Secrets</strong></p>
<pre><code class="language-sh">kubectl get secrets
</code></pre>
</li>
<li>
<p><strong>创建ConfigMap</strong></p>
<pre><code class="language-sh">kubectl create configmap &lt;configmap-name&gt; --from-literal=&lt;key&gt;=&lt;value&gt;
</code></pre>
</li>
<li>
<p><strong>创建Secret</strong></p>
<pre><code class="language-sh">kubectl create secret generic &lt;secret-name&gt; --from-literal=&lt;key&gt;=&lt;value&gt;
</code></pre>
</li>
</ol>
<h3>其他</h3>
<ol>
<li>
<p><strong>执行命令到Pod中</strong></p>
<pre><code class="language-sh">kubectl exec -it &lt;pod-name&gt; -- &lt;command&gt;
</code></pre>
</li>
<li>
<p><strong>转发端口</strong></p>
<pre><code class="language-sh">kubectl port-forward &lt;pod-name&gt; &lt;local-port&gt;:&lt;remote-port&gt;
</code></pre>
</li>
<li>
<p><strong>获取资源的YAML定义</strong></p>
<pre><code class="language-sh">kubectl get &lt;resource-type&gt; &lt;resource-name&gt; -o yaml
</code></pre>
</li>
<li>
<p><strong>编辑资源</strong></p>
<pre><code class="language-sh">kubectl edit &lt;resource-type&gt; &lt;resource-name&gt;
</code></pre>
</li>
</ol>
]]></description><link>https://www.ranisa.cn/pages/17f0e7/</link><guid isPermaLink="true">https://www.ranisa.cn/pages/17f0e7/</guid><pubDate>Wed, 29 Jul 2026 00:00:00 GMT</pubDate></item><item><title><![CDATA[Kubernetes之yaml文件详解]]></title><description><![CDATA[<hr>
<p>title: Kubernetes之yaml文件详解
date: 2022-03-29 16:46:44
permalink: /pages/d96450/
categories:</p>
<ul>
<li>Linux笔记</li>
<li>K8S
tags:</li>
<li>K8S</li>
<li>Kubernetes</li>
<li>容器</li>
</ul>
<hr>
<p>::: tip 版本说明
本文写于 2022-03，基于 Kubernetes 1.20 左右。&lt;br&gt;在 1.31 上的差异：本文若涉及 <code>PodSecurityPolicy</code>（<code>policy/v1beta1</code>），该资源已在 1.21 弃用、1.25 彻底移除，需改用 Pod Security Admission（命名空间级 <code>pod-security.kubernetes.io</code> 标签）；<code>Ingress</code> 资源自 1.22 起仅支持 <code>networking.k8s.io/v1</code>（不再支持 <code>extensions/v1beta1</code>/<code>networking.k8s.io/v1beta1</code>），使用时请核对 <code>apiVersion</code> 是否已更新；<code>Deployment</code>/<code>Service</code>/<code>ConfigMap</code> 等基础资源的 YAML 结构未变。
:::</p>
<p>Kubernetes的YAML文件是用于定义Kubernetes对象（如Pod、Service、Deployment等）的一种格式化文件。这些文件通常由开发人员和运维人员使用，并通过kubectl工具进行部署和管理。</p>
<p>以下是一个基本的Kubernetes YAML文件的示例：</p>
<pre><code class="language-yaml">apiVersion: v1
kind: Pod
metadata:
  name: my-pod
  labels:
    app: my-app
spec:
  containers:
    - name: my-container
      image: nginx:latest

</code></pre>
<p>Kubernetes YAML文件的主要结构由以下几个部分组成：</p>
<ul>
<li>
<p>apiVersion：用于指定该对象的Kubernetes API版本。该版本必须与所使用的Kubernetes版本兼容。</p>
</li>
<li>
<p>kind：用于指定该对象的类型。常见的类型有Pod、Service、Deployment、ConfigMap、Secret等。</p>
</li>
<li>
<p>metadata：用于指定该对象的元数据，包括名称、标签、注释等信息。</p>
</li>
<li>
<p>spec：用于指定该对象的规范，包括容器、服务端口、存储卷等配置信息。</p>
</li>
</ul>
<p>在一个Kubernetes YAML文件中，可以定义多个Kubernetes对象，每个对象之间用 --- 分隔开来。例如：</p>
<pre><code class="language-yaml">
apiVersion: v1
kind: Pod
metadata:
  name: my-pod
  labels:
    app: my-app
spec:
  containers:
    - name: my-container
      image: nginx:latest

---
apiVersion: v1
kind: Service
metadata:
  name: my-service
spec:
  selector:
    app: my-app
  ports:
    - name: http
      port: 80
      targetPort: 80

</code></pre>
<p>在上面的示例中，定义了一个Pod和一个Service对象。</p>
<p>Kubernetes YAML文件的定义格式是相对灵活的，开发人员和运维人员可以根据需要灵活定义和组织它们。在定义时，可以使用一些基本的Kubernetes YAML文件的语法和结构元素，例如注释、缩进、序列和映射等。</p>
<p>总的来说，Kubernetes YAML文件是定义Kubernetes对象的一种简单但强大的方式。熟练掌握Kubernetes YAML文件的语法和结构可以更好地帮助开发人员和运维人员管理和部署Kubernetes对象。</p>
<p>除了上述基本结构外，Kubernetes YAML文件还支持许多其他功能和特性。下面列举了一些常用的Kubernetes YAML文件的功能和技巧：</p>
<ul>
<li>注释：使用 # 符号来添加注释。注释可以添加在任何位置，以提高代码的可读性。</li>
</ul>
<pre><code class="language-yaml">apiVersion: v1
kind: Pod
metadata:
  name: my-pod  # 定义Pod名称
spec:
  containers:
    - name: my-container  # 定义容器名称
      image: nginx:latest  # 定义容器镜像

</code></pre>
<ul>
<li>多行字符串：使用 | 符号来定义多行字符串。这在定义大块的配置文件时非常有用。</li>
</ul>
<pre><code class="language-yaml">apiVersion: v1
kind: ConfigMap
metadata:
  name: my-config
data:
  my-conf.yaml: |
    key1: value1
    key2: value2
    key3: value3

</code></pre>
<ul>
<li>环境变量：可以通过 env 属性来定义容器的环境变量。</li>
</ul>
<pre><code class="language-yaml">apiVersion: v1
kind: Pod
metadata:
  name: my-pod
spec:
  containers:
    - name: my-container
      image: nginx:latest
      env:
        - name: ENV_VAR1
          value: &quot;value1&quot;
        - name: ENV_VAR2
          value: &quot;value2&quot;
</code></pre>
<ul>
<li>存储卷：可以使用 volumes 属性来定义Pod中的存储卷。</li>
</ul>
<pre><code class="language-yaml">
apiVersion: v1
kind: Pod
metadata:
  name: my-pod
spec:
  containers:
    - name: my-container
      image: nginx:latest
      volumeMounts:
        - name: my-volume
          mountPath: /data
  volumes:
    - name: my-volume
      configMap:
        name: my-config

</code></pre>
<ul>
<li>配置文件：可以使用 configMap 和 secret 属性来定义Pod中的配置文件。</li>
</ul>
<pre><code class="language-yaml">apiVersion: v1
kind: Pod
metadata:
  name: my-pod
spec:
  containers:
    - name: my-container
      image: nginx:latest
      volumeMounts:
        - name: my-config
          mountPath: /etc/my-app
      env:
        - name: ENV_VAR1
          valueFrom:
            configMapKeyRef:
              name: my-config
              key: env-var1
        - name: ENV_VAR2
          valueFrom:
            secretKeyRef:
              name: my-secret
              key: env-var2
  volumes:
    - name: my-config
      configMap:
        name: my-config
    - name: my-secret
      secret:
        name: my-secret

</code></pre>
<ul>
<li>部署：可以使用 Deployment 对象来定义Pod的部署和升级策略。</li>
</ul>
<pre><code class="language-yaml">apiVersion: apps/v1
kind: Deployment
metadata:
  name: my-deploy
spec:
  replicas: 3
  selector:
    matchLabels:
      app: my-app
  template:
    metadata:
      labels:
        app: my-app
    spec:
      containers:
        - name: my-container
          image: nginx:latest

</code></pre>
]]></description><link>https://www.ranisa.cn/pages/d96450/</link><guid isPermaLink="true">https://www.ranisa.cn/pages/d96450/</guid><pubDate>Wed, 29 Jul 2026 00:00:00 GMT</pubDate></item><item><title><![CDATA[Kubernetes (k8s) 相关名词详解]]></title><description><![CDATA[<hr>
<p>title: Kubernetes (k8s) 相关名词详解
date: 2024-06-27 10:30:00
titleTag: 原创
permalink: /pages/k8s-terms/
categories:</p>
<ul>
<li>Linux笔记</li>
<li>K8S
tags:</li>
<li>Kubernetes</li>
<li>云原生</li>
<li>容器编排</li>
</ul>
<hr>
<p>了解Kubernetes（简称k8s）相关的名词有助于更好地使用和管理Kubernetes集群。以下是一些常见的Kubernetes相关名词及其详细介绍：</p>
<h3>1. Pod</h3>
<p>Pod 是 Kubernetes 中最小的部署单元，一个 Pod 可以包含一个或多个容器，这些容器共享网络和存储资源。Pod 通常用于运行一个应用程序的一个实例。</p>
<h3>2. Node</h3>
<p>Node 是 Kubernetes 集群中的一台服务器，可以是物理机也可以是虚拟机。每个 Node 上运行一个 kubelet 服务，负责与 Kubernetes API server 通信，并管理该 Node 上的 Pod。</p>
<h3>3. Cluster</h3>
<p>Cluster 是一组 Node 的集合，通过 Kubernetes API 进行统一管理。集群可以在本地数据中心或云环境中部署。</p>
<h3>4. Namespace</h3>
<p>Namespace 是 Kubernetes 中的一个逻辑隔离单位，用于将集群中的资源划分为不同的组。不同的 Namespace 之间的资源默认是隔离的，但可以通过某些配置进行跨 Namespace 访问。</p>
<h3>5. Deployment</h3>
<p>Deployment 是 Kubernetes 中用于声明应用的生命周期管理的资源。通过 Deployment，可以定义 Pod 的副本数、更新策略等，Kubernetes 会自动管理这些 Pod 的创建、删除和更新。</p>
<h3>6. Service</h3>
<p>Service 是 Kubernetes 中用于定义一组 Pod 的网络访问策略。Service 提供了一个稳定的 IP 地址和 DNS 名称，用于访问与其关联的 Pod。</p>
<h3>7. ConfigMap</h3>
<p>ConfigMap 用于在 Kubernetes 中存储非机密的配置数据，以键值对的形式存储。Pod 可以将 ConfigMap 中的数据挂载为环境变量或配置文件。</p>
<h3>8. Secret</h3>
<p>Secret 与 ConfigMap 类似，但用于存储敏感信息，如密码、OAuth 令牌等。Secret 中的数据会被 Base64 编码，并以更高的安全级别进行保护。</p>
<h3>9. Volume</h3>
<p>Volume 是 Kubernetes 中用于持久化数据存储的抽象。Pod 中的容器可以共享 Volume，Volume 的生命周期与 Pod 一致，但 Kubernetes 提供了多种持久化存储解决方案，如 PersistentVolume。</p>
<h3>10. PersistentVolume (PV) 和 PersistentVolumeClaim (PVC)</h3>
<p>PersistentVolume (PV) 是集群级别的存储资源，管理员预先配置。PersistentVolumeClaim (PVC) 是用户对 PV 的请求，类似于 Pod 对 Node 的请求。</p>
<h3>11. Ingress</h3>
<p>Ingress 是 Kubernetes 中的一种 API 对象，用于管理外部访问服务的规则。通过 Ingress，可以配置 HTTP 和 HTTPS 路由，并提供负载均衡、SSL 终端等功能。</p>
<h3>12. StatefulSet</h3>
<p>StatefulSet 是一种用于管理有状态应用的控制器，保证 Pod 的唯一性和顺序性，常用于数据库或其他有状态服务的部署。</p>
<h3>13. DaemonSet</h3>
<p>DaemonSet 确保集群中的每个 Node 都运行一个 Pod 副本，常用于日志收集、监控代理等系统服务。</p>
<h3>14. Job 和 CronJob</h3>
<p>Job 是 Kubernetes 中用于一次性任务的资源，确保任务的完成。CronJob 是基于时间调度的 Job，可以定时执行任务。</p>
<h3>15. kube-apiserver</h3>
<p>kube-apiserver 是 Kubernetes 控制平面的组件，负责处理 API 请求，并与集群中其他组件通信。</p>
<h3>16. kube-controller-manager</h3>
<p>kube-controller-manager 运行控制器进程，负责集群中的常规任务，如副本控制、节点控制、端点控制等。</p>
<h3>17. kube-scheduler</h3>
<p>kube-scheduler 负责将 Pod 调度到适合的 Node 上，考虑资源需求、策略和约束。</p>
<h3>18. etcd</h3>
<p>etcd 是 Kubernetes 的分布式键值存储，保存了集群的所有状态信息。</p>
<h3>19. kubelet</h3>
<p>kubelet 是运行在每个 Node 上的代理，负责管理该 Node 上的容器，确保它们按照 Pod 规范运行。</p>
<h3>20. kubectl</h3>
<p>kubectl 是 Kubernetes 的命令行工具，用于与 Kubernetes 集群交互，执行各种管理任务。</p>
]]></description><link>https://www.ranisa.cn/pages/k8s-terms/</link><guid isPermaLink="true">https://www.ranisa.cn/pages/k8s-terms/</guid><pubDate>Wed, 29 Jul 2026 00:00:00 GMT</pubDate></item><item><title><![CDATA[PV、PVC、StorageClass的区别和联系]]></title><description><![CDATA[<hr>
<p>title: PV、PVC、StorageClass的区别和联系
date: 2025-03-30 15:12:32
titleTag: 原创
permalink: /pages/pvc-storageclass-diff/
categories:</p>
<ul>
<li>Linux笔记</li>
<li>K8S
tags:</li>
<li>PV</li>
<li>PVC</li>
<li>StorageClass</li>
</ul>
<hr>
<p>在 Kubernetes 中，持久化存储是一个重要的概念，它通过 PersistentVolume (PV)、PersistentVolumeClaim (PVC) 和 StorageClass 来实现。下面我们详细介绍它们的区别和联系。</p>
<h3>1. PersistentVolume (PV)</h3>
<p><strong>定义</strong>:
PersistentVolume 是 Kubernetes 中的一种资源对象，它表示集群中的一个存储卷。PV 是由管理员预先创建的，或者通过 StorageClass 动态创建的。</p>
<p><strong>特点</strong>:</p>
<ul>
<li>PV 是集群范围的资源。</li>
<li>PV 的生命周期独立于 Pod。</li>
<li>PV 定义了存储的容量、访问模式、回收策略等。</li>
</ul>
<p><strong>示例</strong>:</p>
<pre><code class="language-yaml">apiVersion: v1
kind: PersistentVolume
metadata:
  name: example-pv
spec:
  capacity:
    storage: 5Gi
  accessModes:
    - ReadWriteOnce
  persistentVolumeReclaimPolicy: Retain
  storageClassName: standard
  hostPath:
    path: /mnt/data
</code></pre>
<h3>2. PersistentVolumeClaim (PVC)</h3>
<p><strong>定义</strong>:
PersistentVolumeClaim 是 Kubernetes 中的一种资源对象，它表示用户对存储的申请。PVC 用于绑定到 PV，并为 Pod 提供存储。</p>
<p><strong>特点</strong>:</p>
<ul>
<li>PVC 是用户的存储需求声明。</li>
<li>PVC 会自动绑定到符合条件的 PV。</li>
<li>PVC 通过 <code>accessModes</code> 和 <code>storageClassName</code> 来匹配 PV。</li>
</ul>
<p><strong>示例</strong>:</p>
<pre><code class="language-yaml">apiVersion: v1
kind: PersistentVolumeClaim
metadata:
  name: example-pvc
spec:
  accessModes:
    - ReadWriteOnce
  resources:
    requests:
      storage: 5Gi
  storageClassName: standard
</code></pre>
<h3>3. StorageClass</h3>
<p><strong>定义</strong>:
StorageClass 是 Kubernetes 中的一种资源对象，它定义了存储卷的动态配置方式。通过 StorageClass，可以动态地创建 PV，而无需管理员手动创建。</p>
<p><strong>特点</strong>:</p>
<ul>
<li>StorageClass 定义了存储的提供方式。</li>
<li>StorageClass 可以指定不同的存储类型（如 NFS、Ceph、AWS EBS 等）。</li>
<li>StorageClass 可以设置 <code>provisioner</code> 和 <code>parameters</code> 来配置存储。</li>
</ul>
<p><strong>示例</strong>:</p>
<pre><code class="language-yaml">apiVersion: storage.k8s.io/v1
kind: StorageClass
metadata:
  name: standard
provisioner: kubernetes.io/aws-ebs
parameters:
  type: gp2
</code></pre>
<h3>4. 区别</h3>
<table>
<thead>
<tr>
<th><strong>资源对象</strong></th>
<th><strong>定义</strong></th>
<th><strong>作用</strong></th>
</tr>
</thead>
<tbody>
<tr>
<td>PersistentVolume (PV)</td>
<td>表示集群中的存储卷</td>
<td>由管理员或 StorageClass 创建，用于存储数据</td>
</tr>
<tr>
<td>PersistentVolumeClaim (PVC)</td>
<td>用户的存储需求声明</td>
<td>用户通过 PVC 申请存储，并绑定到 PV</td>
</tr>
<tr>
<td>StorageClass</td>
<td>动态配置存储卷的方式</td>
<td>定义存储卷的类型和配置，用于动态创建 PV</td>
</tr>
</tbody>
</table>
<h3>5. 联系</h3>
<ol>
<li>
<p><strong>PV 与 PVC 的联系</strong>:</p>
<ul>
<li>PVC 是用户的存储需求声明，PV 是存储的实际实现。</li>
<li>PVC 会自动绑定到符合条件的 PV。</li>
</ul>
</li>
<li>
<p><strong>StorageClass 与 PV 的联系</strong>:</p>
<ul>
<li>StorageClass 定义了动态创建 PV 的方式。</li>
<li>如果使用 StorageClass，PV 会根据 StorageClass 的配置动态生成。</li>
</ul>
</li>
<li>
<p><strong>StorageClass 与 PVC 的联系</strong>:</p>
<ul>
<li>PVC 可以通过 <code>storageClassName</code> 字段指定使用哪个 StorageClass。</li>
<li>PVC 的 <code>storageClassName</code> 决定了绑定的 PV 的类型。</li>
</ul>
</li>
</ol>
<h3>6. 使用场景</h3>
<ul>
<li>
<p><strong>静态存储</strong>:
如果集群管理员已经预先创建了 PV，用户可以通过 PVC 绑定到这些 PV。</p>
</li>
<li>
<p><strong>动态存储</strong>:
如果使用了 StorageClass，用户可以通过 PVC 动态创建 PV，而无需管理员手动干预。</p>
</li>
</ul>
<h3>7. 示例流程</h3>
<p>以下是一个使用 StorageClass 动态创建 PV 的完整流程：</p>
<ol>
<li>创建 StorageClass:</li>
</ol>
<pre><code class="language-yaml">apiVersion: storage.k8s.io/v1
kind: StorageClass
metadata:
  name: fast-storage
provisioner: kubernetes.io/aws-ebs
parameters:
  type: io1
  iopsPerGB: &quot;10&quot;
  fsType: ext4
</code></pre>
<ol start="2">
<li>创建 PVC:</li>
</ol>
<pre><code class="language-yaml">apiVersion: v1
kind: PersistentVolumeClaim
metadata:
  name: fast-pvc
spec:
  accessModes:
    - ReadWriteOnce
  resources:
    requests:
      storage: 10Gi
  storageClassName: fast-storage
</code></pre>
<ol start="3">
<li>检查自动创建的 PV:</li>
</ol>
<pre><code class="language-bash">$ kubectl get pv
</code></pre>
<p>通过以上流程，PVC 会自动绑定到由 StorageClass 动态创建的 PV。</p>
<h3>总结</h3>
<ul>
<li>PV 是存储的实际实现。</li>
<li>PVC 是用户的存储需求声明。</li>
<li>StorageClass 提供了动态创建 PV 的方式。</li>
<li>三者共同构成了 Kubernetes 中的持久化存储体系。</li>
</ul>
]]></description><link>https://www.ranisa.cn/pages/pvc-storageclass-diff/</link><guid isPermaLink="true">https://www.ranisa.cn/pages/pvc-storageclass-diff/</guid><pubDate>Wed, 29 Jul 2026 00:00:00 GMT</pubDate></item><item><title><![CDATA[Nginx 运维知识地图：从配置基础到反向代理实战]]></title><description><![CDATA[<hr>
<p>title: Nginx 运维知识地图：从配置基础到反向代理实战
titleTag: 原创
date: 2026-07-29 21:00:00
permalink: /pages/nginx-guide/
categories:</p>
<ul>
<li>Linux笔记</li>
<li>Nginx
tags:</li>
<li>Nginx</li>
<li>Web服务器</li>
</ul>
<hr>
<p>Nginx 分类下 17 篇文章覆盖配置基础、反向代理、认证安全、限流日志、运维排障五个方向。这一页按实际使用场景重新组织成阅读路径。</p>
<h2>1. 配置基础</h2>
<table>
<thead>
<tr>
<th>主题</th>
<th>文章</th>
<th>说明</th>
</tr>
</thead>
<tbody>
<tr>
<td>配置文件与模块</td>
<td><a href="/pages/1153.html">nginx 配置文件及模块</a></td>
<td>主配置结构与常用模块速查</td>
</tr>
<tr>
<td>状态码</td>
<td><a href="/pages/1239.html">http 状态码详解</a></td>
<td>常见状态码含义与排查方向</td>
</tr>
<tr>
<td>gzip 压缩</td>
<td><a href="/pages/5228.html">nginx 配置 gzip 压缩</a></td>
<td>压缩配置与效果验证</td>
</tr>
<tr>
<td>端口复用</td>
<td><a href="/pages/nginx-reuser-port/">Nginx 的端口复用：提升服务器并发能力</a></td>
<td><code>SO_REUSEPORT</code> 的作用与配置</td>
</tr>
</tbody>
</table>
<h2>2. 反向代理与网关</h2>
<table>
<thead>
<tr>
<th>主题</th>
<th>文章</th>
<th>说明</th>
</tr>
</thead>
<tbody>
<tr>
<td>SFTP 下载服务</td>
<td><a href="/pages/1086.html">利用 nginx+sftp 实现一个可供用户下载的服务</a></td>
<td>静态文件下载服务的搭建</td>
</tr>
<tr>
<td>四层代理</td>
<td><a href="/pages/1197.html">nginx 通过四层代理实现端口转发</a></td>
<td><code>stream</code> 模块的 TCP/UDP 转发</td>
</tr>
<tr>
<td>Cookie 分流</td>
<td><a href="/pages/3103.html">NGINX 基于 cookie 针对同一域名进行分流转发</a></td>
<td>灰度发布/AB 测试的路由方案</td>
</tr>
<tr>
<td>流量复制</td>
<td><a href="/pages/3367.html">利用 NGINX 内置模块 mirror 进行流量复制等操作</a></td>
<td>mirror 模块做流量镜像</td>
</tr>
<tr>
<td>PHP 集群代理</td>
<td><a href="/pages/5352.html">由 Nginx 集中代理分散的 PHP 集群的实践</a></td>
<td>多后端 PHP 服务的统一入口</td>
</tr>
</tbody>
</table>
<h2>3. 认证与安全</h2>
<table>
<thead>
<tr>
<th>主题</th>
<th>文章</th>
<th>说明</th>
</tr>
</thead>
<tbody>
<tr>
<td>三档认证方案</td>
<td><a href="/pages/8531e6/">Nginx 给内部服务加认证：Basic Auth / LDAP / OIDC 三档怎么选</a></td>
<td>按团队规模选认证方案</td>
</tr>
<tr>
<td>OpenResty LDAP</td>
<td><a href="/pages/5019.html">OpenResty-1-13-6-2-新增 ldap 模块儿</a></td>
<td>OpenResty 原生 LDAP 支持</td>
</tr>
<tr>
<td>小程序校验</td>
<td><a href="/pages/5226.html">nginx 配置微信小程序校验及其他</a></td>
<td>域名归属校验相关配置</td>
</tr>
</tbody>
</table>
<h2>4. 限流与日志</h2>
<table>
<thead>
<tr>
<th>主题</th>
<th>文章</th>
<th>说明</th>
</tr>
</thead>
<tbody>
<tr>
<td>限速限流</td>
<td><a href="/pages/3133.html">nginx 利用内置模块配置限速限流</a></td>
<td><code>limit_req</code>/<code>limit_conn</code> 实战</td>
</tr>
<tr>
<td>用户字段记录</td>
<td><a href="/pages/3426.html">使用 $remote_user 字段记录访问 NGINX 的用户</a></td>
<td>访问日志里记录认证用户</td>
</tr>
<tr>
<td>日志切割</td>
<td><a href="/pages/3537.html">Nginx 日志切割两种方案对比：外部脚本 vs 配置文件原生切割</a></td>
<td>两种切割方案的取舍</td>
</tr>
</tbody>
</table>
<h2>5. 运维排障</h2>
<table>
<thead>
<tr>
<th>主题</th>
<th>文章</th>
<th>说明</th>
</tr>
</thead>
<tbody>
<tr>
<td>open_file_cache 404</td>
<td><a href="/pages/afe439/">排查 NGINX 的 open_file_cache 导致发布后访问 404 的问题</a></td>
<td>缓存导致的发布后异常排查</td>
</tr>
<tr>
<td>制作 RPM 包</td>
<td><a href="/pages/296104/">制作 OpenResty-1-19-9-1 的 RPM 包</a></td>
<td>自定义构建与打包流程</td>
</tr>
<tr>
<td>Proxy Manager</td>
<td><a href="/pages/fa7afa/">Nginx Proxy Manager 使用笔记</a></td>
<td>图形化反代管理工具的用法</td>
</tr>
</tbody>
</table>
<h2>怎么用这份地图</h2>
<ul>
<li><strong>刚接触 Nginx</strong>：第 1 节打基础，配置文件结构和 gzip/端口复用是最高频的日常配置项。</li>
<li><strong>要做反向代理网关</strong>：第 2 节按需选型，四层代理和 mirror 流量复制是进阶场景，先确认业务是否真的需要。</li>
<li><strong>要给内部服务加访问控制</strong>：直接看第 3 节的三档认证方案，按团队规模选，不要一上来就上 LDAP/OIDC。</li>
<li><strong>线上访问异常</strong>：第 5 节，<code>open_file_cache</code> 导致的发布后 404 是最容易被忽略的一类坑。</li>
</ul>
]]></description><link>https://www.ranisa.cn/pages/nginx-guide/</link><guid isPermaLink="true">https://www.ranisa.cn/pages/nginx-guide/</guid><pubDate>Wed, 29 Jul 2026 00:00:00 GMT</pubDate></item><item><title><![CDATA[Nginx 给内部服务加认证：Basic Auth / LDAP / OIDC 三档怎么选]]></title><description><![CDATA[<hr>
<p>title: Nginx 给内部服务加认证：Basic Auth / LDAP / OIDC 三档怎么选
date: 2022-03-10 02:52:51
permalink: /pages/8531e6/
categories:</p>
<ul>
<li>Linux笔记</li>
<li>Nginx
tags:</li>
<li>Nginx</li>
<li>Web服务器</li>
</ul>
<hr>
<p>::: tip 版本说明
Basic Auth 是 Nginx 内置模块，任意版本可用；<code>nginx-ldap-auth</code> 与 OIDC 反代方案需要额外组件，版本要求见对应小节。
:::</p>
<p>给一个内部服务（监控面板、管理后台）加访问控制，常见诉求是&quot;不想让服务本身实现登录逻辑，交给反向代理层统一挡一道&quot;。Nginx 层面能做到的方案有三档，复杂度和适用场景依次递进：</p>
<h2>1. 档位一：HTTP Basic Auth（最简单，几分钟搞定）</h2>
<p><strong>生成密码文件</strong>：</p>
<pre><code class="language-shell">printf &quot;admin:$(openssl passwd -apr1)&quot; &gt; /etc/nginx/conf.d/htpasswd
# 命令会提示交互式输入密码
</code></pre>
<p><code>openssl passwd -apr1</code> 生成 Apache MD5 变体的密码哈希，Nginx 的 <code>auth_basic_user_file</code> 兼容这种格式；<code>admin</code> 换成你要用的用户名，文件里每行一个&quot;用户名:密码哈希&quot;。</p>
<p><strong>配置 Nginx</strong>：</p>
<pre><code class="language-nginx">location /internal-monitor/ {
    auth_basic &quot;Restricted Access&quot;;
    auth_basic_user_file /etc/nginx/conf.d/htpasswd;
    proxy_set_header Host $host;
    proxy_set_header X-Real-IP $remote_addr;
    proxy_set_header X-Forwarded-For $remote_addr;
    proxy_pass http://backend:19999/;
}
</code></pre>
<p><code>auth_basic</code> 的字符串会显示在浏览器弹出的登录框标题上，<code>auth_basic_user_file</code> 指向刚才生成的密码文件。</p>
<p><strong>验证</strong>：访问该路径应弹出浏览器原生认证框；<code>curl -u admin:密码 http://host/internal-monitor/</code> 能正常拿到响应，不带认证信息则返回 <code>401</code>。</p>
<p><strong>坑</strong>：Basic Auth 是明文（Base64 编码不是加密）在 HTTP 头里传输密码，<strong>必须配合 HTTPS 使用</strong>，纯 HTTP 下等于裸奔；而且它是&quot;一份密码文件对应若干共享账号&quot;，没有细粒度的用户管理、审计日志、密码策略，只适合团队规模小、临时挡一道的场景。</p>
<h2>2. 档位二：LDAP 认证（对接企业统一账号）</h2>
<p>团队规模大了之后，共享密码文件很快就管不过来——离职要删账号、新人要开账号，Basic Auth 的密码文件没有任何自动化空间。这时候把认证对接到企业已有的 LDAP/AD 账号体系更合理：让员工用平时登录邮箱/OA 的同一套账号访问内部服务，权限统一由 LDAP 侧管理。</p>
<p>Nginx 原生不支持 LDAP，需要借助 <code>nginx-ldap-auth</code> 这类第三方认证子请求模块（<code>auth_request</code> 指令 + 一个独立的 LDAP 认证代理进程）：</p>
<pre><code class="language-nginx">location /internal-monitor/ {
    auth_request /auth-proxy;
    error_page 401 = @error401;
    proxy_pass http://backend:19999/;
}

location = /auth-proxy {
    internal;
    proxy_pass http://ldap-auth-daemon:8888;
    proxy_set_header Content-Length &quot;&quot;;
    proxy_pass_request_body off;
}

location @error401 {
    return 302 /login;
}
</code></pre>
<p><code>auth_request</code> 指令会先向 <code>/auth-proxy</code> 发一个子请求，只关心它返回的状态码——<code>2xx</code> 放行原请求，<code>401</code>/<code>403</code> 则按 <code>error_page</code> 的配置处理（通常跳转到登录页）。真正跟 LDAP 服务器交互（BIND 认证）的逻辑在 <code>ldap-auth-daemon</code> 这个独立进程里完成，Nginx 本身不直接说 LDAP 协议。</p>
<p><strong>坑</strong>：<code>auth_request</code> 子请求走的是<strong>独立的一次 HTTP 请求</strong>，不会自动带上原请求的 body，<code>proxy_pass_request_body off</code> + 清空 <code>Content-Length</code> 是标准写法，忘记这两行可能导致认证代理收到异常请求。</p>
<h2>3. 档位三：OIDC/SSO（统一单点登录，最重的方案）</h2>
<p>组织内已经有统一身份提供商（如 Okta、Keycloak、企业自建 IdP）时，最终形态是把 Nginx 前面的所有内部服务都接入同一个 OIDC 单点登录，用户登录一次，所有内部服务免登录跳转。这一档通常不是纯 Nginx 配置能搞定的，而是引入专门的反向代理网关（如 <code>oauth2-proxy</code>）：</p>
<pre><code class="language-nginx">location /internal-monitor/ {
    auth_request /oauth2/auth;
    error_page 401 = /oauth2/sign_in;
    proxy_pass http://backend:19999/;
}

location /oauth2/ {
    proxy_pass http://oauth2-proxy:4180;
}
</code></pre>
<p><code>oauth2-proxy</code> 独立部署，负责跟 OIDC IdP 完成标准的 OAuth2/OIDC 授权码流程，Nginx 这一层依然是熟悉的 <code>auth_request</code> 套路，只是认证代理换成了理解 OIDC 协议的组件。</p>
<p><strong>适用场景</strong>：需要统一审计、多因素认证（MFA）、跟公司现有 SSO 体系集成时选这一档；小团队、单一内部服务没有必要上这一整套。</p>
<h2>4. 三档怎么选</h2>
<table>
<thead>
<tr>
<th></th>
<th>Basic Auth</th>
<th>LDAP</th>
<th>OIDC/SSO</th>
</tr>
</thead>
<tbody>
<tr>
<td>搭建复杂度</td>
<td>一条命令+几行配置</td>
<td>需要额外部署认证代理进程</td>
<td>需要独立网关组件+对接 IdP</td>
</tr>
<tr>
<td>账号管理</td>
<td>手动维护密码文件</td>
<td>复用企业已有目录</td>
<td>复用企业已有 IdP</td>
</tr>
<tr>
<td>适合场景</td>
<td>临时/小团队挡一道</td>
<td>团队有 LDAP/AD</td>
<td>组织级统一 SSO</td>
</tr>
<tr>
<td>前提要求</td>
<td>必须配 HTTPS</td>
<td>需要可访问的 LDAP 服务</td>
<td>需要 OIDC IdP</td>
</tr>
</tbody>
</table>
<h2>5. 可复用要点</h2>
<ol>
<li>认证方案的复杂度应该匹配团队规模和已有基础设施，不要为一个内部小工具直接上 SSO。</li>
<li>Basic Auth 必须搭配 HTTPS，否则密码等于明文传输。</li>
<li>LDAP/OIDC 这两档在 Nginx 层的共同套路都是 <code>auth_request</code> 子请求 + 独立认证代理进程，Nginx 本身不直接实现认证协议。</li>
</ol>
]]></description><link>https://www.ranisa.cn/pages/8531e6/</link><guid isPermaLink="true">https://www.ranisa.cn/pages/8531e6/</guid><pubDate>Wed, 29 Jul 2026 00:00:00 GMT</pubDate></item><item><title><![CDATA[利用nginx+sftp实现一个可供用户下载的服务]]></title><description><![CDATA[<hr>
<p>title: 利用nginx+sftp实现一个可供用户下载的服务
titleTag: 收藏(二丫讲梵)备查
date: 2018-06-18 22:36:32
permalink: /pages/1086.html
categories:</p>
<ul>
<li>Linux笔记</li>
<li>Nginx
tags:</li>
<li>nginx</li>
<li>ftp</li>
</ul>
<hr>
<p>::: tip 版本说明
本文写于 2018-06，基于 Nginx 1.14 左右版本。&lt;br&gt;SFTP/Nginx 静态文件服务的核心配置项（<code>autoindex</code>、<code>root</code>/<code>alias</code>）历年未变，经 2026-07 复核仍适用。
:::</p>
<p>公司服务端开发小伙伴来提需求啦，好像还很紧急的样子。宁静的日子也就这样被打破。据他描述，需求大概是：做一个可以咱们自己自由上传，而用户那边通过一个链接就可以下载 app 的服务。</p>
<p>经过讨论：想实现这个，一共有两部分，首先是本地将文件上传，其次是普通用户下载。</p>
<p>上传就用 sftp 了。</p>
<p>从技术角度来分析，几个要求：</p>
<ul>
<li>1、从安全方面看，sftp 会更安全一点。</li>
<li>2、线上服务器提供在线服务，对用户需要控制，只能让用户在自己的 home 目录下活动。</li>
<li>3、用户只能使用 sftp，不能 ssh 到机器进行操作。</li>
</ul>
<p>提供 sftp 服务，可以用系统自带的 internal-sftp，也可以使用 vsftpd，这里需求不多，直接选用<code>internal-sftp</code>。</p>
<p><code>限制用户</code>只能在自己的 home 目录下活动，这里需要使用到<code>chroot</code>，openssh 4.8p1 以后都支持 chroot，我现在用的是 CentOS 6.3，自带的 openssh 已经是 5.3p1，足够了。</p>
<pre><code class="language-sh">ssh -V     
 
#查看openssh的版本，如果低于4.8p1，需要自行升级安装，不在这里具体介绍了。
</code></pre>
<p>假设，有一个名为<code>test</code>的组，这个组中的用户<code>只能使用sftp</code>，<code>不能使用ssh</code>，且 sftp 登录后只能在自己的 home 目录下活动。</p>
<p><img src="/img/inline/sftp-download-service.jpg" alt="img"></p>
<h2>1、创建 sftp 组</h2>
<pre><code class="language-sh">groupadd test
</code></pre>
<h2>2、创建一个 sftp 用户，名为 <code>erya</code>。</h2>
<p>（原来的教程是创建了一个系统用户，不能登陆，现在可以创建一个普通用户，然后通过秘钥进行登陆）</p>
<pre><code class="language-sh">useradd -g test erya
passwd erya
</code></pre>
<h2>3、创建目录并分配权限。</h2>
<p>test 组的用户的 home 目录统一指定到 / data/sftp 下，按用户名区分，这里先新建一个 erya 目录，然后指定 erya 的 home 为 / data/sftp/erya</p>
<pre><code class="language-sh">mkdir -p /data/sftp/erya
usermod -d /data/sftp/erya erya
</code></pre>
<h2>4、配置 sshd_config。</h2>
<p>编辑 ssh 配置文件 / etc/ssh/sshd_config。</p>
<h3>1，注释如下行。</h3>
<pre><code class="language-sh"> vim  /etc/ssh/sshd_config  
 
Subsystem      sftp    /usr/libexec/openssh/sftp-server      
#注释此行
</code></pre>
<h3>2，添加如下几行。</h3>
<pre><code class="language-sh">Subsystem       sftp    internal-sftp  
#这行指定使用sftp服务使用系统自带的internal-sftp
 
Match Group sftp  
#这行用来匹配sftp组的用户，如果要匹配多个组，多个组之间用逗号分割
 
当然，也可以匹配用户
Match User mysftp
#这样就可以匹配用户了，多个用户名之间也是用逗号分割，但我们这里按组匹配更灵活和方便
 
ChrootDirectory /data/sftp/%u  
#用chroot将用户的根目录指定到/data/sftp/%u，%u代表用户名，这样用户就只能在/data/sftp/%u下活动，chroot的含义，可以参考这里：http://www.ibm.com/developerworks/cn/linux/l-cn-chroot/
 
ForceCommand    internal-sftp  
#指定sftp命令
 
AllowTcpForwarding no  
X11Forwarding no  
#这两行，如果不希望该用户能使用端口转发的话就加上，否则删掉
</code></pre>
<p><code>注意：里边的注释是为了帮助理解，实际使用中可以去掉。</code></p>
<h2>5、设定 Chroot 目录权限。</h2>
<pre><code class="language-sh">chown root:test /data/sftp/erya
chmod 755 /data/sftp/erya
</code></pre>
<p>错误的目录权限设定会导致在 log 中出现”<code>fatal: bad ownership or modes for chroot directory XXXXXX</code>” 的内容.</p>
<h3>1，目录的权限设定有两个要点</h3>
<ul>
<li>1、由 ChrootDirectory 指定的目录开始一直往上到系统根目录为止的目录拥有者都只能是 root</li>
<li>2、由 ChrootDirectory 指定的目录开始一直往上到系统根目录为止都不可以具有群组写入权限</li>
</ul>
<h3>2，所以遵循以上两个原则</h3>
<ul>
<li>1）我们将 / data/sftp/erya 的所有者设置为了 root，所有组设置为 test</li>
<li>2）我们将 / data/sftp/erya 的权限设置为 755，所有者 root 有写入权限，而所有组 test 无写入权限</li>
</ul>
<h2>6、建立 erya 用户登入后可写入的目录。</h2>
<p>照上面设置后，在重启 sshd 服务后，用户 erya 已经可以登录，但使用 chroot 指定根目录后，根应该是无法写入的，所以要新建一个目录供 erya 上传文件。这个目录所有者为 erya，所有组为 test，所有者有写入权限，而所有组无写入权限。</p>
<pre><code class="language-sh">mkdir /data/sftp/erya/upload  
chown erya:test /data/sftp/erya/upload  
chmod 755 /data/sftp/erya/upload
</code></pre>
<h2>7、重启 sshd 服务。</h2>
<pre><code class="language-sh">service sshd restart
</code></pre>
<p>到这里，我们就可以通过 sftp 客户端登录并可以上传文件到<code>upload</code>目录。</p>
<p>如果还是不能在此目录下上传文件，提示没有权限，检查 SElinux 是否关闭，可以使用<code># setenforce 0</code>指令关闭临时 SElinux。
或者修改<code>/etc/selinux/config</code>文件中的<code>SELINUX=&quot;&quot; 为 disabled</code>，然后重启，进行永久关闭。</p>
<p>此时可以通过 Linux 命令行登陆刚才配置的 sftp 服务了。</p>
<p>常规登陆：sftp <a href="mailto:erya@192.168.96.219">erya@192.168.96.219</a>
指定端口：sftp <a href="mailto:erya@192.168.96.219">erya@192.168.96.219</a> -oPort=2222</p>
<p>也可以用过 file-zilla，sftp 等客户端登陆，进行上传下载。</p>
<p>然后是对下载端进行配置。</p>
<h2>8，安装 nginx 服务。</h2>
<p>进入到配置文件中，配置如下内容：</p>
<pre><code class="language-nginx">server {  
	        listen       80;  
	        server_name sftp.erya.net;  
	        charset utf-8;  
	        location / {  
	                root   /data/sftp/erya/upload;  
	                autoindex       on;  
	                autoindex_exact_size    off;  
	                autoindex_localtime     on;  
	          }  
	     } 
</code></pre>
<p><code>nginx -t</code> 检测一下配置文件。
<code>nginx -s reload</code>重新加载。</p>
<p>然后对刚才配置的域名进行解析配置。完成之后就可以到浏览器直接访问并进行下载了。</p>
<p>现在为了控制 sftp 授权的用户（<code>erya</code>）对服务器的权限，让他在连接工具中直接<code>免密码登陆</code>。</p>
<p>先在 root 用户下生成一对密钥对。</p>
<pre><code class="language-sh">[root@localhost ~]# ssh-keygen -t rsa
</code></pre>
<p>然后把公钥传给家目录下改名为<code>authorized_keys</code>，然后在登陆的时候，使用私钥文件，就实现了免密码登陆。</p>
<pre><code class="language-sh">cp /root/.ssh/id_rsa.pub /home/erya/.ssh/authorized_keys
</code></pre>
<p>如果想通过传输的方式将公钥传输过去，那么有两种情况。</p>
<h3>1，端口默认。</h3>
<p>这种情况下，就直接使用 ssh-copy-id 的方式进行传输就好了。</p>
<h3>2，指定端口。</h3>
<pre><code class="language-sh">ssh-copy-id –I .ssh/id_rsa.pub “-p 12345 abc@192.168.66.10”
</code></pre>
<h2>9，sftp 客户端如何使用。</h2>
<p>1， 将 / root/.ssh/id_rsa 文件发到本地，然后在 Xftp 的工具栏里导入。</p>
<p><img src="/img/inline/sftp-filezilla-config.png" alt="img"></p>
<p>2， 进行 erya 用户登陆的配置，IP，协议，端口，秘钥，用户名。</p>
<p><img src="/img/inline/sftp-erya-login.jpg" alt="img"></p>
<p>3， 配置完成，直接点击连接，这样用户就锁定在 upload 目录下了。</p>
<p>这样如果给别人来进行上传，直接让他在客户端，把秘钥文件发给他，就 ok 了。安全又卫生。</p>
<p><img src="/img/inline/sftp-upload-verify.jpg" alt="img"></p>
<p>现在，上传的文件，与 nginx 所访问到的目录文件保持了一致，只要在域名后边添加相应的文件名字，就可以直接进行下载了，把这样的效果交给服务端开发同学，只需要他这边把链接放到对应的地方就可以啦。</p>
]]></description><link>https://www.ranisa.cn/pages/1086.html</link><guid isPermaLink="true">https://www.ranisa.cn/pages/1086.html</guid><pubDate>Wed, 29 Jul 2026 00:00:00 GMT</pubDate></item><item><title><![CDATA[nginx配置文件及模块]]></title><description><![CDATA[<hr>
<p>title: nginx配置文件及模块
titleTag: 收藏(二丫讲梵)备查
date: 2018-06-21 22:36:45
permalink: /pages/1153.html
categories:</p>
<ul>
<li>Linux笔记</li>
<li>Nginx
tags:</li>
<li>nginx</li>
</ul>
<hr>
<p>::: tip 版本说明
本文写于 2018-06，基于 Nginx 1.14 左右版本。&lt;br&gt;核心配置结构（<code>http</code>/<code>server</code>/<code>location</code>）与本文所涉模块历年未变，经 2026-07 复核仍适用。
:::</p>
<h2>1，nginx 是什么？</h2>
<p>Nginx 是一个基于 c 语言开发的高性能 http 服务器及反向代理服务器。由俄罗斯的程序设计师 Igor Sysoev 所开发，官方测试 nginx 能够支支撑 5 万并发链接，并且 cpu、内存等资源消耗却非常低，运行非常稳定。</p>
<h2>2，为什么要用 nginx？</h2>
<h3>理由一：</h3>
<p>传统的小型网站并发量小，用户使用的少，所以在低并发的情况下，用户可以直接访问 tomcat 服务器，然后 tomcat 服务器返回消息给用户。为了解决并发，可以使用负载均衡，也就是多增加几个 tomcat 服务器，当用户访问的时候，请求可以提交到空闲的 tomcat 服务器上。</p>
<p>但是这种情况下可能会出现一种问题：假设把图片上传到了 tomcat1 上了，当要访问这个图片的时候，tomcat1 正好在工作，所以访问的请求就交给其他的 tomcat 操作，而 tomcat 之间的数据没有进行同步，所以就发生了我们要请求的图片找不到。</p>
<p>为了解决这种情况，我们专门建立一个图片服务器，用来存储图片。这样当都把图片上传的时候，不管是哪个服务器接收到图片，都把图片上传到图片服务器。而图片服务器上需要安装一个 http 服务，可以使用 tomcat、apache、nginx。</p>
<h3>理由二：</h3>
<p>nginx 常用做静态内容服务和代理服务器，直面外来请求转发给后面的应用服务（tomcat，django 什么的），tomcat 更多用来做做一个应用容器，让 java web app 跑在里面的东西。</p>
<h3>理由三：</h3>
<p><code>nginx作反向代理：</code></p>
<p>反向代理就是后端服务不直接对外暴露, 请求首先发送到 nginx, 然后 nginx 将请求转发到后端服务器, 比如 tomcat 等. 如果后端服务只有一台服务器, nginx 在这里只有一个作用就是起到了代理后端服务接收请求的作用. 称之为反向代理.</p>
<h3>理由四：</h3>
<p><code>nginx作负载均衡：</code></p>
<p>在现实的应用场景中, 一台后端服务器出现单点故障的概率很大或者单台机器的吞吐量有限, 无法承担过多请求. 这时候就需要在 nginx 后端配置多台服务器, 利用 nginx 内置的规则讲请求转发到后端不同的机器上. 这时候就起到了负载均衡的作用.</p>
<h2>3，nginx 配置文件。</h2>
<p><code>主要组成部分：</code></p>
<p><em><strong>main（全局设置）</strong></em></p>
<p>main 部分设置的指令将影响其它所有部分的设置；</p>
<p><em><strong>server（主机设置）</strong></em></p>
<p>server 部分的指令主要用于指定虚拟主机域名、IP 和端口；</p>
<p><em><strong>upstream</strong></em></p>
<p>upstream 的指令用于设置一系列的后端服务器，设置反向代理及后端服务器的负载均衡；</p>
<p><em><strong>location</strong></em></p>
<p>location 部分用于匹配网页位置（比如，根目录 “/”,“/images”, 等等）；</p>
<p><code>他们之间的关系：</code></p>
<p>server 继承 main，location 继承 server；upstream 既不会继承指令也不会被继承。它有自己的特殊指令，不需要在其他地方的应用。</p>
<p><code>举例说明：</code></p>
<p>下面的 nginx.conf 简单的实现 nginx 在前端做反向代理服务器的例子，处理 js、png 等静态文件，jsp 等动态请求转发到其它服务器 tomcat：</p>
<pre><code class="language-nginx">user www www;
worker_processes 2;
error_log logs/error.log;
#error_log logs/error.log notice;
#error_log logs/error.log info;
pid logs/nginx.pid;
events {
    use epoll;
    worker_connections 2048;
}
http {
    include mime.types;
    default_type application/octet-stream;
    #log_format main '$remote_addr - $remote_user [$time_local] &quot;$request&quot; '
    # '$status $body_bytes_sent &quot;$http_referer&quot; '
    # '&quot;$http_user_agent&quot; &quot;$http_x_forwarded_for&quot;';
    #access_log logs/access.log main;
    sendfile on;
    # tcp_nopush on;
    keepalive_timeout 65;
    # gzip压缩功能设置
    gzip on;
    gzip_min_length 1k;
    gzip_buffers 4 16k;
    gzip_http_version 1.0;
    gzip_comp_level 6;
    gzip_types text/html text/plain text/css text/javascript application/json application/javascript application/x-javascript application/xml;
    gzip_vary on;
    # http_proxy 设置
    client_max_body_size 10m;
    client_body_buffer_size 128k;
    proxy_connect_timeout 75;
    proxy_send_timeout 75;
    proxy_read_timeout 75;
    proxy_buffer_size 4k;
    proxy_buffers 4 32k;
    proxy_busy_buffers_size 64k;
    proxy_temp_file_write_size 64k;
    proxy_temp_path /usr/local/nginx/proxy_temp 1 2;
    # 设定负载均衡后台服务器列表
    upstream backend {
        #ip_hash;
        server &lt;INTERNAL_IP&gt;:8080 max_fails=2 fail_timeout=30s ;
        server &lt;INTERNAL_IP&gt;:8080 max_fails=2 fail_timeout=30s ;
    }
    # 很重要的虚拟主机配置
    server {
        listen 80;
        server_name itoatest.example.com;
        root /apps/oaapp;
        charset utf-8;
        access_log logs/host.access.log main;
       
        #对 / 所有做负载均衡+反向代理
        location / {
            root /apps/oaapp;
            index index.jsp index.html index.htm;
            proxy_pass http://backend;
            proxy_redirect off;
            # 后端的Web服务器可以通过X-Forwarded-For获取用户真实IP
            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_next_upstream error timeout invalid_header http_500 http_502 http_503 http_504;
        }
        #静态文件，nginx自己处理，不去backend请求tomcat
        location ~* /download/ {
            root /apps/oa/fs;
        }
        location ~ .*\.(gif|jpg|jpeg|bmp|png|ico|txt|js|css)$ {
            root /apps/oaapp;
            expires 7d;
        }
        location /nginx_status {
            stub_status on;
            access_log off;
            allow &lt;INTERNAL_IP&gt;/24;
            deny all;
        }
        location ~ ^/(WEB-INF)/ {
            deny all;
        }
        #error_page 404 /404.html;
        # redirect server error pages to the static page /50x.html
        #
        error_page 500 502 503 504 /50x.html;
        location = /50x.html {
            root html;
        }
    }
## 其它虚拟主机，server 指令开始
}
</code></pre>
<p>这里仅仅是作为一个示例。</p>
<p><img src="/img/inline/nginx-config-modules.jpg" alt="img"></p>
<h2>4，常用指令或者模块说明。</h2>
<h3>4.1main 全局设置。</h3>
<p><code>woker_processes 2;</code></p>
<blockquote>
<p>在配置文件的顶级 main 部分，worker 角色的工作进程的个数，master 进程是接收并分配请求给 worker 处理。这个数值简单一点可以设置为 cpu 的核数 grep ^processor /proc/cpuinfo | wc -l，也是 auto 值，如果开启了 ssl 和 gzip 更应该设置成与逻辑 CPU 数量一样甚至为 2 倍，可以减少 I/O 操作。如果 nginx 服务器还有其它服务，可以考虑适当减少。</p>
</blockquote>
<p><code>worker_cpu_affinity;</code></p>
<blockquote>
<p>也是写在 main 部分。在高并发情况下，通过设置 cpu 粘性来降低由于多 CPU 核切换造成的寄存器等现场重建带来的性能损耗。如 worker_cpu_affinity 0001 0010 0100 1000; （四核）。</p>
</blockquote>
<p><code>worker_connections 2048;</code></p>
<blockquote>
<p>写在 events 部分。每一个 worker 进程能并发处理（发起）的最大连接数（包含与客户端或后端被代理服务器间等所有连接数）。nginx 作为反向代理服务器，计算公式 最大连接数 = worker_processes *</p>
</blockquote>
<p><code>worker_rlimit_nofile 10240;</code></p>
<blockquote>
<p>写在 main 部分。默认是没有设置，可以限制为操作系统最大的限制 65535。</p>
</blockquote>
<p><code>use epoll;</code></p>
<blockquote>
<p>写在 events 部分。在 Linux 操作系统下，nginx 默认使用 epoll 事件模型，得益于此，nginx 在 Linux 操作系统下效率相当高。同时 Nginx 在 OpenBSD 或 FreeBSD 操作系统上采用类似于 epoll 的高效事件模型 kqueue。在操作系统不支持这些高效模型时才使用 select。</p>
</blockquote>
<h3>4.2http 服务器。</h3>
<p><code>sendfile on;</code></p>
<blockquote>
<p>开启高效文件传输模式，sendfile 指令指定 nginx 是否调用 sendfile 函数来输出文件，减少用户空间到内核空间的上下文切换。对于普通应用设为 on，如果用来进行下载等应用磁盘 IO 重负载应用，可设置为 off，以平衡磁盘与网络 I/O 处理速度，降低系统的负载；</p>
</blockquote>
<p><code>keepalive_timeout 65;</code></p>
<blockquote>
<p>长连接超时时间，单位是秒，这个参数很敏感，涉及浏览器的种类、后端服务器的超时设置、操作系统的设置，可以另外起一片文章了。长连接请求大量小文件的时候，可以减少重建连接的开销，但假如有大文件上传，65s 内没上传完成会导致失败。如果设置时间过长，用户又多，长时间保持连接会占用大量资源；</p>
</blockquote>
<p><code>send_timeout ;</code></p>
<blockquote>
<p>用于指定响应客户端的超时时间。这个超时仅限于两个连接活动之间的时间，如果超过这个时间，客户端没有任何活动，Nginx 将会关闭连接；</p>
</blockquote>
<p><code>client_max_body_size 10m;</code></p>
<blockquote>
<p>允许客户端请求的最大单文件字节数。如果有上传较大文件，请设置它的限制值；</p>
</blockquote>
<p><code>client_body_buffer_size 128k;</code></p>
<blockquote>
<p>缓冲区代理缓冲用户端请求的最大字节数；</p>
</blockquote>
<h3>4.3 模块 http_proxy</h3>
<p><code>proxy_read_timeout 60;</code></p>
<blockquote>
<p>连接成功后，与后端服务器两个成功的响应操作之间超时时间 (代理接收超时)</p>
</blockquote>
<p><code>proxy_buffer_size 4k;</code></p>
<blockquote>
<p>设置代理服务器（nginx）从后端 realserver 读取并保存用户头信息的缓冲区大小，默认与 proxy_buffers 大小相同，其实可以将这个指令值设的小一点</p>
</blockquote>
<p><code>proxy_buffers 4 32k;</code></p>
<blockquote>
<p>proxy_buffers 缓冲区，nginx 针对单个连接缓存来自后端 realserver 的响应，网页平均在 32k 以下的话，这样设置</p>
</blockquote>
<p><code>proxy_busy_buffers_size 64k;</code></p>
<blockquote>
<p>高负荷下缓冲大小（proxy_buffers*2）</p>
</blockquote>
<p><code>proxy_max_temp_file_size;</code></p>
<blockquote>
<p>当 proxy_buffers 放不下后端服务器的响应内容时，会将一部分保存到硬盘的临时文件中，这个值用来设置最大临时文件大小，默认 1024M，它与 proxy_cache 没有关系。大于这个值，将从 upstream 服务器传回。设置为 0 禁用。</p>
</blockquote>
<p><code>proxy_temp_file_write_size 64k;</code></p>
<blockquote>
<p>当缓存被代理的服务器响应到临时文件时，这个选项限制每次写临时文件的大小。proxy_temp_path（可以在编译的时候）指定写到哪那个目录。</p>
</blockquote>
<h3>4.4 模块 http_gzip：</h3>
<p><code>gzip on :</code></p>
<blockquote>
<p>开启 gzip 压缩输出，减少网络传输。</p>
</blockquote>
<p><code>gzip_min_length 1k ：</code></p>
<blockquote>
<p>设置允许压缩的页面最小字节数，页面字节数从 header 头得 content-length 中进行获取。默认值是 20。建议设置成大于 1k 的字节数，小于 1k 可能会越压越大。</p>
</blockquote>
<p><code>gzip_buffers 4 16k ：</code></p>
<blockquote>
<p>设置系统获取几个单位的缓存用于存储 gzip 的压缩结果数据流。4 16k 代表以 16k 为单位，安装原始数据大小以 16k 为单位的 4 倍申请内存。</p>
</blockquote>
<p><code>gzip_http_version 1.0 ：</code></p>
<blockquote>
<p>用于识别 http 协议的版本，早期的浏览器不支持 Gzip 压缩，用户就会看到乱码，所以为了支持前期版本加上了这个选项，如果你用了 Nginx 的反向代理并期望也启用 Gzip 压缩的话，由于末端通信是 http/1.0，故请设置为 1.0。</p>
</blockquote>
<p><code>gzip_comp_level 6 ：</code></p>
<blockquote>
<p>gzip 压缩比，1 压缩比最小处理速度最快，9 压缩比最大但处理速度最慢 (传输快但比较消耗 cpu)</p>
</blockquote>
<p><code>gzip_types ：</code></p>
<blockquote>
<p>匹配 mime 类型进行压缩，无论是否指定,”text/html” 类型总是会被压缩的。</p>
</blockquote>
<p><code>gzip_proxied any ：</code></p>
<blockquote>
<p>Nginx 作为反向代理的时候启用，决定开启或者关闭后端服务器返回的结果是否压缩，匹配的前提是后端服务器必须要返回包含”Via” 的 header 头。</p>
</blockquote>
<p><code>gzip_vary on ：</code></p>
<blockquote>
<p>和 http 头有关系，会在响应头加个 Vary: Accept-Encoding ，可以让前端的缓存服务器缓存经过 gzip 压缩的页面，例如，用 Squid 缓存经过 Nginx 压缩的数据。</p>
</blockquote>
<h3>4.5server 虚拟主机</h3>
<p><code>listen;</code></p>
<blockquote>
<p>监听端口，默认 80，小于 1024 的要以 root 启动。可以为 listen *:80、listen &lt;PUBLIC_IP&gt;:80 等形式。</p>
</blockquote>
<p><code>server_name;</code></p>
<blockquote>
<p>服务器名，如 localhost、www.example.com，可以通过正则匹配。</p>
</blockquote>
<h3>4.6 模块 http_stream</h3>
<p><code>host:port options;</code></p>
<blockquote>
<p>这个模块通过一个简单的调度算法来实现客户端 IP 到后端服务器的负载均衡，upstream 后接负载均衡器的名字，后端 realserver 以 host:port options; 方式组织在 {} 中。如果后端被代理的只有一台，也可以直接写在 proxy_pass 。</p>
</blockquote>
<h3>4.7location</h3>
<p><code>root /var/www/html;</code></p>
<blockquote>
<p>定义服务器的默认网站根目录位置。如果 locationURL 匹配的是子目录或文件，root 没什么作用，一般放在 server 指令里面或 / 下。</p>
</blockquote>
<p><code>index index.jsp index.html index.htm;</code></p>
<blockquote>
<p>定义路径下默认访问的文件名，一般跟着 root 放</p>
</blockquote>
<p><code>proxy_pass http:/backend;</code></p>
<blockquote>
<p>请求转向 backend 定义的服务器列表，即反向代理，对应 upstream 负载均衡器。也可以 proxy_pass <a href="http://ip:port%E3%80%82/">http://ip:port。</a></p>
</blockquote>
<p><strong>实战：<code>root</code> 和 <code>alias</code> 单独代理一个静态文件的区别</strong></p>
<p>给某个特定路径（比如 SEO 需要的 <code>sitemap.xml</code>）单独指定物理文件位置，是 <code>root</code>/<code>alias</code> 用法差异体现最明显的场景。两种写法：</p>
<pre><code class="language-nginx"># 方式一：alias —— location 路径不会拼进最终文件路径
location /sitemap.xml {
    alias /data/www/static/maps/map.xml;
}

# 方式二：root —— location 路径会拼进最终文件路径
location /sitemap.xml {
    root /data/www/static/maps;
}
</code></pre>
<p>区别在于<strong>最终请求的文件路径怎么拼</strong>：<code>alias</code> 直接把 <code>alias</code> 值当成目标文件/目录，<code>location</code> 后面的路径不参与拼接；<code>root</code> 则是把 <code>location</code> 匹配到的路径原样拼到 <code>root</code> 值后面。所以上面两种写法要生效，第一种的 <code>alias</code> 必须精确到文件名 <code>map.xml</code>，第二种的 <code>root</code> 目录下必须真实存在一个叫 <code>sitemap.xml</code> 的文件（因为 <code>root</code> 会拼接 <code>/sitemap.xml</code> 到路径末尾）。</p>
<p><strong>坑</strong>：混用是最常见的错误——把 <code>alias</code> 当 <code>root</code> 用（<code>alias</code> 目录下没有对应的子路径文件，直接 404），或者反过来把 <code>root</code> 当 <code>alias</code> 用（多拼出一层路径导致 404）。规则记忆：<code>alias</code> 是&quot;精确替换&quot;，<code>root</code> 是&quot;目录拼接&quot;。</p>
<p><strong>验证</strong>：<code>curl -I http://your-domain/sitemap.xml</code>，看到 <code>200</code> 且 <code>Content-Type</code> 正确即为生效；<code>nginx -t</code> 语法检查通过不代表路径正确，必须实际请求验证。</p>
<h3>4.8 访问控制 allow/deny</h3>
<p>Nginx 的访问控制模块默认就会安装，而且写法也非常简单，可以分别有多个<code>allow,deny</code>，允许或禁止某个 ip 或 ip 段访问，依次满足任何一个规则就停止往下匹配。如：</p>
<pre><code class="language-sh">location /nginx-status {
    stub_status on;
    access_log off;
    # auth_basic &quot;NginxStatus&quot;;
    # auth_basic_user_file /usr/local/nginx-1.6/htpasswd;
    allow &lt;INTERNAL_IP&gt;;
    allow &lt;INTERNAL_IP&gt;/24;
    deny all;
}
</code></pre>
<p>也常用 httpd-devel 工具的 <code>htpasswd</code> 来为访问的路径设置登录密码：</p>
<pre><code class="language-sh"># htpasswd -c htpasswd admin
New passwd=&lt;PASSWORD&gt; new password=&lt;PASSWORD&gt; password for user admin
# htpasswd htpasswd admin //修改admin密码
# htpasswd htpasswd sean //多添加一个认证用户
</code></pre>
<p>这样就生成了默认使用 CRYPT 加密的密码文件。打开上面 nginx-status 的两行注释，重启 nginx 生效。</p>
<h3>4.9 列出目录 autoindex</h3>
<p>Nginx 默认是不允许列出整个目录的。</p>
<p>如需此功能，打开 nginx.conf 文件，在 location，server 或 http 段中加入 autoindex on;，另外两个参数最好也加上去:</p>
<p><code>autoindex_exact_size off;</code></p>
<blockquote>
<p>默认为 on，显示出文件的确切大小，单位是 bytes。改为 off 后，显示出文件的大概大小，单位是 kB 或者 MB 或者 GB</p>
</blockquote>
<p><code>autoindex_localtime on;</code></p>
<blockquote>
<p>默认为 off，显示的文件时间为 GMT 时间。改为 on 后，显示的文件时间为文件的服务器时间</p>
</blockquote>
<pre><code class="language-sh">location /images {
    root /var/www/nginx-default/images;
    autoindex on;
    autoindex_exact_size off;
    autoindex_localtime on;
}
</code></pre>
<p>整理自公众号《<a href="https://mp.weixin.qq.com/s/YrC8aPZHtDlDL2Fqku2fbA">我的运维之旅</a>》</p>
]]></description><link>https://www.ranisa.cn/pages/1153.html</link><guid isPermaLink="true">https://www.ranisa.cn/pages/1153.html</guid><pubDate>Wed, 29 Jul 2026 00:00:00 GMT</pubDate></item><item><title><![CDATA[nginx通过四层代理实现端口转发]]></title><description><![CDATA[<hr>
<p>title: nginx通过四层代理实现端口转发
titleTag: 收藏(二丫讲梵)备查
date: 2018-11-08 22:37:09
permalink: /pages/1197.html
categories:</p>
<ul>
<li>Linux笔记</li>
<li>Nginx
tags:</li>
<li>nginx</li>
</ul>
<hr>
<p>::: tip 版本说明
本文写于 2018-11，基于 Nginx 1.14 左右版本。&lt;br&gt;<code>stream</code> 模块自 1.9 起长期稳定，配置语法未变，经 2026-07 复核仍适用。
:::</p>
<p>公司原有的测试数据库在主机<code>192.168.10.5</code>上边，现在数据库转移到了<code>192.168.10.4</code>上，为了不让各个地方都需要更改地址，现在需要一个四层代理工具，将原来请求到<code>192.168.10.5</code>的<code>3306</code>端口转发到<code>192.168.10.4</code>的<code>3306</code>端口。</p>
<p>这个工具，用到了 nginx 的四层代理。</p>
<p>官方文档：http://nginx.org/en/docs/stream/ngx_stream_core_module.html</p>
<p>四层代理依赖模块<code>ngx_stream_core_module</code>，该模块自 1.9.0 版开始可用。默认情况下，此模块不构建，应使用配置参数启用 <code>--with-stream</code>。</p>
<p>安装过程简示：</p>
<pre><code class="language-sh">[root@linux-node1 src]# tar xf nginx-1.10.3.tar.gz 
[root@linux-node1 src]# cd nginx-1.10.3
[root@linux-node1 nginx-1.10.3]# useradd -s /sbin/nologin -M www
[root@linux-node1 nginx-1.10.3]# yum install gcc gcc-c++ zlib-devel pcre-devel openssl openssl-devel -y
[root@linux-node1 nginx-1.10.3]# ./configure --prefix=/usr/local/nginx-1.10.3 --user=www --group=www --with-http_ssl_module --with-http_stub_status_module --with-file-aio --with-stream
[root@linux-node1 nginx-1.10.3]# make &amp;&amp; make install 
</code></pre>
<p>可以通过<code>nginx -V</code>查看一下是否将上述模块编译进来，如果没有，可以重新编译一下。</p>
<p><img src="/img/inline/nginx-l4-proxy.jpg" alt="img"></p>
<p>来到主配置：</p>
<pre><code class="language-nginx">worker_processes  1;
events {
    worker_connections  1024;
}
stream {  
        upstream tcp_proxy {
        hash $remote_addr consistent;  #远程地址做个hash
        server 192.168.10.4:22;
   }
      server {
        listen 2222;
        proxy_connect_timeout 1s;
        proxy_timeout 10s;  #后端连接超时时间
        proxy_pass tcp_proxy;
     }
  }
</code></pre>
<p>此配置是将本机的 2222 端口转发到 192.168.10.4 的 22 端口，配置之后，试验一下：</p>
<pre><code class="language-sh">[root@7-3 nginx]$ssh -p 2222 root@192.168.10.5
The authenticity of host '[192.168.10.5]:2222 ([192.168.10.5]:2222)' can't be established.
ECDSA key fingerprint is 05:2f:63:e9:87:be:b4:44:d3:d7:77:a0:52:e0:4f:2f.
Are you sure you want to continue connecting (yes/no)? yes
Warning: Permanently added '[192.168.10.5]:2222' (ECDSA) to the list of known hosts.
root@192.168.10.5's password:
Last login: Wed Nov  7 15:24:33 2018 from 192.168.10.1
[root@7-2 ~]$hostname -I
192.168.10.4
</code></pre>
<p>刚刚设置了 10 的超时，如果需要的话，可以将之注释掉。</p>
<p>同理，配置数据库端口的转发也就非常简单了：</p>
<pre><code class="language-nginx">worker_processes  1;
events {
    worker_connections  1024;
}
stream {  
        upstream tcp_proxy {
        hash $remote_addr consistent;  #远程地址做个hash
        server 192.168.10.4:3306;
   }
      server {
        listen 3306;
        proxy_connect_timeout 1s;
       # proxy_timeout 10s;  #后端连接超时时间
        proxy_pass tcp_proxy;
     }
  }
</code></pre>
<p>这样一来，用户连接<code>192.168.10.5:3306</code>的时候，就会被转发到<code>192.168.10.4:3306</code>了。</p>
<p>本文参考地址：https://www.cnblogs.com/w787815/p/6682824.html</p>
]]></description><link>https://www.ranisa.cn/pages/1197.html</link><guid isPermaLink="true">https://www.ranisa.cn/pages/1197.html</guid><pubDate>Wed, 29 Jul 2026 00:00:00 GMT</pubDate></item></channel></rss>