<?xml version="1.0" encoding="utf-8" standalone="yes"?><rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom" xmlns:content="http://purl.org/rss/1.0/modules/content/"><channel><title>开发文档onDocs</title><link>https://hiraethecho.github.io/docs/dev/</link><description>Recent contentin开发文档onDocs</description><generator>Hugo --0.152.2</generator><language>en</language><managingEditor>wyz2016zxc@outlook.com(Hiraeth)</managingEditor><webMaster>wyz2016zxc@outlook.com(Hiraeth)</webMaster><atom:link href="https://hiraethecho.github.io/docs/dev/index.xml" rel="self" type="application/rss+xml"/><item><title>git底层设计</title><link>https://hiraethecho.github.io/docs/dev/git-base/</link><pubDate>Wed, 17 Dec 2025 00:00:00 +0000</pubDate><author>wyz2016zxc@outlook.com(Hiraeth)</author><guid>https://hiraethecho.github.io/docs/dev/git-base/</guid><description>了解了一下git的底层实现方式，感觉很厉害，记录一下</description><content:encoded><![CDATA[<h1 id="git底层设计">
  <a class="anchor inpage" href="#git%e5%ba%95%e5%b1%82%e8%ae%be%e8%ae%a1">#</a>git底层设计</h1>
<p>git是Linus的分布式版本控制软件，据说用了一周写出来，太强了。</p>
<h2 id="目标">
  <a class="anchor inpage" href="#%e7%9b%ae%e6%a0%87">##</a>目标</h2>
<p>版本控制的目标是，记录每次更改，或者说记录每个版本。除此之外还有额外要求：</p>
<ul>
<li>低成本创建分支</li>
<li>保证版本内容的可信性，不被篡改</li>
<li>分布式</li>
</ul>
<h2 id="思路">
  <a class="anchor inpage" href="#%e6%80%9d%e8%b7%af">##</a>思路</h2>
<p>我第一个想到的实现方式是，增量存储，记录变更的内容。换句话说，存储的是一堆diff文件。这样的好处是，理论上存储空间会小。但是每一个版本的内容都会是从某一个版本为基础根据diff计算而来。</p>
<p>然而，信息的存储方式其实只是技术细节，关键的问题在于，如何把部分信息提取出来，组成一个版本的文件。
按照我的理解用比喻的方式描述。</p>
<p>假设现在写一本书，但是不是线性写作，而是多个章节同时开始，内容写在一个活页本上。<br>
第一天分别写了一二三节的开头，写在三页纸上，这三页纸有各自的名字，暂且称为a, b, c。再用一张小纸条，记录内容是<em>a, b, c是第一个版本的内容</em>，这个小纸条也有个名字，暂称为A。把它们放进活页本里。<br>
第二天重写了第二节，写在新的一张纸上，这张纸名字是d。同样的，有另一张小纸条，记录内容是<em>a, d, c是第二个版本的内容</em>，这个小纸条的名字记为B。再把它们放进活页本里。<br>
这样，我们就有A, B两个版本了。</p>
<h2 id="目标的实现">
  <a class="anchor inpage" href="#%e7%9b%ae%e6%a0%87%e7%9a%84%e5%ae%9e%e7%8e%b0">##</a>目标的实现</h2>
<p>沿用上面的比喻，接下来是一些额外的结构，来使用上述思路实现目标。</p>
<p>首先是分支。其实分支就只是又一个小纸条，贴在A, B这样的小纸条上。比如我是书的主要作者，我在B上贴一个main。我的合作者在A的基础上重写了第三节，写在e这张纸上，并且有个C记录<em>a, b, e</em>，在C上就可以有一个dev的小纸条，这就是dev分支。<br>
保证版本内容的可信性，有2个细节。第一，名字a, b, c和A, B, C其实是sha1，这样可以确保内容和名称匹配。第二，B, C上除了内容，其实还包括它的上一个版本，也就是说B还记录了A的名字，这就保证了历史的可信性。<br>
除此之外，git还使用了内容寻址的存储方式。这张纸a的文件名就是a，而a是内容的sha1，所以不同内容的纸不会在这里，很容易检验信息的真实性。<br>
至于分布式，由于分支只是一个小标签，这就自动满足了。</p>
<h2 id="ref">
  <a class="anchor inpage" href="#ref">##</a>ref</h2>
<p>
</p>
]]></content:encoded></item><item><title>hugo</title><link>https://hiraethecho.github.io/docs/dev/hugo/</link><pubDate>Tue, 02 Dec 2025 00:00:00 +0000</pubDate><author>wyz2016zxc@outlook.com(Hiraeth)</author><guid>https://hiraethecho.github.io/docs/dev/hugo/</guid><description>自制hugo主题后做一些记录</description><content:encoded><![CDATA[<h1 id="hugo">
  <a class="anchor inpage" href="#hugo">#</a>hugo</h1>
<p>hugo is a SSG. Using golang.</p>
<h2 id="hugo-site-structure">
  <a class="anchor inpage" href="#hugo-site-structure">##</a>hugo site structure</h2>
<h3 id="kinds">
  <a class="anchor inpage" href="#kinds">###</a>kinds</h3>
<p>There are mainly two kinds of site pages:</p>
<ul>
<li><code>page</code> for all markdown files like <code>content/subfolder/something.md</code> and goes to <code>https://example.com/subfolder/somethinng</code></li>
<li><code>section</code> for all <code>_index.md</code> in folder <code>content/another/_index.md</code> and goes to <code>https://example.com/another</code></li>
</ul>
<p>there are some special <code>section</code>, for example <code>content/_index</code> is <code>home</code>. And <code>taxonomy</code>, <code>term</code>, which are associated to taxonomy feature of hugo.</p>
<p>also you can make a bundle of a <code>page</code> with some resources. For example, <code>content/subfolder/something/index.md</code> goes to <code>https://example.com/subfolder/something</code>, and corresponding resources at <code>content/cubfolder/something/pic.jpg</code></p>
<h2 id="hugo-theme-structure">
  <a class="anchor inpage" href="#hugo-theme-structure">##</a>hugo theme structure</h2>
<details open>
    <summary>TEXT</summary><pre
        class="codeblock"
      ><code class="language-" data-lang="">custom-theme
├── assets
├── data
├── exampleSite
├── layouts
└── static</code><button onclick="copyCode(this)" class="copybtn">copy</button></pre></details>

  <script>
    function copyCode(btn) {
      const code = btn.previousElementSibling.textContent.trim();
      navigator.clipboard.writeText(code).then(() => {
        btn.innerText = "copied";
        setTimeout(() => (btn.innerText = "copy"), 2000);
      });
    }
  </script><h3 id="layouts">
  <a class="anchor inpage" href="#layouts">###</a>layouts</h3>
<details open>
    <summary>tree</summary><pre
        class="codeblock"
      ><code class="language-tree" data-lang="tree">layouts
├── _markup
├── _partials
├── baseof.html
├── home.html
├── index.json
├── page.html
├── rss.xml
├── section.html
├── taxonomy.html
└── term.html</code><button onclick="copyCode(this)" class="copybtn">copy</button></pre></details>

  <script>
    function copyCode(btn) {
      const code = btn.previousElementSibling.textContent.trim();
      navigator.clipboard.writeText(code).then(() => {
        btn.innerText = "copied";
        setTimeout(() => (btn.innerText = "copy"), 2000);
      });
    }
  </script><h3 id="render">
  <a class="anchor inpage" href="#render">###</a>render</h3>
<details open>
    <summary>tree</summary><pre
        class="codeblock"
      ><code class="language-tree" data-lang="tree">_markup
├── render-blockquote.html
├── render-codeblock-mermaid.html
├── render-codeblock.html
├── render-heading.html
├── render-image.html
└── render-link.html</code><button onclick="copyCode(this)" class="copybtn">copy</button></pre></details>

  <script>
    function copyCode(btn) {
      const code = btn.previousElementSibling.textContent.trim();
      navigator.clipboard.writeText(code).then(() => {
        btn.innerText = "copied";
        setTimeout(() => (btn.innerText = "copy"), 2000);
      });
    }
  </script><h3 id="others">
  <a class="anchor inpage" href="#others">###</a>others</h3>
<p>assets</p>
<p>i18n</p>
<p>data</p>
<h2 id="go-templates">
  <a class="anchor inpage" href="#go-templates">##</a>go templates</h2>
<p>transforms data into HTML.</p>
<h3 id="context">
  <a class="anchor inpage" href="#context">###</a>context</h3>
<p>Hugo makes extensive use of the Go Template language for designing its themes. &ldquo;Context&rdquo; refers to the data that is passed to a template when it is rendered. Templates can access context to display dynamic content.</p>
<p><strong>Example Context Access:</strong></p>
<details open>
    <summary>TEXT</summary><pre
        class="codeblock"
      ><code class="language-" data-lang="">&lt;title&gt;{{ .Title }}&lt;/title&gt;
&lt;p&gt;{{ .Content }}&lt;/p&gt;</code><button onclick="copyCode(this)" class="copybtn">copy</button></pre></details>

  <script>
    function copyCode(btn) {
      const code = btn.previousElementSibling.textContent.trim();
      navigator.clipboard.writeText(code).then(() => {
        btn.innerText = "copied";
        setTimeout(() => (btn.innerText = "copy"), 2000);
      });
    }
  </script><h3 id="range-with-if-index">
  <a class="anchor inpage" href="#range-with-if-index">###</a>range, with, if, index</h3>
<ul>
<li><strong>Range</strong>: Used to iterate over collections such as a slice or map.
<strong>Example:</strong>
<details open>
    <summary>TEXT</summary><pre
        class="codeblock"
      ><code class="language-" data-lang="">{{ range .Data.Pages }}
  &lt;p&gt;{{ .Title }}&lt;/p&gt;
{{ end }}</code><button onclick="copyCode(this)" class="copybtn">copy</button></pre></details>

  <script>
    function copyCode(btn) {
      const code = btn.previousElementSibling.textContent.trim();
      navigator.clipboard.writeText(code).then(() => {
        btn.innerText = "copied";
        setTimeout(() => (btn.innerText = "copy"), 2000);
      });
    }
  </script></li>
<li><strong>With</strong>: Equivalent to an <code>if</code> statement that changes the default context.
<strong>Example:</strong>
<details open>
    <summary>TEXT</summary><pre
        class="codeblock"
      ><code class="language-" data-lang="">{{ with .Site.Menu.main }}
  &lt;ul&gt;
    {{ range . }}
      &lt;li&gt;{{ .Name }}&lt;/li&gt;
    {{ end }}
  &lt;/ul&gt;
{{ end }}</code><button onclick="copyCode(this)" class="copybtn">copy</button></pre></details>

  <script>
    function copyCode(btn) {
      const code = btn.previousElementSibling.textContent.trim();
      navigator.clipboard.writeText(code).then(() => {
        btn.innerText = "copied";
        setTimeout(() => (btn.innerText = "copy"), 2000);
      });
    }
  </script></li>
<li><strong>If</strong>: Conditional rendering.
<strong>Example:</strong>
<details open>
    <summary>TEXT</summary><pre
        class="codeblock"
      ><code class="language-" data-lang="">{{ if isset .Site.Params &#34;author&#34; }}
  &lt;p&gt;Author: {{ .Site.Params.author }}&lt;/p&gt;
{{ end }}</code><button onclick="copyCode(this)" class="copybtn">copy</button></pre></details>

  <script>
    function copyCode(btn) {
      const code = btn.previousElementSibling.textContent.trim();
      navigator.clipboard.writeText(code).then(() => {
        btn.innerText = "copied";
        setTimeout(() => (btn.innerText = "copy"), 2000);
      });
    }
  </script></li>
<li><strong>Index</strong>: Retrieves specific content from a slice or map.
<strong>Example:</strong>
<details open>
    <summary>TEXT</summary><pre
        class="codeblock"
      ><code class="language-" data-lang="">{{ index .Site.Params &#34;social&#34; &#34;twitter&#34; }}</code><button onclick="copyCode(this)" class="copybtn">copy</button></pre></details>

  <script>
    function copyCode(btn) {
      const code = btn.previousElementSibling.textContent.trim();
      navigator.clipboard.writeText(code).then(() => {
        btn.innerText = "copied";
        setTimeout(() => (btn.innerText = "copy"), 2000);
      });
    }
  </script></li>
</ul>
<p>Sorting, grouping, and accessing the first elements of collections can refine the data display.</p>
<h3 id="partials">
  <a class="anchor inpage" href="#partials">###</a>partials</h3>
<details open>
    <summary>go</summary><pre
        class="chroma codeblock"
      ><code class="language-go" data-lang="go"
          ><span style="display:flex;"><span>{{ <span style="color:#a6e22e">partial</span> <span style="color:#e6db74">&#34;header.html&#34;</span> . }}</span></span></code
        ><button onclick="copyCode(this)" class="copybtn">copy</button></pre></details>

  <script>
    function copyCode(btn) {
      const code = btn.previousElementSibling.textContent.trim();
      navigator.clipboard.writeText(code).then(() => {
        btn.innerText = "copied";
        setTimeout(() => (btn.innerText = "copy"), 2000);
      });
    }
  </script><p>where <code>layouts/partials/header.html</code> is the partial template file.</p>
<h3 id="hugo-special">
  <a class="anchor inpage" href="#hugo-special">###</a>hugo special</h3>
<h4 id="slice-scratch">
  <a class="anchor inpage" href="#slice-scratch">####</a>slice, scratch</h4>
<p>Hugo provides a <code>slice</code> function that helps in working with lists and arrays, enabling you to append items or create slices dynamically. The <code>scratch</code> object in Hugo allows for temporary data storage and manipulation during template rendering through methods like <code>add</code>, <code>set</code>, and <code>get</code>.</p>
<p><strong>Example of Using Slice:</strong></p>
<details open>
    <summary>TEXT</summary><pre
        class="codeblock"
      ><code class="language-" data-lang="">{{ $list := slice &#34;apple&#34; &#34;banana&#34; &#34;cherry&#34; }}
{{ range $list }}
  &lt;p&gt;{{ . }}&lt;/p&gt;
{{ end }}</code><button onclick="copyCode(this)" class="copybtn">copy</button></pre></details>

  <script>
    function copyCode(btn) {
      const code = btn.previousElementSibling.textContent.trim();
      navigator.clipboard.writeText(code).then(() => {
        btn.innerText = "copied";
        setTimeout(() => (btn.innerText = "copy"), 2000);
      });
    }
  </script><p><strong>Example of Using Scratch:</strong></p>
<details open>
    <summary>TEXT</summary><pre
        class="codeblock"
      ><code class="language-" data-lang="">{{ .Scratch.Set &#34;count&#34; 0 }}
{{ range .Pages }}
    {{ .Scratch.Add &#34;count&#34; 1 }}
{{ end }}
&lt;p&gt;Total Pages: {{ .Scratch.Get &#34;count&#34; }}&lt;/p&gt;</code><button onclick="copyCode(this)" class="copybtn">copy</button></pre></details>

  <script>
    function copyCode(btn) {
      const code = btn.previousElementSibling.textContent.trim();
      navigator.clipboard.writeText(code).then(() => {
        btn.innerText = "copied";
        setTimeout(() => (btn.innerText = "copy"), 2000);
      });
    }
  </script><h2 id="hugo-feature">
  <a class="anchor inpage" href="#hugo-feature">##</a>hugo feature</h2>
<h3 id="taxonomies">
  <a class="anchor inpage" href="#taxonomies">###</a>taxonomies</h3>
<h3 id="menus">
  <a class="anchor inpage" href="#menus">###</a>menus</h3>
<h3 id="outputs">
  <a class="anchor inpage" href="#outputs">###</a>outputs</h3>
<h3 id="assets">
  <a class="anchor inpage" href="#assets">###</a>assets</h3>
<p>The <code>assets</code> folder in Hugo is a central place for managing your static assets, such as CSS, JavaScript, and images. You can preprocess your assets using Hugo Pipes, enabling features like minification, fingerprinting, and transpiling. This allows you to optimize your site&rsquo;s performance and maintain organized asset management.</p>
<p><strong>Example of Minification Using Hugo Pipes:</strong></p>
<details open>
    <summary>TEXT</summary><pre
        class="codeblock"
      ><code class="language-" data-lang="">{{ $styles := resources.Get &#34;css/styles.css&#34; | minify }}
&lt;link rel=&#34;stylesheet&#34; href=&#34;{{ $styles.Permalink }}&#34;&gt;</code><button onclick="copyCode(this)" class="copybtn">copy</button></pre></details>

  <script>
    function copyCode(btn) {
      const code = btn.previousElementSibling.textContent.trim();
      navigator.clipboard.writeText(code).then(() => {
        btn.innerText = "copied";
        setTimeout(() => (btn.innerText = "copy"), 2000);
      });
    }
  </script><p><strong>Example of Fingerprinting for Cache Busting:</strong></p>
<details open>
    <summary>TEXT</summary><pre
        class="codeblock"
      ><code class="language-" data-lang="">{{ $js := resources.Get &#34;js/script.js&#34; | fingerprint }}
&lt;script src=&#34;{{ $js.Permalink }}&#34;&gt;&lt;/script&gt;</code><button onclick="copyCode(this)" class="copybtn">copy</button></pre></details>

  <script>
    function copyCode(btn) {
      const code = btn.previousElementSibling.textContent.trim();
      navigator.clipboard.writeText(code).then(() => {
        btn.innerText = "copied";
        setTimeout(() => (btn.innerText = "copy"), 2000);
      });
    }
  </script><h3 id="misc">
  <a class="anchor inpage" href="#misc">###</a>misc</h3>
<p>i18n</p>
<h2 id="trick">
  <a class="anchor inpage" href="#trick">##</a>trick</h2>
<h3 id="backlinks">
  <a class="anchor inpage" href="#backlinks">###</a>backlinks</h3>
<h3 id="local-partials">
  <a class="anchor inpage" href="#local-partials">###</a>local partials</h3>
<h3 id="misc-1">
  <a class="anchor inpage" href="#misc-1">###</a>misc</h3>
<p>related</p>
<p>prev next</p>
]]></content:encoded></item><item><title>一些sh脚本</title><link>https://hiraethecho.github.io/docs/dev/scripts-example/</link><pubDate>Sat, 25 Oct 2025 00:00:00 +0000</pubDate><author>wyz2016zxc@outlook.com(Hiraeth)</author><guid>https://hiraethecho.github.io/docs/dev/scripts-example/</guid><description>&lt;h1 id="scripts-example"&gt;
&lt;a class="anchor inpage" href="#scripts-example"&gt;#&lt;/a&gt;scripts example&lt;/h1&gt;
&lt;details open&gt;
&lt;summary&gt;TEXT&lt;/summary&gt;&lt;pre
class="codeblock"
&gt;&lt;code class="language-" data-lang=""&gt;find . -name &amp;#34;*.md&amp;#34; -type f -exec grep -lE &amp;#34;Finished&amp;#34; {} &amp;#43; | while read file; do
if ! grep -q &amp;#34;2025-05-31&amp;#34; &amp;#34;$file&amp;#34;; then
number=$(awk &amp;#39;/^pages: [0-9]&amp;#43;/ {print $2}&amp;#39; &amp;#34;$file&amp;#34;)
if [ -n &amp;#34;$number&amp;#34; ]; then
sed -i &amp;#34;/Finished/i\\- 2025-05-31: $number&amp;#34; &amp;#34;$file&amp;#34;
echo &amp;#34;已处理: $file - 插入: - 2025-05-31: $number&amp;#34;
else
echo &amp;#34;跳过: $file (未找到pages数字或有效日期)&amp;#34;
fi
else
echo &amp;#34;排除: $file (包含 2025-05-31)&amp;#34;
fi
done&lt;/code&gt;&lt;button onclick="copyCode(this)" class="copybtn"&gt;copy&lt;/button&gt;&lt;/pre&gt;&lt;/details&gt;
&lt;script&gt;
function copyCode(btn) {
const code = btn.previousElementSibling.textContent.trim();
navigator.clipboard.writeText(code).then(() =&gt; {
btn.innerText = "copied";
setTimeout(() =&gt; (btn.innerText = "copy"), 2000);
});
}
&lt;/script&gt;&lt;details open&gt;
&lt;summary&gt;TEXT&lt;/summary&gt;&lt;pre
class="codeblock"
&gt;&lt;code class="language-" data-lang=""&gt;# 创建备份和日志
backup_dir=&amp;#34;backup_$(date &amp;#43;%Y%m%d)&amp;#34;
mkdir -p &amp;#34;$backup_dir&amp;#34;
log_file=&amp;#34;replace_log.txt&amp;#34;
echo &amp;#34;开始替换操作 $(date)&amp;#34; &amp;gt; &amp;#34;$log_file&amp;#34;
find . -name &amp;#34;*.md&amp;#34; -type f | while read file; do
# 检查文件是否包含目标字符串
if grep -q &amp;#34;- 2025-06-01: Finished&amp;#34; &amp;#34;$file&amp;#34;; then
# 创建备份
cp &amp;#34;$file&amp;#34; &amp;#34;$backup_dir/$(basename &amp;#34;$file&amp;#34;)&amp;#34;
# 执行替换
sed -i &amp;#39;s/- 2025-06-01: Finished/- 2025-05-31: Finished/g&amp;#39; &amp;#34;$file&amp;#34;
# 记录日志
echo &amp;#34;已修改: $file&amp;#34; &amp;gt;&amp;gt; &amp;#34;$log_file&amp;#34;
# 显示变更
echo &amp;#34;=== $file 修改内容 ===&amp;#34;
diff &amp;#34;$backup_dir/$(basename &amp;#34;$file&amp;#34;)&amp;#34; &amp;#34;$file&amp;#34; || true
else
echo &amp;#34;无修改: $file&amp;#34; &amp;gt;&amp;gt; &amp;#34;$log_file&amp;#34;
fi
done
echo &amp;#34;操作完成，备份在 $backup_dir，日志见 $log_file&amp;#34;&lt;/code&gt;&lt;button onclick="copyCode(this)" class="copybtn"&gt;copy&lt;/button&gt;&lt;/pre&gt;&lt;/details&gt;
&lt;script&gt;
function copyCode(btn) {
const code = btn.previousElementSibling.textContent.trim();
navigator.clipboard.writeText(code).then(() =&gt; {
btn.innerText = "copied";
setTimeout(() =&gt; (btn.innerText = "copy"), 2000);
});
}
&lt;/script&gt;&lt;details open&gt;
&lt;summary&gt;TEXT&lt;/summary&gt;&lt;pre
class="codeblock"
&gt;&lt;code class="language-" data-lang=""&gt;find . -name &amp;#34;*.md&amp;#34; -type f -exec grep -l &amp;#34;lists: book&amp;#34; {} &amp;#43; | \
while read file; do
if ! grep -q &amp;#34;Finished&amp;#34; &amp;#34;$file&amp;#34;; then
# 确保文件末尾有空行（避免追加内容粘连）
[ -n &amp;#34;$(tail -c 1 &amp;#34;$file&amp;#34;)&amp;#34; ] &amp;amp;&amp;amp; echo &amp;gt;&amp;gt; &amp;#34;$file&amp;#34;
# 追加内容
echo &amp;#34;- 2025-06-01: Finished&amp;#34; &amp;gt;&amp;gt; &amp;#34;$file&amp;#34;
echo &amp;#34;已处理: $file&amp;#34;
else
echo &amp;#34;跳过: $file (已包含 Finished)&amp;#34;
fi
done&lt;/code&gt;&lt;button onclick="copyCode(this)" class="copybtn"&gt;copy&lt;/button&gt;&lt;/pre&gt;&lt;/details&gt;
&lt;script&gt;
function copyCode(btn) {
const code = btn.previousElementSibling.textContent.trim();
navigator.clipboard.writeText(code).then(() =&gt; {
btn.innerText = "copied";
setTimeout(() =&gt; (btn.innerText = "copy"), 2000);
});
}
&lt;/script&gt;&lt;details open&gt;
&lt;summary&gt;TEXT&lt;/summary&gt;&lt;pre
class="codeblock"
&gt;&lt;code class="language-" data-lang=""&gt;find . -name &amp;#34;*.md&amp;#34; -type f -exec grep -L &amp;#34;Finished&amp;#34; {} &amp;#43; | while read file; do
awk &amp;#39;BEGIN {done=0} /^---/ &amp;amp;&amp;amp; !done {print; print &amp;#34;- 2025-06-01: Finished&amp;#34;; done=1; next} 1&amp;#39; &amp;#34;$file&amp;#34; &amp;gt; tmp &amp;amp;&amp;amp; mv tmp &amp;#34;$file&amp;#34;
done&lt;/code&gt;&lt;button onclick="copyCode(this)" class="copybtn"&gt;copy&lt;/button&gt;&lt;/pre&gt;&lt;/details&gt;
&lt;script&gt;
function copyCode(btn) {
const code = btn.previousElementSibling.textContent.trim();
navigator.clipboard.writeText(code).then(() =&gt; {
btn.innerText = "copied";
setTimeout(() =&gt; (btn.innerText = "copy"), 2000);
});
}
&lt;/script&gt;</description><content:encoded><![CDATA[<h1 id="scripts-example">
  <a class="anchor inpage" href="#scripts-example">#</a>scripts example</h1>
<details open>
    <summary>TEXT</summary><pre
        class="codeblock"
      ><code class="language-" data-lang="">find . -name &#34;*.md&#34; -type f -exec grep -lE &#34;Finished&#34; {} &#43; | while read file; do
  if ! grep -q &#34;2025-05-31&#34; &#34;$file&#34;; then
    number=$(awk &#39;/^pages: [0-9]&#43;/ {print $2}&#39; &#34;$file&#34;)
    if [ -n &#34;$number&#34; ]; then
      sed -i &#34;/Finished/i\\- 2025-05-31: $number&#34; &#34;$file&#34;
      echo &#34;已处理: $file - 插入: - 2025-05-31: $number&#34;
    else
      echo &#34;跳过: $file (未找到pages数字或有效日期)&#34;
    fi
  else
    echo &#34;排除: $file (包含 2025-05-31)&#34;
  fi
done</code><button onclick="copyCode(this)" class="copybtn">copy</button></pre></details>

  <script>
    function copyCode(btn) {
      const code = btn.previousElementSibling.textContent.trim();
      navigator.clipboard.writeText(code).then(() => {
        btn.innerText = "copied";
        setTimeout(() => (btn.innerText = "copy"), 2000);
      });
    }
  </script><details open>
    <summary>TEXT</summary><pre
        class="codeblock"
      ><code class="language-" data-lang=""># 创建备份和日志
backup_dir=&#34;backup_$(date &#43;%Y%m%d)&#34;
mkdir -p &#34;$backup_dir&#34;
log_file=&#34;replace_log.txt&#34;

echo &#34;开始替换操作 $(date)&#34; &gt; &#34;$log_file&#34;

find . -name &#34;*.md&#34; -type f | while read file; do
    # 检查文件是否包含目标字符串
    if grep -q &#34;- 2025-06-01: Finished&#34; &#34;$file&#34;; then
        # 创建备份
        cp &#34;$file&#34; &#34;$backup_dir/$(basename &#34;$file&#34;)&#34;
        # 执行替换
        sed -i &#39;s/- 2025-06-01: Finished/- 2025-05-31: Finished/g&#39; &#34;$file&#34;
        # 记录日志
        echo &#34;已修改: $file&#34; &gt;&gt; &#34;$log_file&#34;
        # 显示变更
        echo &#34;=== $file 修改内容 ===&#34;
        diff &#34;$backup_dir/$(basename &#34;$file&#34;)&#34; &#34;$file&#34; || true
    else
        echo &#34;无修改: $file&#34; &gt;&gt; &#34;$log_file&#34;
    fi
done

echo &#34;操作完成，备份在 $backup_dir，日志见 $log_file&#34;</code><button onclick="copyCode(this)" class="copybtn">copy</button></pre></details>

  <script>
    function copyCode(btn) {
      const code = btn.previousElementSibling.textContent.trim();
      navigator.clipboard.writeText(code).then(() => {
        btn.innerText = "copied";
        setTimeout(() => (btn.innerText = "copy"), 2000);
      });
    }
  </script><details open>
    <summary>TEXT</summary><pre
        class="codeblock"
      ><code class="language-" data-lang="">find . -name &#34;*.md&#34; -type f -exec grep -l &#34;lists: book&#34; {} &#43; | \
while read file; do
    if ! grep -q &#34;Finished&#34; &#34;$file&#34;; then
        # 确保文件末尾有空行（避免追加内容粘连）
        [ -n &#34;$(tail -c 1 &#34;$file&#34;)&#34; ] &amp;&amp; echo &gt;&gt; &#34;$file&#34;
        # 追加内容
        echo &#34;- 2025-06-01: Finished&#34; &gt;&gt; &#34;$file&#34;
        echo &#34;已处理: $file&#34;
    else
        echo &#34;跳过: $file (已包含 Finished)&#34;
    fi
done</code><button onclick="copyCode(this)" class="copybtn">copy</button></pre></details>

  <script>
    function copyCode(btn) {
      const code = btn.previousElementSibling.textContent.trim();
      navigator.clipboard.writeText(code).then(() => {
        btn.innerText = "copied";
        setTimeout(() => (btn.innerText = "copy"), 2000);
      });
    }
  </script><details open>
    <summary>TEXT</summary><pre
        class="codeblock"
      ><code class="language-" data-lang="">find . -name &#34;*.md&#34; -type f -exec grep -L &#34;Finished&#34; {} &#43; | while read file; do
    awk &#39;BEGIN {done=0} /^---/ &amp;&amp; !done {print; print &#34;- 2025-06-01: Finished&#34;; done=1; next} 1&#39; &#34;$file&#34; &gt; tmp &amp;&amp; mv tmp &#34;$file&#34;
done</code><button onclick="copyCode(this)" class="copybtn">copy</button></pre></details>

  <script>
    function copyCode(btn) {
      const code = btn.previousElementSibling.textContent.trim();
      navigator.clipboard.writeText(code).then(() => {
        btn.innerText = "copied";
        setTimeout(() => (btn.innerText = "copy"), 2000);
      });
    }
  </script>]]></content:encoded></item><item><title>cli收集</title><link>https://hiraethecho.github.io/docs/dev/cli/</link><pubDate>Thu, 23 Oct 2025 00:00:00 +0000</pubDate><author>wyz2016zxc@outlook.com(Hiraeth)</author><guid>https://hiraethecho.github.io/docs/dev/cli/</guid><description>收集一些cli的命令工具用法</description><content:encoded><![CDATA[<h1 id="cli收集">
  <a class="anchor inpage" href="#cli%e6%94%b6%e9%9b%86">#</a>cli收集</h1>
<h2 id="utils">
  <a class="anchor inpage" href="#utils">##</a>utils</h2>
<p>一些基础的，常常是系统自带的命令工具。</p>
<h3 id="chattr">
  <a class="anchor inpage" href="#chattr">###</a>chattr</h3>
<details open>
    <summary>TEXT</summary><pre
        class="codeblock"
      ><code class="language-" data-lang="">sudo chattr &#43;i /etc/resolv.conf  # 设置文件不可修改
sudo chattr -i /etc/resolv.conf  # 解除</code><button onclick="copyCode(this)" class="copybtn">copy</button></pre></details>

  <script>
    function copyCode(btn) {
      const code = btn.previousElementSibling.textContent.trim();
      navigator.clipboard.writeText(code).then(() => {
        btn.innerText = "copied";
        setTimeout(() => (btn.innerText = "copy"), 2000);
      });
    }
  </script><h3 id="file">
  <a class="anchor inpage" href="#file">###</a>file</h3>
<p>use following to find file type. <code>-L</code> means follow the symbolic link</p>
<details open>
    <summary>TEXT</summary><pre
        class="codeblock"
      ><code class="language-" data-lang="">file --mime-type -L file</code><button onclick="copyCode(this)" class="copybtn">copy</button></pre></details>

  <script>
    function copyCode(btn) {
      const code = btn.previousElementSibling.textContent.trim();
      navigator.clipboard.writeText(code).then(() => {
        btn.innerText = "copied";
        setTimeout(() => (btn.innerText = "copy"), 2000);
      });
    }
  </script><p>use following shell scripts to set mime (need rofi)</p>
<details open>
    <summary>sh</summary><pre
        class="chroma codeblock"
      ><code class="language-sh" data-lang="sh"
          ><span style="display:flex;"><span><span style="color:#75715e">#!/bin/sh
</span></span></span><span style="display:flex;"><span><span style="color:#75715e"></span>
</span></span><span style="display:flex;"><span>FILETYPE<span style="color:#f92672">=</span><span style="color:#66d9ef">$(</span>xdg-mime query filetype $1<span style="color:#66d9ef">)</span>
</span></span><span style="display:flex;"><span>APP<span style="color:#f92672">=</span><span style="color:#66d9ef">$(</span> find /usr/share -type f -name <span style="color:#e6db74">&#34;*.desktop&#34;</span> -printf <span style="color:#e6db74">&#34;%p\n&#34;</span> | sed <span style="color:#e6db74">&#39;s/\/.*\///g&#39;</span> | rofi -threads <span style="color:#ae81ff">0</span> -dmenu -i -p <span style="color:#e6db74">&#34;select default app&#34;</span><span style="color:#66d9ef">)</span>
</span></span><span style="display:flex;"><span>echo $APP
</span></span><span style="display:flex;"><span>xdg-mime default <span style="color:#e6db74">&#34;</span>$APP<span style="color:#e6db74">&#34;</span> <span style="color:#e6db74">&#34;</span>$FILETYPE<span style="color:#e6db74">&#34;</span>
</span></span><span style="display:flex;"><span>echo <span style="color:#e6db74">&#34;</span>$APP<span style="color:#e6db74"> set as default application to open </span>$FILETYPE<span style="color:#e6db74">&#34;</span></span></span></code
        ><button onclick="copyCode(this)" class="copybtn">copy</button></pre></details>

  <script>
    function copyCode(btn) {
      const code = btn.previousElementSibling.textContent.trim();
      navigator.clipboard.writeText(code).then(() => {
        btn.innerText = "copied";
        setTimeout(() => (btn.innerText = "copy"), 2000);
      });
    }
  </script><h3 id="stat">
  <a class="anchor inpage" href="#stat">###</a>stat</h3>
<p><code>stat</code>展示文件状态，例如</p>
<details open>
    <summary>TEXT</summary><pre
        class="codeblock"
      ><code class="language-" data-lang="">stat /

  File: /
  Size: 122       	Blocks: 0          IO Block: 4096   directory
Device: 0,28	Inode: 256         Links: 1
Access: (0755/drwxr-xr-x)  Uid: (    0/    root)   Gid: (    0/    root)
Access: 2025-05-10 23:46:03.122616066 &#43;0800
Modify: 2025-05-11 21:26:49.474145593 &#43;0800
Change: 2025-05-11 21:26:49.474145593 &#43;0800
 Birth: 2025-01-01 14:58:38.377746860 &#43;0800</code><button onclick="copyCode(this)" class="copybtn">copy</button></pre></details>

  <script>
    function copyCode(btn) {
      const code = btn.previousElementSibling.textContent.trim();
      navigator.clipboard.writeText(code).then(() => {
        btn.innerText = "copied";
        setTimeout(() => (btn.innerText = "copy"), 2000);
      });
    }
  </script><h3 id="type">
  <a class="anchor inpage" href="#type">###</a>type</h3>
<details open>
    <summary>TEXT</summary><pre
        class="codeblock"
      ><code class="language-" data-lang="">  Display the type of command the shell will execute.
  Note: All examples are not POSIX compliant.
  More information: &lt;https://www.gnu.org/software/bash/manual/bash.html#index-type&gt;.

  Display the type of a command:

      type command

  Display all locations containing the specified executable (works only in Bash/fish/Zsh shells):

      type -a command

  Display the name of the disk file that would be executed (works only in Bash/fish/Zsh shells):

      type -p command

  Display the type of a specific command, alias/keyword/function/builtin/file (works only in Bash/fish shells):

      type -t command</code><button onclick="copyCode(this)" class="copybtn">copy</button></pre></details>

  <script>
    function copyCode(btn) {
      const code = btn.previousElementSibling.textContent.trim();
      navigator.clipboard.writeText(code).then(() => {
        btn.innerText = "copied";
        setTimeout(() => (btn.innerText = "copy"), 2000);
      });
    }
  </script><h3 id="date">
  <a class="anchor inpage" href="#date">###</a>date</h3>
<details open>
    <summary>TEXT</summary><pre
        class="codeblock"
      ><code class="language-" data-lang="">Usage: date [OPTION]... [&#43;FORMAT]
  or:  date [-u|--utc|--universal] [MMDDhhmm[[CC]YY][.ss]]
Display date and time in the given FORMAT.
With -s, or with [MMDDhhmm[[CC]YY][.ss]], set the date and time.

Mandatory arguments to long options are mandatory for short options too.
  -d, --date=STRING          display time described by STRING, not &#39;now&#39;
      --debug                annotate the parsed date,
                              and warn about questionable usage to stderr
  -f, --file=DATEFILE        like --date; once for each line of DATEFILE
  -I[FMT], --iso-8601[=FMT]  output date/time in ISO 8601 format.
                               FMT=&#39;date&#39; for date only (the default),
                               &#39;hours&#39;, &#39;minutes&#39;, &#39;seconds&#39;, or &#39;ns&#39;
                               for date and time to the indicated precision.
                               Example: 2006-08-14T02:34:56-06:00
  --resolution               output the available resolution of timestamps
                               Example: 0.000000001
  -R, --rfc-email            output date and time in RFC 5322 format.
                               Example: Mon, 14 Aug 2006 02:34:56 -0600
      --rfc-3339=FMT         output date/time in RFC 3339 format.
                               FMT=&#39;date&#39;, &#39;seconds&#39;, or &#39;ns&#39;
                               for date and time to the indicated precision.
                               Example: 2006-08-14 02:34:56-06:00
  -r, --reference=FILE       display the last modification time of FILE
  -s, --set=STRING           set time described by STRING
  -u, --utc, --universal     print or set Coordinated Universal Time (UTC)
      --help        display this help and exit
      --version     output version information and exit

All options that specify the date to display are mutually exclusive.
I.e.: --date, --file, --reference, --resolution.

FORMAT controls the output.  Interpreted sequences are:

  %%   a literal %
  %a   locale&#39;s abbreviated weekday name (e.g., Sun)
  %A   locale&#39;s full weekday name (e.g., Sunday)
  %b   locale&#39;s abbreviated month name (e.g., Jan)
  %B   locale&#39;s full month name (e.g., January)
  %c   locale&#39;s date and time (e.g., Thu Mar  3 23:05:25 2005)
  %C   century; like %Y, except omit last two digits (e.g., 20)
  %d   day of month (e.g., 01)
  %D   date (ambiguous); same as %m/%d/%y
  %e   day of month, space padded; same as %_d
  %F   full date; like %&#43;4Y-%m-%d
  %g   last two digits of year of ISO week number (ambiguous; 00-99); see %G
  %G   year of ISO week number; normally useful only with %V
  %h   same as %b
  %H   hour (00..23)
  %I   hour (01..12)
  %j   day of year (001..366)
  %k   hour, space padded ( 0..23); same as %_H
  %l   hour, space padded ( 1..12); same as %_I
  %m   month (01..12)
  %M   minute (00..59)
  %n   a newline
  %N   nanoseconds (000000000..999999999)
  %p   locale&#39;s equivalent of either AM or PM; blank if not known
  %P   like %p, but lower case
  %q   quarter of year (1..4)
  %r   locale&#39;s 12-hour clock time (e.g., 11:11:04 PM)
  %R   24-hour hour and minute; same as %H:%M
  %s   seconds since the Epoch (1970-01-01 00:00 UTC)
  %S   second (00..60)
  %t   a tab
  %T   time; same as %H:%M:%S
  %u   day of week (1..7); 1 is Monday
  %U   week number of year, with Sunday as first day of week (00..53)
  %V   ISO week number, with Monday as first day of week (01..53)
  %w   day of week (0..6); 0 is Sunday
  %W   week number of year, with Monday as first day of week (00..53)
  %x   locale&#39;s date (can be ambiguous; e.g., 12/31/99)
  %X   locale&#39;s time representation (e.g., 23:13:48)
  %y   last two digits of year (ambiguous; 00..99)
  %Y   year
  %z   &#43;hhmm numeric time zone (e.g., -0400)
  %:z  &#43;hh:mm numeric time zone (e.g., -04:00)
  %::z  &#43;hh:mm:ss numeric time zone (e.g., -04:00:00)
  %:::z  numeric time zone with : to necessary precision (e.g., -04, &#43;05:30)
  %Z   alphabetic time zone abbreviation (e.g., EDT)

By default, date pads numeric fields with zeroes.
The following optional flags may follow &#39;%&#39;:

  -  (hyphen) do not pad the field
  _  (underscore) pad with spaces
  0  (zero) pad with zeros
  &#43;  pad with zeros, and put &#39;&#43;&#39; before future years with &gt;4 digits
  ^  use upper case if possible
  #  use opposite case if possible

After any flags comes an optional field width, as a decimal number;
then an optional modifier, which is either
E to use the locale&#39;s alternate representations if available, or
O to use the locale&#39;s alternate numeric symbols if available.

Examples:
Convert seconds since the Epoch (1970-01-01 UTC) to a date
  $ date --date=&#39;@2147483647&#39;

Show the time on the west coast of the US (use tzselect(1) to find TZ)
  $ TZ=&#39;America/Los_Angeles&#39; date

Show the local time for 9AM next Friday on the west coast of the US
  $ date --date=&#39;TZ=&#34;America/Los_Angeles&#34; 09:00 next Fri&#39;</code><button onclick="copyCode(this)" class="copybtn">copy</button></pre></details>

  <script>
    function copyCode(btn) {
      const code = btn.previousElementSibling.textContent.trim();
      navigator.clipboard.writeText(code).then(() => {
        btn.innerText = "copied";
        setTimeout(() => (btn.innerText = "copy"), 2000);
      });
    }
  </script><h2 id="tricks">
  <a class="anchor inpage" href="#tricks">##</a>tricks</h2>
<p>后台挂起</p>
<details open>
    <summary>sh</summary><pre
        class="chroma codeblock"
      ><code class="language-sh" data-lang="sh"
          ><span style="display:flex;"><span>nohup onedrivegui &amp; &gt; /dev/null</span></span></code
        ><button onclick="copyCode(this)" class="copybtn">copy</button></pre></details>

  <script>
    function copyCode(btn) {
      const code = btn.previousElementSibling.textContent.trim();
      navigator.clipboard.writeText(code).then(() => {
        btn.innerText = "copied";
        setTimeout(() => (btn.innerText = "copy"), 2000);
      });
    }
  </script>]]></content:encoded></item><item><title>探索ai时遇到的混乱</title><link>https://hiraethecho.github.io/docs/dev/opencode/</link><pubDate>Wed, 30 Jul 2025 00:00:00 +0000</pubDate><author>wyz2016zxc@outlook.com(Hiraeth)</author><guid>https://hiraethecho.github.io/docs/dev/opencode/</guid><description>玩llm，agent，mcp，感到一些混乱</description><content:encoded><![CDATA[<h1 id="一团乱麻的ai">
  <a class="anchor inpage" href="#%e4%b8%80%e5%9b%a2%e4%b9%b1%e9%ba%bb%e7%9a%84ai">#</a>一团乱麻的ai</h1>
<h2 id="cli">
  <a class="anchor inpage" href="#cli">##</a>cli</h2>
<p>在搞一些cli下的agent，发现一个开源的opencode，以及它在nvim的插件。结果</p>
<ul>
<li>两个不同的插件都叫<code>opencode.nvim</code>，于是lazyvim对同名插件支持有问题。用<code>name</code>修改其中一个为<code>opencode-nvim</code>后，似乎<code>require(&quot;opencode.nvim&quot;)</code>会出问题。disable掉其中一个都不行，必须去掉一个插件，并且手动删除插件，重新下载才行。</li>
<li>发现其中一个<code>opencode.nvim</code>是用<code>goose.nvim</code>改的，<code>goose</code>是另一个cli的agent，但是aur里<code>goose</code>包是个<code>Database migration tool written in Go</code>，我要的<code>goose</code>包名是<code>codename-goose</code></li>
<li>再之后发现还有另一个<code>opencode-ai/opencode</code>，一开始找的有插件的是<code>sst/opencode</code>，以及7/30突然前者<code>archive</code>停止开发了。</li>
<li>吃了个瓜发现一开始是<code>opencode-ai/opencode</code>，后来其中一批人想卖给公司，虽然承诺继续开源；另一批人不愿意，跑出去做了<code>sst/opencode</code>。再之后前者又搞了个新的<code>crush</code></li>
</ul>
<h2 id="llm">
  <a class="anchor inpage" href="#llm">##</a>llm</h2>
<p>我的llm来源，有个本地拉跨的ollama，然后deepseek充值了巨资五元人民币。还有<code>openroute</code>一堆免费模型，但是似乎额度在变少。<code>通义灵码</code>似乎免费开放了某个版本的<code>qwen3-coder</code>，刚出来的时候有人在吹，过两天又有人喷。我最好用的是github-copilot，教育优惠爽啊</p>
<h2 id="ide">
  <a class="anchor inpage" href="#ide">##</a>ide</h2>
<p>nvim上好几个，都用起来有点费劲。</p>
<p>vscode上有官方的copilot，然后有好用的cline。还有个ali的通义灵码，在我家目录拉屎，有点烦。</p>
<h2 id="mcp">
  <a class="anchor inpage" href="#mcp">##</a>mcp</h2>
<p>配置有两三种格式，而且还不太方便放在一个位置，有点烦</p>
<p>uvx和npx都产生好多cache类的东西，赛博洁癖感到痛苦</p>
<h2 id="app">
  <a class="anchor inpage" href="#app">##</a>app</h2>
<p>chatbox 和 cherrystudio，都是home到处拉屎，烦人</p>
<p>provider也不好配，mcp也不好配</p>
]]></content:encoded></item><item><title>大模型使用概览</title><link>https://hiraethecho.github.io/docs/dev/ai-overview/</link><pubDate>Tue, 22 Jul 2025 00:00:00 +0000</pubDate><author>wyz2016zxc@outlook.com(Hiraeth)</author><guid>https://hiraethecho.github.io/docs/dev/ai-overview/</guid><description>&lt;h1 id="概览"&gt;
&lt;a class="anchor inpage" href="#%e6%a6%82%e8%a7%88"&gt;#&lt;/a&gt;概览&lt;/h1&gt;
&lt;p&gt;使用大模型的能力，根据用户提供的知识库，调用某些工具，来实现用户的需求。
他们合为一个智能体（agent）。&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;使用大模型的能力，需要一个LLM&lt;/li&gt;
&lt;li&gt;获取用户的知识库，需要RAG&lt;/li&gt;
&lt;li&gt;调用工具（function call），可以用mcp&lt;/li&gt;
&lt;/ul&gt;
&lt;h2 id="agents"&gt;
&lt;a class="anchor inpage" href="#agents"&gt;##&lt;/a&gt;agents&lt;/h2&gt;
&lt;h3 id="cli-tools"&gt;
&lt;a class="anchor inpage" href="#cli-tools"&gt;###&lt;/a&gt;CLI Tools&lt;/h3&gt;
&lt;p&gt;命令行环境&lt;/p&gt;</description><content:encoded><![CDATA[<h1 id="概览">
  <a class="anchor inpage" href="#%e6%a6%82%e8%a7%88">#</a>概览</h1>
<p>使用大模型的能力，根据用户提供的知识库，调用某些工具，来实现用户的需求。
他们合为一个智能体（agent）。</p>
<ul>
<li>使用大模型的能力，需要一个LLM</li>
<li>获取用户的知识库，需要RAG</li>
<li>调用工具（function call），可以用mcp</li>
</ul>
<h2 id="agents">
  <a class="anchor inpage" href="#agents">##</a>agents</h2>
<h3 id="cli-tools">
  <a class="anchor inpage" href="#cli-tools">###</a>CLI Tools</h3>
<p>命令行环境</p>
<ul>
<li>private
<ul>
<li>gemini-cli Google Gemini 命令行工具，支持多模态交互与自动化。</li>
<li>claude code Anthropic Claude CLI，适用于安全高效的对话与文档处理。</li>
<li>qwen code开源了</li>
</ul>
</li>
<li>opensource
<ul>
<li>opencode 
</li>
<li>crush 
 这两个本来
，然后分支了，后者被<code>charm</code>买了。</li>
<li>
</li>
</ul>
</li>
</ul>
<p>基本上每个开发团队都有它们自己的cli，当然也主要对接自家llm。至于开源的三个，支持的模型和provider各不相同。<code>crush</code>暂时还不支持<code>github copilot</code>，但是可以配置<code>lsp</code>，比较有特色。</p>
<ul>
<li>goose</li>
<li>opencode</li>
<li>gemini</li>
<li>claude</li>
<li>crush</li>
<li>codex</li>
<li>aichat</li>
<li>auggie</li>
<li>cursor-agent</li>
</ul>
<h3 id="ides">
  <a class="anchor inpage" href="#ides">###</a>IDEs</h3>
<table>
  <thead>
      <tr>
          <th></th>
          <th>nvim</th>
          <th>vscode</th>
          <th>cursor</th>
      </tr>
  </thead>
  <tbody>
      <tr>
          <td>native</td>
          <td>用内置terminal</td>
          <td>copilot</td>
          <td>yes</td>
      </tr>
      <tr>
          <td>plugin</td>
          <td>avante, CodeCompanion</td>
          <td>cline, ligma</td>
          <td></td>
      </tr>
      <tr>
          <td>cli</td>
          <td>opencode, goose</td>
          <td></td>
          <td></td>
      </tr>
  </tbody>
</table>
<p>nvim的
</p>
<h3 id="desktop-applications">
  <a class="anchor inpage" href="#desktop-applications">###</a>Desktop Applications</h3>
<p>桌面客户端。</p>
<ul>
<li>cherry studio 
。自带一些ai网站，deepseek之类的。但是用electron，有点难受。</li>
<li>chatbox 
。和cherry studio差不多</li>
<li>dify 开源 AI 应用开发与管理平台。特色是低代码。官网：
</li>
<li>open-webui：支持多模型的开源 Web UI，需要浏览器。为ollama设计。
</li>
</ul>
<h2 id="llm-large-language-models">
  <a class="anchor inpage" href="#llm-large-language-models">##</a>LLM (Large Language Models)</h2>
<h3 id="developers-and-models">
  <a class="anchor inpage" href="#developers-and-models">###</a>Developers and Models</h3>
<ul>
<li>
<p><strong>Gemini</strong><br>
Google DeepMind 推出的 Gemini 系列是 Google 旗下最先进的大语言模型，具备多模态理解、超长上下文、强推理和代码能力，广泛应用于搜索、助手、开发等场景。Gemini 2.5 Pro/Flash/Flash-Lite 等模型已开放 API 和网页端体验。<br>
官网：
</p>
</li>
<li>
<p><strong>claude</strong><br>
Claude 是由 Anthropic 推出的先进大语言模型，主打安全、可控和高效，广泛应用于对话、代码、文档处理等场景。最新模型包括 Claude Opus 4、Sonnet 4、Haiku 3.5 等，支持 API、网页端和多平台集成。<br>
官网：
</p>
</li>
<li>
<p><strong>openai</strong><br>
OpenAI 是全球领先的人工智能研究与应用公司，推出了 GPT-4o、ChatGPT、Sora 等多项前沿大模型及产品，广泛应用于自然语言处理、代码生成、图像与视频生成等领域。<br>
官网：
</p>
</li>
<li>
<p><strong>deepseek</strong><br>
DeepSeek（深度求索）是中国领先的开源大模型团队，推出 DeepSeek R1、V3、Coder、Math、VL 等多款大语言模型，支持多语言、代码、数学、视觉等多场景，开放 API、网页端和 App。<br>
官网：
</p>
</li>
<li>
<p><strong>kimi</strong><br>
Kimi 智能助手由 Moonshot AI（月之暗面）推出，主打超长上下文、强推理和多模态能力，适用于文档解析、知识问答、写作、代码等多场景，支持网页端和 API。<br>
官网：
</p>
</li>
<li>
<p><strong>qwen</strong><br>
通义千问是阿里云推出的多模态大模型，具备文本、图像、音频等多种能力，广泛应用于办公、开发、教育等领域，支持 API、网页端和企业集成。<br>
官网：
</p>
</li>
</ul>
<h3 id="providers">
  <a class="anchor inpage" href="#providers">###</a>Providers</h3>
<ul>
<li>多模型合集
<ul>
<li>OpenRouter 是一个统一的 LLM API 聚合平台，支持 OpenAI、Google、Anthropic、DeepSeek、Moonshot 等数百种主流大模型，提供统一接口、灵活计费和高可用性，适合开发者和企业多模型接入。官网：
</li>
<li>硅基流动</li>
<li>github copilot （有大学生认证的话这个最好用）</li>
</ul>
</li>
<li>专用
<ul>
<li>deepseek</li>
<li>gemini之类的</li>
</ul>
</li>
<li>本地
</li>
</ul>
<h3 id="capabilities">
  <a class="anchor inpage" href="#capabilities">###</a>Capabilities</h3>
<ul>
<li>chat：就聊天</li>
<li>coder：为代码编写和调试提供支持，通常包括代码生成、错误修复、代码重构等功能。</li>
<li>completion：代码补全，类似snippet</li>
<li>tool：调用工具，function call。有些纯chat的用不了。</li>
</ul>
<h2 id="mcp">
  <a class="anchor inpage" href="#mcp">##</a>mcp</h2>
<p>mcp-hub 可以把多个mcp整合为一个mcp，这样调用<code>mcp-hub</code>的mcp相当于调用多个mcp。</p>
<ul>
<li>npx</li>
<li>uvx</li>
</ul>
<h2 id="rag">
  <a class="anchor inpage" href="#rag">##</a>rag</h2>
<h2 id="others">
  <a class="anchor inpage" href="#others">##</a>others</h2>
<p>
</p>
<p>用
来把github copilot包装成 OpenAI 或 Anthropic的格式，然后被调用。</p>
]]></content:encoded></item><item><title>薅羊毛cloudflare</title><link>https://hiraethecho.github.io/docs/dev/cloudflare/</link><pubDate>Sun, 20 Jul 2025 00:00:00 +0000</pubDate><author>wyz2016zxc@outlook.com(Hiraeth)</author><guid>https://hiraethecho.github.io/docs/dev/cloudflare/</guid><description>&lt;h1 id="cloudflare的功能"&gt;
&lt;a class="anchor inpage" href="#cloudflare%e7%9a%84%e5%8a%9f%e8%83%bd"&gt;#&lt;/a&gt;cloudflare的功能&lt;/h1&gt;
&lt;h2 id="安全防护"&gt;
&lt;a class="anchor inpage" href="#%e5%ae%89%e5%85%a8%e9%98%b2%e6%8a%a4"&gt;##&lt;/a&gt;安全防护&lt;/h2&gt;
&lt;p&gt;Cloudflare 提供全球领先的安全解决方案，保护网站和用户免受攻击：&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;&lt;strong&gt;Web 应用防火墙 (WAF)&lt;/strong&gt;：实时阻止恶意流量，防止常见攻击如 SQL 注入和跨站脚本攻击。&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;DDoS 防护&lt;/strong&gt;：自动检测并缓解大规模分布式拒绝服务攻击。&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Bot 管理&lt;/strong&gt;：区分合法用户和恶意机器人，防止数据抓取或资源滥用。&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;SSL/TLS 加密&lt;/strong&gt;：通过一键启用 HTTPS 提供网站加密，确保数据传输安全。&lt;/li&gt;
&lt;/ol&gt;
&lt;h2 id="流量管理"&gt;
&lt;a class="anchor inpage" href="#%e6%b5%81%e9%87%8f%e7%ae%a1%e7%90%86"&gt;##&lt;/a&gt;流量管理&lt;/h2&gt;
&lt;p&gt;Cloudflare 的流量管理服务帮助用户优化请求路径，提高访问速度：&lt;/p&gt;</description><content:encoded><![CDATA[<h1 id="cloudflare的功能">
  <a class="anchor inpage" href="#cloudflare%e7%9a%84%e5%8a%9f%e8%83%bd">#</a>cloudflare的功能</h1>
<h2 id="安全防护">
  <a class="anchor inpage" href="#%e5%ae%89%e5%85%a8%e9%98%b2%e6%8a%a4">##</a>安全防护</h2>
<p>Cloudflare 提供全球领先的安全解决方案，保护网站和用户免受攻击：</p>
<ol>
<li><strong>Web 应用防火墙 (WAF)</strong>：实时阻止恶意流量，防止常见攻击如 SQL 注入和跨站脚本攻击。</li>
<li><strong>DDoS 防护</strong>：自动检测并缓解大规模分布式拒绝服务攻击。</li>
<li><strong>Bot 管理</strong>：区分合法用户和恶意机器人，防止数据抓取或资源滥用。</li>
<li><strong>SSL/TLS 加密</strong>：通过一键启用 HTTPS 提供网站加密，确保数据传输安全。</li>
</ol>
<h2 id="流量管理">
  <a class="anchor inpage" href="#%e6%b5%81%e9%87%8f%e7%ae%a1%e7%90%86">##</a>流量管理</h2>
<p>Cloudflare 的流量管理服务帮助用户优化请求路径，提高访问速度：</p>
<ol>
<li><strong>负载均衡</strong>：分配流量到不同的服务器或数据中心，确保高可用性和可靠性。</li>
<li><strong>Argo 智能路由</strong>：利用 Cloudflare 网络的实时数据，为请求选择最快的路径。</li>
<li><strong>内容分发网络 (CDN)</strong>：缓存静态资源，提高全球访问速度并减少服务器负载。</li>
</ol>
<h2 id="分析与监控">
  <a class="anchor inpage" href="#%e5%88%86%e6%9e%90%e4%b8%8e%e7%9b%91%e6%8e%a7">##</a>分析与监控</h2>
<p>Cloudflare 提供详细的分析工具，帮助用户了解网站流量和性能：</p>
<ol>
<li><strong>实时分析</strong>：显示实时流量、威胁拦截和性能数据。</li>
<li><strong>日志访问</strong>：通过 API 提供详细的请求日志，支持高级分析和故障排查。</li>
<li><strong>用户洞察</strong>：了解访客的地理位置、设备类型和行为数据。</li>
</ol>
<h2 id="dns">
  <a class="anchor inpage" href="#dns">##</a>DNS</h2>
<p>添加 DNS 记录是 Cloudflare 的核心功能之一，可以使其他人访问某个 URL 时解析到特定位置。</p>
<h3 id="如何添加-dns-记录">
  <a class="anchor inpage" href="#%e5%a6%82%e4%bd%95%e6%b7%bb%e5%8a%a0-dns-%e8%ae%b0%e5%bd%95">###</a>如何添加 DNS 记录</h3>
<ol>
<li>登录到 
。</li>
<li>选择需要管理的域名。</li>
<li>导航到 <strong>DNS</strong> 页面。</li>
<li>点击 <strong>添加记录 (Add Record)</strong> 按钮。</li>
<li>填写以下信息：
<ul>
<li><strong>记录类型 (Type)</strong>：如 A、CNAME、MX 等。</li>
<li><strong>名称 (Name)</strong>：子域名或主域名。</li>
<li><strong>内容 (Content)</strong>：目标地址，例如 IP 或 URL。</li>
<li><strong>TTL (生存时间)</strong>：可选，通常默认即可。</li>
</ul>
</li>
<li>保存更改后，记录会立即生效。</li>
</ol>
<h3 id="支持的服务">
  <a class="anchor inpage" href="#%e6%94%af%e6%8c%81%e7%9a%84%e6%9c%8d%e5%8a%a1">###</a>支持的服务</h3>
<ul>
<li><strong>Cloudflare 内服务</strong>：如桶存储、Zero Trust Tunnel、Workers and Pages、Email 服务等，通常自动添加记录。</li>
<li><strong>Cloudflare 外服务</strong>：如服务器、Netlify、Vercel 等服务，用户可以手动配置。</li>
</ul>
<p>通过精准和高效的 DNS 管理，Cloudflare 提升了域名解析的速度和可靠性。</p>
<h2 id="zero-trust">
  <a class="anchor inpage" href="#zero-trust">##</a>zero trust</h2>
<p>Cloudflare Zero Trust 提供了一种现代化的网络安全解决方案，可以保护用户、设备和应用程序的安全访问。其主要特性包括：</p>
<ol>
<li><strong>身份验证</strong>：通过集成身份提供商（如 Okta、Google Workspace），可以确保只有授权用户才能访问资源。</li>
<li><strong>应用程序访问</strong>：无需 VPN，用户可以通过 Cloudflare Access 安全地访问内部应用程序。</li>
<li><strong>威胁防护</strong>：利用 DNS 过滤和浏览器隔离技术，阻止恶意软件、钓鱼攻击等威胁。</li>
<li><strong>设备管理</strong>：通过 Cloudflare Gateway 支持设备的安全策略和流量监控。</li>
</ol>
<h3 id="使用场景">
  <a class="anchor inpage" href="#%e4%bd%bf%e7%94%a8%e5%9c%ba%e6%99%af">###</a>使用场景</h3>
<ul>
<li><strong>远程办公</strong>：为分布式团队提供安全的资源访问。</li>
<li><strong>零信任架构迁移</strong>：逐步替代传统的网络边界安全模型。</li>
<li><strong>第三方访问控制</strong>：为合作伙伴或供应商提供安全的访问权限。</li>
</ul>
<h3 id="配置方法">
  <a class="anchor inpage" href="#%e9%85%8d%e7%bd%ae%e6%96%b9%e6%b3%95">###</a>配置方法</h3>
<ol>
<li>登录到 
。</li>
<li>设置身份验证规则，选择身份提供商。</li>
<li>配置应用程序访问策略，指定允许访问的用户和条件。</li>
<li>启用威胁防护功能，根据需要调整策略。</li>
</ol>
<p>通过 Zero Trust，企业可以显著提升安全性，同时简化资源访问的流程。</p>
<h2 id="存储">
  <a class="anchor inpage" href="#%e5%ad%98%e5%82%a8">##</a>存储</h2>
<h3 id="bucket">
  <a class="anchor inpage" href="#bucket">###</a>Bucket</h3>
<p>Cloudflare 提供了对象存储服务，用户可以通过 <strong>R2 Bucket</strong> 以低成本存储大量非结构化数据，兼容 S3 API，便于与其他工具整合。</p>
<p><strong>使用案例：</strong></p>
<ul>
<li>为 Web 应用提供静态文件存储。</li>
<li>存储日志文件或大数据集。</li>
<li>备份和归档重要数据。</li>
</ul>
<h3 id="kv">
  <a class="anchor inpage" href="#kv">###</a>KV</h3>
<p>Cloudflare Key-Value（KV）存储是一种分布式的键值数据库，适用于缓存和快速读取小型数据。</p>
<p><strong>使用案例：</strong></p>
<ul>
<li>缓存 API 响应数据以减少服务器负载。</li>
<li>存储用户偏好设置、会话信息等轻量级数据。</li>
</ul>
<h3 id="d1">
  <a class="anchor inpage" href="#d1">###</a>D1</h3>
<p>Cloudflare D1 是新推出的分布式 SQL 数据库，提供强大的查询功能和一致性，适合需要结构化数据存储的应用。</p>
<p><strong>使用案例：</strong></p>
<ul>
<li>构建基于数据库的动态 Web 应用。</li>
<li>存储用户表单输入、订单信息等结构化数据。</li>
<li>实现实时分析和报告。</li>
</ul>
<h2 id="计算">
  <a class="anchor inpage" href="#%e8%ae%a1%e7%ae%97">##</a>计算</h2>
<h3 id="网页-pages">
  <a class="anchor inpage" href="#%e7%bd%91%e9%a1%b5-pages">###</a>网页 pages</h3>
<p>Cloudflare Pages 是一种无服务器的平台，支持快速部署静态和动态网站。通过与 GitHub 集成，可以自动构建和部署网站。</p>
<p>部署步骤</p>
<ol>
<li>登录到 
。</li>
<li>转到 <strong>Pages</strong> 部分，点击 <strong>创建项目 (Create a Project)</strong>。</li>
<li>选择绑定的 GitHub 仓库，授权 Pages 访问代码。</li>
<li>设置构建配置，包括：
<ul>
<li><strong>构建命令 (Build Command)</strong>：如 <code>npm run build</code>。</li>
<li><strong>输出目录 (Output Directory)</strong>：如 <code>dist</code> 文件夹。</li>
</ul>
</li>
<li>点击 <strong>保存并部署 (Save and Deploy)</strong>，系统将开始自动构建和部署。</li>
</ol>
<p>使用场景</p>
<ul>
<li><strong>个人博客和作品集</strong>：快速搭建和部署个人网站。</li>
<li><strong>文档站点</strong>：为开源项目或企业创建文档页面。</li>
<li><strong>电商网站</strong>：托管小型在线商店的前端页面。</li>
</ul>
<p>通过 Pages，开发者可以专注于代码，而无需担心服务器配置和运维。</p>
<h3 id="workers">
  <a class="anchor inpage" href="#workers">###</a>workers</h3>
<p>Cloudflare Workers 是一种无服务器的计算平台，可以让开发者在边缘运行代码，从而减少延迟并提升性能。</p>
<ol>
<li><strong>性能优越</strong>：运行代码的延迟极低，因为它直接在用户最近的边缘节点执行。</li>
<li><strong>语言灵活</strong>：支持 JavaScript、TypeScript 和 WebAssembly。</li>
<li><strong>集成生态</strong>：可以与 Cloudflare 的其他服务（如 KV 和 R2）无缝集成。</li>
</ol>
<p>使用场景</p>
<ul>
<li><strong>API 网关</strong>：快速处理 API 请求，并将其转发到后端服务。</li>
<li><strong>动态内容生成</strong>：根据用户请求生成个性化的网页。</li>
<li><strong>安全增强</strong>：在边缘执行请求过滤或内容安全策略。</li>
</ul>
<p>以下是一个简单的示例，展示如何使用 Workers 来响应 HTTP 请求：</p>
<details open>
    <summary>javascript</summary><pre
        class="chroma codeblock"
      ><code class="language-javascript" data-lang="javascript"
          ><span style="display:flex;"><span><span style="color:#a6e22e">addEventListener</span>(<span style="color:#e6db74">&#34;fetch&#34;</span>, (<span style="color:#a6e22e">event</span>) =&gt; {
</span></span><span style="display:flex;"><span>  <span style="color:#a6e22e">event</span>.<span style="color:#a6e22e">respondWith</span>(<span style="color:#a6e22e">handleRequest</span>(<span style="color:#a6e22e">event</span>.<span style="color:#a6e22e">request</span>));
</span></span><span style="display:flex;"><span>});
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span><span style="color:#66d9ef">async</span> <span style="color:#66d9ef">function</span> <span style="color:#a6e22e">handleRequest</span>(<span style="color:#a6e22e">request</span>) {
</span></span><span style="display:flex;"><span>  <span style="color:#66d9ef">return</span> <span style="color:#66d9ef">new</span> <span style="color:#a6e22e">Response</span>(<span style="color:#e6db74">&#34;Hello, World!&#34;</span>, {
</span></span><span style="display:flex;"><span>    <span style="color:#a6e22e">headers</span><span style="color:#f92672">:</span> { <span style="color:#e6db74">&#34;content-type&#34;</span><span style="color:#f92672">:</span> <span style="color:#e6db74">&#34;text/plain&#34;</span> },
</span></span><span style="display:flex;"><span>  });
</span></span><span style="display:flex;"><span>}</span></span></code
        ><button onclick="copyCode(this)" class="copybtn">copy</button></pre></details>

  <script>
    function copyCode(btn) {
      const code = btn.previousElementSibling.textContent.trim();
      navigator.clipboard.writeText(code).then(() => {
        btn.innerText = "copied";
        setTimeout(() => (btn.innerText = "copy"), 2000);
      });
    }
  </script><p>通过这个示例代码，开发者可以快速开始使用 Cloudflare Workers 构建和部署无服务器应用。</p>
<h2 id="ai">
  <a class="anchor inpage" href="#ai">##</a>AI</h2>
]]></content:encoded></item><item><title>编程语言概览</title><link>https://hiraethecho.github.io/docs/dev/code-lang/</link><pubDate>Sat, 12 Jul 2025 00:00:00 +0000</pubDate><author>wyz2016zxc@outlook.com(Hiraeth)</author><guid>https://hiraethecho.github.io/docs/dev/code-lang/</guid><description>编程语言的类型。主要为AI生成。</description><content:encoded><![CDATA[<h2 id="语言分类">
  <a class="anchor inpage" href="#%e8%af%ad%e8%a8%80%e5%88%86%e7%b1%bb">##</a>语言分类</h2>
<ol>
<li>静态类型 vs. 动态类型
<ul>
<li>静态：类型固定，编译检查（C++/Java）。</li>
<li>动态：类型可变，灵活但易出错（Python/JS）。</li>
</ul>
</li>
<li>编译型 vs. 解释型
<ul>
<li>编译型：直接运行机器码（C++/Go）。</li>
<li>解释型：逐行执行（Python/JS）。</li>
<li>JIT：混合优化（Java/JS V8）。</li>
</ul>
</li>
<li>脚本语言
<ul>
<li>解释型，用于自动化、Web（Python/JS/PHP）。</li>
</ul>
</li>
</ol>
<h3 id="静态类型-vs-动态类型">
  <a class="anchor inpage" href="#%e9%9d%99%e6%80%81%e7%b1%bb%e5%9e%8b-vs-%e5%8a%a8%e6%80%81%e7%b1%bb%e5%9e%8b">###</a>静态类型 vs. 动态类型</h3>
<p>静态类型（Statically Typed）</p>
<ul>
<li>定义：变量、函数参数、返回值等的数据类型在编译时就确定，不能随意更改。</li>
<li>特点：
<ul>
<li>编译时会检查类型错误，避免运行时崩溃。</li>
<li>性能更高（编译器可以优化）。</li>
<li>代码更严谨，适合大型项目。</li>
</ul>
</li>
<li>例子：
<ul>
<li>C/C++/Java/C#/Go/Rust</li>
</ul>
<details open>
    <summary>java</summary><pre
        class="chroma codeblock"
      ><code class="language-java" data-lang="java"
          ><span style="display:flex;"><span><span style="color:#66d9ef">int</span> num <span style="color:#f92672">=</span> 10;  <span style="color:#75715e">// num 只能是整数，不能赋值为字符串</span>
</span></span><span style="display:flex;"><span>num <span style="color:#f92672">=</span> <span style="color:#e6db74">&#34;hello&#34;</span>; <span style="color:#f92672">//</span> 编译报错<span style="color:#960050;background-color:#1e0010">！</span></span></span></code
        ><button onclick="copyCode(this)" class="copybtn">copy</button></pre></details>

  <script>
    function copyCode(btn) {
      const code = btn.previousElementSibling.textContent.trim();
      navigator.clipboard.writeText(code).then(() => {
        btn.innerText = "copied";
        setTimeout(() => (btn.innerText = "copy"), 2000);
      });
    }
  </script></li>
</ul>
<p>动态类型（Dynamically Typed）</p>
<ul>
<li>定义：变量类型在运行时才确定，可以随时改变。</li>
<li>特点：
<ul>
<li>更灵活，适合快速开发。</li>
<li>运行时可能因类型错误崩溃（如 <code>&quot;1&quot; + 2</code> 可能出错）。</li>
<li>性能稍低（需要运行时检查）。</li>
</ul>
</li>
<li>例子：
<ul>
<li>Python/JavaScript/Ruby/PHP/Lua</li>
</ul>
<details open>
    <summary>python</summary><pre
        class="chroma codeblock"
      ><code class="language-python" data-lang="python"
          ><span style="display:flex;"><span>num <span style="color:#f92672">=</span> <span style="color:#ae81ff">10</span>      <span style="color:#75715e"># num 是整数</span>
</span></span><span style="display:flex;"><span>num <span style="color:#f92672">=</span> <span style="color:#e6db74">&#34;hello&#34;</span> <span style="color:#75715e"># 现在 num 变成字符串，不会报错</span></span></span></code
        ><button onclick="copyCode(this)" class="copybtn">copy</button></pre></details>

  <script>
    function copyCode(btn) {
      const code = btn.previousElementSibling.textContent.trim();
      navigator.clipboard.writeText(code).then(() => {
        btn.innerText = "copied";
        setTimeout(() => (btn.innerText = "copy"), 2000);
      });
    }
  </script></li>
</ul>
<p>对比总结</p>
<table>
  <thead>
      <tr>
          <th>特性</th>
          <th>静态类型</th>
          <th>动态类型</th>
      </tr>
  </thead>
  <tbody>
      <tr>
          <td>类型检查</td>
          <td>编译时检查</td>
          <td>运行时检查</td>
      </tr>
      <tr>
          <td>性能</td>
          <td>更高（编译器优化）</td>
          <td>稍低（运行时解析）</td>
      </tr>
      <tr>
          <td>灵活性</td>
          <td>低（类型固定）</td>
          <td>高（随时改变类型）</td>
      </tr>
      <tr>
          <td>代表语言</td>
          <td>C/C++/Java/Go/Rust</td>
          <td>Python/JS/Ruby/PHP</td>
      </tr>
  </tbody>
</table>
<h3 id="编译型-vs-解释型">
  <a class="anchor inpage" href="#%e7%bc%96%e8%af%91%e5%9e%8b-vs-%e8%a7%a3%e9%87%8a%e5%9e%8b">###</a>编译型 vs. 解释型</h3>
<p>编译型语言（Compiled Languages）</p>
<ul>
<li>定义：代码先被编译器转换成机器码（二进制文件），再直接由CPU执行。</li>
<li>特点：
<ul>
<li>运行速度快（已经是机器码）。</li>
<li>需要针对不同平台（Windows/Linux/macOS）编译。</li>
<li>调试较麻烦（错误在编译时发现）。</li>
</ul>
</li>
<li>例子：
<ul>
<li>C/C++/Go/Rust</li>
</ul>
<details open>
    <summary>TEXT</summary><pre
        class="codeblock"
      ><code class="language-" data-lang="">源代码（.c） → 编译器（gcc） → 可执行文件（.exe） → CPU执行</code><button onclick="copyCode(this)" class="copybtn">copy</button></pre></details>

  <script>
    function copyCode(btn) {
      const code = btn.previousElementSibling.textContent.trim();
      navigator.clipboard.writeText(code).then(() => {
        btn.innerText = "copied";
        setTimeout(() => (btn.innerText = "copy"), 2000);
      });
    }
  </script></li>
</ul>
<h3 id="解释型语言interpreted-languages">
  <a class="anchor inpage" href="#%e8%a7%a3%e9%87%8a%e5%9e%8b%e8%af%ad%e8%a8%80interpreted-languages">###</a>解释型语言（Interpreted Languages）</h3>
<ul>
<li>定义：代码由解释器逐行翻译并执行，不生成独立可执行文件。</li>
<li>特点：
<ul>
<li>跨平台性好（只要有解释器就能运行）。</li>
<li>运行速度较慢（每次都要解析）。</li>
<li>调试方便（错误直接显示）。</li>
</ul>
</li>
<li>例子：
<ul>
<li>Python/JavaScript/PHP/Ruby</li>
</ul>
<details open>
    <summary>TEXT</summary><pre
        class="codeblock"
      ><code class="language-" data-lang="">源代码（.py） → 解释器（Python） → 直接执行（不生成.exe）</code><button onclick="copyCode(this)" class="copybtn">copy</button></pre></details>

  <script>
    function copyCode(btn) {
      const code = btn.previousElementSibling.textContent.trim();
      navigator.clipboard.writeText(code).then(() => {
        btn.innerText = "copied";
        setTimeout(() => (btn.innerText = "copy"), 2000);
      });
    }
  </script></li>
</ul>
<p>repl: read-eval-print loop, 解释器交互式模式</p>
<h3 id="混合型jit-编译">
  <a class="anchor inpage" href="#%e6%b7%b7%e5%90%88%e5%9e%8bjit-%e7%bc%96%e8%af%91">###</a>混合型（JIT 编译）</h3>
<ul>
<li>定义：结合编译和解释，先解释执行，再动态编译优化（如Java/C#/JS V8引擎）。</li>
<li>例子：
<ul>
<li>Java（编译成字节码，JVM解释执行）</li>
<li>JavaScript（V8引擎先解释，再JIT优化）</li>
</ul>
</li>
</ul>
<h3 id="对比总结">
  <a class="anchor inpage" href="#%e5%af%b9%e6%af%94%e6%80%bb%e7%bb%93">###</a>对比总结</h3>
<table>
  <thead>
      <tr>
          <th>特性</th>
          <th>编译型</th>
          <th>解释型</th>
          <th>JIT（混合型）</th>
      </tr>
  </thead>
  <tbody>
      <tr>
          <td>执行方式</td>
          <td>直接运行机器码</td>
          <td>逐行解释执行</td>
          <td>先解释，后编译优化</td>
      </tr>
      <tr>
          <td>速度</td>
          <td>最快</td>
          <td>较慢</td>
          <td>中等（优化后接近编译型）</td>
      </tr>
      <tr>
          <td>跨平台</td>
          <td>需重新编译</td>
          <td>直接运行（依赖解释器）</td>
          <td>依赖虚拟机（如JVM）</td>
      </tr>
      <tr>
          <td>代表语言</td>
          <td>C/C++/Go/Rust</td>
          <td>Python/JS/PHP</td>
          <td>Java/C#/JavaScript</td>
      </tr>
  </tbody>
</table>
<h3 id="脚本语言scripting-languages">
  <a class="anchor inpage" href="#%e8%84%9a%e6%9c%ac%e8%af%ad%e8%a8%80scripting-languages">###</a>脚本语言（Scripting Languages）</h3>
<ul>
<li>脚本语言是解释型语言的一种，通常用于自动化任务或控制其他程序。</li>
<li>特点：
<ul>
<li>不需要编译，直接运行。</li>
<li>语法简单，适合快速开发。</li>
<li>通常嵌入到其他系统中（如JS在浏览器，Lua在游戏引擎）。</li>
</ul>
</li>
</ul>
<p>常见脚本语言</p>
<table>
  <thead>
      <tr>
          <th>语言</th>
          <th>主要用途</th>
      </tr>
  </thead>
  <tbody>
      <tr>
          <td>JavaScript</td>
          <td>网页交互（浏览器）、后端（Node.js）</td>
      </tr>
      <tr>
          <td>Python</td>
          <td>数据分析、自动化脚本、Web后端</td>
      </tr>
      <tr>
          <td>PHP</td>
          <td>传统Web开发（WordPress）</td>
      </tr>
      <tr>
          <td>Lua</td>
          <td>游戏脚本（魔兽世界）、嵌入式扩展</td>
      </tr>
      <tr>
          <td>Ruby</td>
          <td>Web开发（Ruby on Rails）</td>
      </tr>
  </tbody>
</table>
<p>脚本语言 vs. 系统编程语言</p>
<table>
  <thead>
      <tr>
          <th>特性</th>
          <th>脚本语言（Python/JS）</th>
          <th>系统语言（C++/Rust）</th>
      </tr>
  </thead>
  <tbody>
      <tr>
          <td>执行方式</td>
          <td>解释执行</td>
          <td>编译成机器码</td>
      </tr>
      <tr>
          <td>性能</td>
          <td>较慢</td>
          <td>极快</td>
      </tr>
      <tr>
          <td>用途</td>
          <td>自动化、Web、数据分析</td>
          <td>操作系统、游戏引擎、高频交易</td>
      </tr>
  </tbody>
</table>
]]></content:encoded></item><item><title>lua</title><link>https://hiraethecho.github.io/docs/dev/lua/</link><pubDate>Mon, 07 Jul 2025 00:00:00 +0000</pubDate><author>wyz2016zxc@outlook.com(Hiraeth)</author><guid>https://hiraethecho.github.io/docs/dev/lua/</guid><description>&lt;h1 id="lua"&gt;
&lt;a class="anchor inpage" href="#lua"&gt;#&lt;/a&gt;lua&lt;/h1&gt;
&lt;h2 id="variable"&gt;
&lt;a class="anchor inpage" href="#variable"&gt;##&lt;/a&gt;variable&lt;/h2&gt;
&lt;details open&gt;
&lt;summary&gt;lua&lt;/summary&gt;&lt;pre
class="chroma codeblock"
&gt;&lt;code class="language-lua" data-lang="lua"
&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;num &lt;span style="color:#f92672"&gt;=&lt;/span&gt; &lt;span style="color:#ae81ff"&gt;42&lt;/span&gt; &lt;span style="color:#75715e"&gt;-- Numbers can be integer or floating point.&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;s &lt;span style="color:#f92672"&gt;=&lt;/span&gt; &lt;span style="color:#e6db74"&gt;&amp;#39;walternate&amp;#39;&lt;/span&gt; &lt;span style="color:#75715e"&gt;-- Immutable strings like Python.&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;t &lt;span style="color:#f92672"&gt;=&lt;/span&gt; &lt;span style="color:#e6db74"&gt;&amp;#34;double-quotes are also fine&amp;#34;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;u &lt;span style="color:#f92672"&gt;=&lt;/span&gt; &lt;span style="color:#e6db74"&gt;[[ Double brackets
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#e6db74"&gt; start and end
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#e6db74"&gt; multi-line strings.]]&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;t &lt;span style="color:#f92672"&gt;=&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;nil&lt;/span&gt; &lt;span style="color:#75715e"&gt;-- Undefines t; Lua has garbage collection.&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/code
&gt;&lt;button onclick="copyCode(this)" class="copybtn"&gt;copy&lt;/button&gt;&lt;/pre&gt;&lt;/details&gt;
&lt;script&gt;
function copyCode(btn) {
const code = btn.previousElementSibling.textContent.trim();
navigator.clipboard.writeText(code).then(() =&gt; {
btn.innerText = "copied";
setTimeout(() =&gt; (btn.innerText = "copy"), 2000);
});
}
&lt;/script&gt;&lt;h3 id="string"&gt;
&lt;a class="anchor inpage" href="#string"&gt;###&lt;/a&gt;string&lt;/h3&gt;
&lt;h2 id="control"&gt;
&lt;a class="anchor inpage" href="#control"&gt;##&lt;/a&gt;control&lt;/h2&gt;
&lt;details open&gt;
&lt;summary&gt;lua&lt;/summary&gt;&lt;pre
class="chroma codeblock"
&gt;&lt;code class="language-lua" data-lang="lua"
&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#66d9ef"&gt;if&lt;/span&gt; num &lt;span style="color:#f92672"&gt;&amp;gt;&lt;/span&gt; &lt;span style="color:#ae81ff"&gt;40&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;then&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; print(&lt;span style="color:#e6db74"&gt;&amp;#39;over 40&amp;#39;&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#66d9ef"&gt;elseif&lt;/span&gt; s &lt;span style="color:#f92672"&gt;~=&lt;/span&gt; &lt;span style="color:#e6db74"&gt;&amp;#39;walternate&amp;#39;&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;then&lt;/span&gt; &lt;span style="color:#75715e"&gt;-- ~= is not equals.&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#75715e"&gt;-- Equality check is == like Python; ok for strs.&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; io.write(&lt;span style="color:#e6db74"&gt;&amp;#39;not over 40&lt;/span&gt;&lt;span style="color:#ae81ff"&gt;\n&lt;/span&gt;&lt;span style="color:#e6db74"&gt;&amp;#39;&lt;/span&gt;) &lt;span style="color:#75715e"&gt;-- Defaults to stdout.&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#66d9ef"&gt;else&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#75715e"&gt;-- Variables are global by default.&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; thisIsGlobal &lt;span style="color:#f92672"&gt;=&lt;/span&gt; &lt;span style="color:#ae81ff"&gt;5&lt;/span&gt; &lt;span style="color:#75715e"&gt;-- Camel case is common.&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#75715e"&gt;-- How to make a variable local:&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#66d9ef"&gt;local&lt;/span&gt; line &lt;span style="color:#f92672"&gt;=&lt;/span&gt; io.read() &lt;span style="color:#75715e"&gt;-- Reads next stdin line.&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#75715e"&gt;-- String concatenation uses the .. operator:&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; print(&lt;span style="color:#e6db74"&gt;&amp;#39;Winter is coming, &amp;#39;&lt;/span&gt; &lt;span style="color:#f92672"&gt;..&lt;/span&gt; line)
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#66d9ef"&gt;end&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#75715e"&gt;-- Undefined variables return nil.&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#75715e"&gt;-- This is not an error:&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;foo &lt;span style="color:#f92672"&gt;=&lt;/span&gt; anUnknownVariable &lt;span style="color:#75715e"&gt;-- Now foo = nil.&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;aBoolValue &lt;span style="color:#f92672"&gt;=&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;false&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#75715e"&gt;-- Only nil and false are falsy; 0 and &amp;#39;&amp;#39; are true!&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#66d9ef"&gt;if&lt;/span&gt; &lt;span style="color:#f92672"&gt;not&lt;/span&gt; aBoolValue &lt;span style="color:#66d9ef"&gt;then&lt;/span&gt; print(&lt;span style="color:#e6db74"&gt;&amp;#39;it was false&amp;#39;&lt;/span&gt;) &lt;span style="color:#66d9ef"&gt;end&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#75715e"&gt;-- &amp;#39;or&amp;#39; and &amp;#39;and&amp;#39; are short-circuited.&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#75715e"&gt;-- This is similar to the a?b:c operator in C/js:&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;ans &lt;span style="color:#f92672"&gt;=&lt;/span&gt; aBoolValue &lt;span style="color:#f92672"&gt;and&lt;/span&gt; &lt;span style="color:#e6db74"&gt;&amp;#39;yes&amp;#39;&lt;/span&gt; &lt;span style="color:#f92672"&gt;or&lt;/span&gt; &lt;span style="color:#e6db74"&gt;&amp;#39;no&amp;#39;&lt;/span&gt; &lt;span style="color:#75715e"&gt;--&amp;gt; &amp;#39;no&amp;#39;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;karlSum &lt;span style="color:#f92672"&gt;=&lt;/span&gt; &lt;span style="color:#ae81ff"&gt;0&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#66d9ef"&gt;for&lt;/span&gt; i &lt;span style="color:#f92672"&gt;=&lt;/span&gt; &lt;span style="color:#ae81ff"&gt;1&lt;/span&gt;, &lt;span style="color:#ae81ff"&gt;100&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;do&lt;/span&gt; &lt;span style="color:#75715e"&gt;-- The range includes both ends.&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; karlSum &lt;span style="color:#f92672"&gt;=&lt;/span&gt; karlSum &lt;span style="color:#f92672"&gt;+&lt;/span&gt; i
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#66d9ef"&gt;end&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#75715e"&gt;-- Use &amp;#34;100, 1, -1&amp;#34; as the range to count down:&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;fredSum &lt;span style="color:#f92672"&gt;=&lt;/span&gt; &lt;span style="color:#ae81ff"&gt;0&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#66d9ef"&gt;for&lt;/span&gt; j &lt;span style="color:#f92672"&gt;=&lt;/span&gt; &lt;span style="color:#ae81ff"&gt;100&lt;/span&gt;, &lt;span style="color:#ae81ff"&gt;1&lt;/span&gt;, &lt;span style="color:#f92672"&gt;-&lt;/span&gt;&lt;span style="color:#ae81ff"&gt;1&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;do&lt;/span&gt; fredSum &lt;span style="color:#f92672"&gt;=&lt;/span&gt; fredSum &lt;span style="color:#f92672"&gt;+&lt;/span&gt; j &lt;span style="color:#66d9ef"&gt;end&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#75715e"&gt;-- In general, the range is begin, end[, step].&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#75715e"&gt;-- Another loop construct:&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#66d9ef"&gt;repeat&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; print(&lt;span style="color:#e6db74"&gt;&amp;#39;the way of the future&amp;#39;&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; num &lt;span style="color:#f92672"&gt;=&lt;/span&gt; num &lt;span style="color:#f92672"&gt;-&lt;/span&gt; &lt;span style="color:#ae81ff"&gt;1&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#66d9ef"&gt;until&lt;/span&gt; num &lt;span style="color:#f92672"&gt;==&lt;/span&gt; &lt;span style="color:#ae81ff"&gt;0&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/code
&gt;&lt;button onclick="copyCode(this)" class="copybtn"&gt;copy&lt;/button&gt;&lt;/pre&gt;&lt;/details&gt;
&lt;script&gt;
function copyCode(btn) {
const code = btn.previousElementSibling.textContent.trim();
navigator.clipboard.writeText(code).then(() =&gt; {
btn.innerText = "copied";
setTimeout(() =&gt; (btn.innerText = "copy"), 2000);
});
}
&lt;/script&gt;&lt;details open&gt;
&lt;summary&gt;lua&lt;/summary&gt;&lt;pre
class="chroma codeblock"
&gt;&lt;code class="language-lua" data-lang="lua"
&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#66d9ef"&gt;for&lt;/span&gt; k, v &lt;span style="color:#66d9ef"&gt;in&lt;/span&gt; pairs(t) &lt;span style="color:#66d9ef"&gt;do&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; print(k, v)
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#66d9ef"&gt;end&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;array &lt;span style="color:#f92672"&gt;=&lt;/span&gt; {&lt;span style="color:#e6db74"&gt;&amp;#34;Google&amp;#34;&lt;/span&gt;, &lt;span style="color:#e6db74"&gt;&amp;#34;Runoob&amp;#34;&lt;/span&gt;}
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#66d9ef"&gt;for&lt;/span&gt; key,value &lt;span style="color:#66d9ef"&gt;in&lt;/span&gt; ipairs(array)
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#66d9ef"&gt;do&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; print(key, value)
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#66d9ef"&gt;end&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/code
&gt;&lt;button onclick="copyCode(this)" class="copybtn"&gt;copy&lt;/button&gt;&lt;/pre&gt;&lt;/details&gt;
&lt;script&gt;
function copyCode(btn) {
const code = btn.previousElementSibling.textContent.trim();
navigator.clipboard.writeText(code).then(() =&gt; {
btn.innerText = "copied";
setTimeout(() =&gt; (btn.innerText = "copy"), 2000);
});
}
&lt;/script&gt;&lt;h2 id="function"&gt;
&lt;a class="anchor inpage" href="#function"&gt;##&lt;/a&gt;function&lt;/h2&gt;
&lt;details open&gt;
&lt;summary&gt;lua&lt;/summary&gt;&lt;pre
class="chroma codeblock"
&gt;&lt;code class="language-lua" data-lang="lua"
&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#66d9ef"&gt;function&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;fib&lt;/span&gt;(n)
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#66d9ef"&gt;if&lt;/span&gt; n &lt;span style="color:#f92672"&gt;&amp;lt;&lt;/span&gt; &lt;span style="color:#ae81ff"&gt;2&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;then&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;return&lt;/span&gt; &lt;span style="color:#ae81ff"&gt;1&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;end&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#66d9ef"&gt;return&lt;/span&gt; fib(n &lt;span style="color:#f92672"&gt;-&lt;/span&gt; &lt;span style="color:#ae81ff"&gt;2&lt;/span&gt;) &lt;span style="color:#f92672"&gt;+&lt;/span&gt; fib(n &lt;span style="color:#f92672"&gt;-&lt;/span&gt; &lt;span style="color:#ae81ff"&gt;1&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#66d9ef"&gt;end&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#75715e"&gt;-- Closures and anonymous functions are ok:&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#66d9ef"&gt;function&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;adder&lt;/span&gt;(x)
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#75715e"&gt;-- The returned function is created when adder is&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#75715e"&gt;-- called, and remembers the value of x:&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#66d9ef"&gt;return&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;function&lt;/span&gt; (y) &lt;span style="color:#66d9ef"&gt;return&lt;/span&gt; x &lt;span style="color:#f92672"&gt;+&lt;/span&gt; y &lt;span style="color:#66d9ef"&gt;end&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#66d9ef"&gt;end&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;a1 &lt;span style="color:#f92672"&gt;=&lt;/span&gt; adder(&lt;span style="color:#ae81ff"&gt;9&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;a2 &lt;span style="color:#f92672"&gt;=&lt;/span&gt; adder(&lt;span style="color:#ae81ff"&gt;36&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;print(a1(&lt;span style="color:#ae81ff"&gt;16&lt;/span&gt;)) &lt;span style="color:#75715e"&gt;--&amp;gt; 25&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;print(a2(&lt;span style="color:#ae81ff"&gt;64&lt;/span&gt;)) &lt;span style="color:#75715e"&gt;--&amp;gt; 100&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#75715e"&gt;-- Returns, func calls, and assignments all work&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#75715e"&gt;-- with lists that may be mismatched in length.&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#75715e"&gt;-- Unmatched receivers are nil;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#75715e"&gt;-- unmatched senders are discarded.&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;x, y, z &lt;span style="color:#f92672"&gt;=&lt;/span&gt; &lt;span style="color:#ae81ff"&gt;1&lt;/span&gt;, &lt;span style="color:#ae81ff"&gt;2&lt;/span&gt;, &lt;span style="color:#ae81ff"&gt;3&lt;/span&gt;, &lt;span style="color:#ae81ff"&gt;4&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#75715e"&gt;-- Now x = 1, y = 2, z = 3, and 4 is thrown away.&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#66d9ef"&gt;function&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;bar&lt;/span&gt;(a, b, c)
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; print(a, b, c)
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#66d9ef"&gt;return&lt;/span&gt; &lt;span style="color:#ae81ff"&gt;4&lt;/span&gt;, &lt;span style="color:#ae81ff"&gt;8&lt;/span&gt;, &lt;span style="color:#ae81ff"&gt;15&lt;/span&gt;, &lt;span style="color:#ae81ff"&gt;16&lt;/span&gt;, &lt;span style="color:#ae81ff"&gt;23&lt;/span&gt;, &lt;span style="color:#ae81ff"&gt;42&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#66d9ef"&gt;end&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;x, y &lt;span style="color:#f92672"&gt;=&lt;/span&gt; bar(&lt;span style="color:#e6db74"&gt;&amp;#39;zaphod&amp;#39;&lt;/span&gt;) &lt;span style="color:#75715e"&gt;--&amp;gt; prints &amp;#34;zaphod nil nil&amp;#34;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#75715e"&gt;-- Now x = 4, y = 8, values 15...42 are discarded.&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#75715e"&gt;-- Functions are first-class, may be local/global.&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#75715e"&gt;-- These are the same:&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#66d9ef"&gt;function&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;f&lt;/span&gt;(x) &lt;span style="color:#66d9ef"&gt;return&lt;/span&gt; x &lt;span style="color:#f92672"&gt;*&lt;/span&gt; x &lt;span style="color:#66d9ef"&gt;end&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;f &lt;span style="color:#f92672"&gt;=&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;function&lt;/span&gt; (x) &lt;span style="color:#66d9ef"&gt;return&lt;/span&gt; x &lt;span style="color:#f92672"&gt;*&lt;/span&gt; x &lt;span style="color:#66d9ef"&gt;end&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#75715e"&gt;-- And so are these:&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#66d9ef"&gt;local&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;function&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;g&lt;/span&gt;(x) &lt;span style="color:#66d9ef"&gt;return&lt;/span&gt; math.sin(x) &lt;span style="color:#66d9ef"&gt;end&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#66d9ef"&gt;local&lt;/span&gt; g; g &lt;span style="color:#f92672"&gt;=&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;function&lt;/span&gt; (x) &lt;span style="color:#66d9ef"&gt;return&lt;/span&gt; math.sin(x) &lt;span style="color:#66d9ef"&gt;end&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#75715e"&gt;-- the &amp;#39;local g&amp;#39; decl makes g-self-references ok.&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#75715e"&gt;-- Calls with one string param don&amp;#39;t need parens:&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;print &lt;span style="color:#e6db74"&gt;&amp;#39;hello&amp;#39;&lt;/span&gt; &lt;span style="color:#75715e"&gt;-- Works fine.&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/code
&gt;&lt;button onclick="copyCode(this)" class="copybtn"&gt;copy&lt;/button&gt;&lt;/pre&gt;&lt;/details&gt;
&lt;script&gt;
function copyCode(btn) {
const code = btn.previousElementSibling.textContent.trim();
navigator.clipboard.writeText(code).then(() =&gt; {
btn.innerText = "copied";
setTimeout(() =&gt; (btn.innerText = "copy"), 2000);
});
}
&lt;/script&gt;&lt;p&gt;多变量参数&lt;/p&gt;</description><content:encoded><![CDATA[<h1 id="lua">
  <a class="anchor inpage" href="#lua">#</a>lua</h1>
<h2 id="variable">
  <a class="anchor inpage" href="#variable">##</a>variable</h2>
<details open>
    <summary>lua</summary><pre
        class="chroma codeblock"
      ><code class="language-lua" data-lang="lua"
          ><span style="display:flex;"><span>num <span style="color:#f92672">=</span> <span style="color:#ae81ff">42</span>  <span style="color:#75715e">-- Numbers can be integer or floating point.</span>
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span>s <span style="color:#f92672">=</span> <span style="color:#e6db74">&#39;walternate&#39;</span>  <span style="color:#75715e">-- Immutable strings like Python.</span>
</span></span><span style="display:flex;"><span>t <span style="color:#f92672">=</span> <span style="color:#e6db74">&#34;double-quotes are also fine&#34;</span>
</span></span><span style="display:flex;"><span>u <span style="color:#f92672">=</span> <span style="color:#e6db74">[[ Double brackets
</span></span></span><span style="display:flex;"><span><span style="color:#e6db74">       start and end
</span></span></span><span style="display:flex;"><span><span style="color:#e6db74">       multi-line strings.]]</span>
</span></span><span style="display:flex;"><span>t <span style="color:#f92672">=</span> <span style="color:#66d9ef">nil</span>  <span style="color:#75715e">-- Undefines t; Lua has garbage collection.</span></span></span></code
        ><button onclick="copyCode(this)" class="copybtn">copy</button></pre></details>

  <script>
    function copyCode(btn) {
      const code = btn.previousElementSibling.textContent.trim();
      navigator.clipboard.writeText(code).then(() => {
        btn.innerText = "copied";
        setTimeout(() => (btn.innerText = "copy"), 2000);
      });
    }
  </script><h3 id="string">
  <a class="anchor inpage" href="#string">###</a>string</h3>
<h2 id="control">
  <a class="anchor inpage" href="#control">##</a>control</h2>
<details open>
    <summary>lua</summary><pre
        class="chroma codeblock"
      ><code class="language-lua" data-lang="lua"
          ><span style="display:flex;"><span><span style="color:#66d9ef">if</span> num <span style="color:#f92672">&gt;</span> <span style="color:#ae81ff">40</span> <span style="color:#66d9ef">then</span>
</span></span><span style="display:flex;"><span>  print(<span style="color:#e6db74">&#39;over 40&#39;</span>)
</span></span><span style="display:flex;"><span><span style="color:#66d9ef">elseif</span> s <span style="color:#f92672">~=</span> <span style="color:#e6db74">&#39;walternate&#39;</span> <span style="color:#66d9ef">then</span>  <span style="color:#75715e">-- ~= is not equals.</span>
</span></span><span style="display:flex;"><span>  <span style="color:#75715e">-- Equality check is == like Python; ok for strs.</span>
</span></span><span style="display:flex;"><span>  io.write(<span style="color:#e6db74">&#39;not over 40</span><span style="color:#ae81ff">\n</span><span style="color:#e6db74">&#39;</span>)  <span style="color:#75715e">-- Defaults to stdout.</span>
</span></span><span style="display:flex;"><span><span style="color:#66d9ef">else</span>
</span></span><span style="display:flex;"><span>  <span style="color:#75715e">-- Variables are global by default.</span>
</span></span><span style="display:flex;"><span>  thisIsGlobal <span style="color:#f92672">=</span> <span style="color:#ae81ff">5</span>  <span style="color:#75715e">-- Camel case is common.</span>
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span>  <span style="color:#75715e">-- How to make a variable local:</span>
</span></span><span style="display:flex;"><span>  <span style="color:#66d9ef">local</span> line <span style="color:#f92672">=</span> io.read()  <span style="color:#75715e">-- Reads next stdin line.</span>
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span>  <span style="color:#75715e">-- String concatenation uses the .. operator:</span>
</span></span><span style="display:flex;"><span>  print(<span style="color:#e6db74">&#39;Winter is coming, &#39;</span> <span style="color:#f92672">..</span> line)
</span></span><span style="display:flex;"><span><span style="color:#66d9ef">end</span>
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span><span style="color:#75715e">-- Undefined variables return nil.</span>
</span></span><span style="display:flex;"><span><span style="color:#75715e">-- This is not an error:</span>
</span></span><span style="display:flex;"><span>foo <span style="color:#f92672">=</span> anUnknownVariable  <span style="color:#75715e">-- Now foo = nil.</span>
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span>aBoolValue <span style="color:#f92672">=</span> <span style="color:#66d9ef">false</span>
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span><span style="color:#75715e">-- Only nil and false are falsy; 0 and &#39;&#39; are true!</span>
</span></span><span style="display:flex;"><span><span style="color:#66d9ef">if</span> <span style="color:#f92672">not</span> aBoolValue <span style="color:#66d9ef">then</span> print(<span style="color:#e6db74">&#39;it was false&#39;</span>) <span style="color:#66d9ef">end</span>
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span><span style="color:#75715e">-- &#39;or&#39; and &#39;and&#39; are short-circuited.</span>
</span></span><span style="display:flex;"><span><span style="color:#75715e">-- This is similar to the a?b:c operator in C/js:</span>
</span></span><span style="display:flex;"><span>ans <span style="color:#f92672">=</span> aBoolValue <span style="color:#f92672">and</span> <span style="color:#e6db74">&#39;yes&#39;</span> <span style="color:#f92672">or</span> <span style="color:#e6db74">&#39;no&#39;</span>  <span style="color:#75715e">--&gt; &#39;no&#39;</span>
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span>karlSum <span style="color:#f92672">=</span> <span style="color:#ae81ff">0</span>
</span></span><span style="display:flex;"><span><span style="color:#66d9ef">for</span> i <span style="color:#f92672">=</span> <span style="color:#ae81ff">1</span>, <span style="color:#ae81ff">100</span> <span style="color:#66d9ef">do</span>  <span style="color:#75715e">-- The range includes both ends.</span>
</span></span><span style="display:flex;"><span>  karlSum <span style="color:#f92672">=</span> karlSum <span style="color:#f92672">+</span> i
</span></span><span style="display:flex;"><span><span style="color:#66d9ef">end</span>
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span><span style="color:#75715e">-- Use &#34;100, 1, -1&#34; as the range to count down:</span>
</span></span><span style="display:flex;"><span>fredSum <span style="color:#f92672">=</span> <span style="color:#ae81ff">0</span>
</span></span><span style="display:flex;"><span><span style="color:#66d9ef">for</span> j <span style="color:#f92672">=</span> <span style="color:#ae81ff">100</span>, <span style="color:#ae81ff">1</span>, <span style="color:#f92672">-</span><span style="color:#ae81ff">1</span> <span style="color:#66d9ef">do</span> fredSum <span style="color:#f92672">=</span> fredSum <span style="color:#f92672">+</span> j <span style="color:#66d9ef">end</span>
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span><span style="color:#75715e">-- In general, the range is begin, end[, step].</span>
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span><span style="color:#75715e">-- Another loop construct:</span>
</span></span><span style="display:flex;"><span><span style="color:#66d9ef">repeat</span>
</span></span><span style="display:flex;"><span>  print(<span style="color:#e6db74">&#39;the way of the future&#39;</span>)
</span></span><span style="display:flex;"><span>  num <span style="color:#f92672">=</span> num <span style="color:#f92672">-</span> <span style="color:#ae81ff">1</span>
</span></span><span style="display:flex;"><span><span style="color:#66d9ef">until</span> num <span style="color:#f92672">==</span> <span style="color:#ae81ff">0</span></span></span></code
        ><button onclick="copyCode(this)" class="copybtn">copy</button></pre></details>

  <script>
    function copyCode(btn) {
      const code = btn.previousElementSibling.textContent.trim();
      navigator.clipboard.writeText(code).then(() => {
        btn.innerText = "copied";
        setTimeout(() => (btn.innerText = "copy"), 2000);
      });
    }
  </script><details open>
    <summary>lua</summary><pre
        class="chroma codeblock"
      ><code class="language-lua" data-lang="lua"
          ><span style="display:flex;"><span><span style="color:#66d9ef">for</span> k, v <span style="color:#66d9ef">in</span> pairs(t) <span style="color:#66d9ef">do</span>
</span></span><span style="display:flex;"><span>    print(k, v)
</span></span><span style="display:flex;"><span><span style="color:#66d9ef">end</span>
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span>array <span style="color:#f92672">=</span> {<span style="color:#e6db74">&#34;Google&#34;</span>, <span style="color:#e6db74">&#34;Runoob&#34;</span>}
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span><span style="color:#66d9ef">for</span> key,value <span style="color:#66d9ef">in</span> ipairs(array)
</span></span><span style="display:flex;"><span><span style="color:#66d9ef">do</span>
</span></span><span style="display:flex;"><span>   print(key, value)
</span></span><span style="display:flex;"><span><span style="color:#66d9ef">end</span></span></span></code
        ><button onclick="copyCode(this)" class="copybtn">copy</button></pre></details>

  <script>
    function copyCode(btn) {
      const code = btn.previousElementSibling.textContent.trim();
      navigator.clipboard.writeText(code).then(() => {
        btn.innerText = "copied";
        setTimeout(() => (btn.innerText = "copy"), 2000);
      });
    }
  </script><h2 id="function">
  <a class="anchor inpage" href="#function">##</a>function</h2>
<details open>
    <summary>lua</summary><pre
        class="chroma codeblock"
      ><code class="language-lua" data-lang="lua"
          ><span style="display:flex;"><span><span style="color:#66d9ef">function</span> <span style="color:#a6e22e">fib</span>(n)
</span></span><span style="display:flex;"><span>  <span style="color:#66d9ef">if</span> n <span style="color:#f92672">&lt;</span> <span style="color:#ae81ff">2</span> <span style="color:#66d9ef">then</span> <span style="color:#66d9ef">return</span> <span style="color:#ae81ff">1</span> <span style="color:#66d9ef">end</span>
</span></span><span style="display:flex;"><span>  <span style="color:#66d9ef">return</span> fib(n <span style="color:#f92672">-</span> <span style="color:#ae81ff">2</span>) <span style="color:#f92672">+</span> fib(n <span style="color:#f92672">-</span> <span style="color:#ae81ff">1</span>)
</span></span><span style="display:flex;"><span><span style="color:#66d9ef">end</span>
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span><span style="color:#75715e">-- Closures and anonymous functions are ok:</span>
</span></span><span style="display:flex;"><span><span style="color:#66d9ef">function</span> <span style="color:#a6e22e">adder</span>(x)
</span></span><span style="display:flex;"><span>  <span style="color:#75715e">-- The returned function is created when adder is</span>
</span></span><span style="display:flex;"><span>  <span style="color:#75715e">-- called, and remembers the value of x:</span>
</span></span><span style="display:flex;"><span>  <span style="color:#66d9ef">return</span> <span style="color:#66d9ef">function</span> (y) <span style="color:#66d9ef">return</span> x <span style="color:#f92672">+</span> y <span style="color:#66d9ef">end</span>
</span></span><span style="display:flex;"><span><span style="color:#66d9ef">end</span>
</span></span><span style="display:flex;"><span>a1 <span style="color:#f92672">=</span> adder(<span style="color:#ae81ff">9</span>)
</span></span><span style="display:flex;"><span>a2 <span style="color:#f92672">=</span> adder(<span style="color:#ae81ff">36</span>)
</span></span><span style="display:flex;"><span>print(a1(<span style="color:#ae81ff">16</span>))  <span style="color:#75715e">--&gt; 25</span>
</span></span><span style="display:flex;"><span>print(a2(<span style="color:#ae81ff">64</span>))  <span style="color:#75715e">--&gt; 100</span>
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span><span style="color:#75715e">-- Returns, func calls, and assignments all work</span>
</span></span><span style="display:flex;"><span><span style="color:#75715e">-- with lists that may be mismatched in length.</span>
</span></span><span style="display:flex;"><span><span style="color:#75715e">-- Unmatched receivers are nil;</span>
</span></span><span style="display:flex;"><span><span style="color:#75715e">-- unmatched senders are discarded.</span>
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span>x, y, z <span style="color:#f92672">=</span> <span style="color:#ae81ff">1</span>, <span style="color:#ae81ff">2</span>, <span style="color:#ae81ff">3</span>, <span style="color:#ae81ff">4</span>
</span></span><span style="display:flex;"><span><span style="color:#75715e">-- Now x = 1, y = 2, z = 3, and 4 is thrown away.</span>
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span><span style="color:#66d9ef">function</span> <span style="color:#a6e22e">bar</span>(a, b, c)
</span></span><span style="display:flex;"><span>  print(a, b, c)
</span></span><span style="display:flex;"><span>  <span style="color:#66d9ef">return</span> <span style="color:#ae81ff">4</span>, <span style="color:#ae81ff">8</span>, <span style="color:#ae81ff">15</span>, <span style="color:#ae81ff">16</span>, <span style="color:#ae81ff">23</span>, <span style="color:#ae81ff">42</span>
</span></span><span style="display:flex;"><span><span style="color:#66d9ef">end</span>
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span>x, y <span style="color:#f92672">=</span> bar(<span style="color:#e6db74">&#39;zaphod&#39;</span>)  <span style="color:#75715e">--&gt; prints &#34;zaphod  nil nil&#34;</span>
</span></span><span style="display:flex;"><span><span style="color:#75715e">-- Now x = 4, y = 8, values 15...42 are discarded.</span>
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span><span style="color:#75715e">-- Functions are first-class, may be local/global.</span>
</span></span><span style="display:flex;"><span><span style="color:#75715e">-- These are the same:</span>
</span></span><span style="display:flex;"><span><span style="color:#66d9ef">function</span> <span style="color:#a6e22e">f</span>(x) <span style="color:#66d9ef">return</span> x <span style="color:#f92672">*</span> x <span style="color:#66d9ef">end</span>
</span></span><span style="display:flex;"><span>f <span style="color:#f92672">=</span> <span style="color:#66d9ef">function</span> (x) <span style="color:#66d9ef">return</span> x <span style="color:#f92672">*</span> x <span style="color:#66d9ef">end</span>
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span><span style="color:#75715e">-- And so are these:</span>
</span></span><span style="display:flex;"><span><span style="color:#66d9ef">local</span> <span style="color:#66d9ef">function</span> <span style="color:#a6e22e">g</span>(x) <span style="color:#66d9ef">return</span> math.sin(x) <span style="color:#66d9ef">end</span>
</span></span><span style="display:flex;"><span><span style="color:#66d9ef">local</span> g; g  <span style="color:#f92672">=</span> <span style="color:#66d9ef">function</span> (x) <span style="color:#66d9ef">return</span> math.sin(x) <span style="color:#66d9ef">end</span>
</span></span><span style="display:flex;"><span><span style="color:#75715e">-- the &#39;local g&#39; decl makes g-self-references ok.</span>
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span><span style="color:#75715e">-- Calls with one string param don&#39;t need parens:</span>
</span></span><span style="display:flex;"><span>print <span style="color:#e6db74">&#39;hello&#39;</span>  <span style="color:#75715e">-- Works fine.</span></span></span></code
        ><button onclick="copyCode(this)" class="copybtn">copy</button></pre></details>

  <script>
    function copyCode(btn) {
      const code = btn.previousElementSibling.textContent.trim();
      navigator.clipboard.writeText(code).then(() => {
        btn.innerText = "copied";
        setTimeout(() => (btn.innerText = "copy"), 2000);
      });
    }
  </script><p>多变量参数</p>
<details open>
    <summary>lua</summary><pre
        class="chroma codeblock"
      ><code class="language-lua" data-lang="lua"
          ><span style="display:flex;"><span><span style="color:#75715e">--[[
</span></span></span><span style="display:flex;"><span><span style="color:#75715e">local function 函数名(...)
</span></span></span><span style="display:flex;"><span><span style="color:#75715e">    local args = {...} -- 转为表
</span></span></span><span style="display:flex;"><span><span style="color:#75715e">    -- 处理args
</span></span></span><span style="display:flex;"><span><span style="color:#75715e">end
</span></span></span><span style="display:flex;"><span><span style="color:#75715e">]]</span>
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span><span style="color:#66d9ef">local</span> <span style="color:#66d9ef">function</span> <span style="color:#a6e22e">sum</span>(...)
</span></span><span style="display:flex;"><span>    <span style="color:#66d9ef">local</span> result <span style="color:#f92672">=</span> <span style="color:#ae81ff">0</span>
</span></span><span style="display:flex;"><span>    <span style="color:#66d9ef">for</span> _, num <span style="color:#66d9ef">in</span> ipairs({...}) <span style="color:#66d9ef">do</span>
</span></span><span style="display:flex;"><span>        result <span style="color:#f92672">=</span> result <span style="color:#f92672">+</span> num
</span></span><span style="display:flex;"><span>    <span style="color:#66d9ef">end</span>
</span></span><span style="display:flex;"><span>    <span style="color:#66d9ef">return</span> result
</span></span><span style="display:flex;"><span><span style="color:#66d9ef">end</span>
</span></span><span style="display:flex;"><span>print(sum(<span style="color:#ae81ff">1</span>, <span style="color:#ae81ff">2</span>, <span style="color:#ae81ff">3</span>)) <span style="color:#75715e">-- 输出: 6</span></span></span></code
        ><button onclick="copyCode(this)" class="copybtn">copy</button></pre></details>

  <script>
    function copyCode(btn) {
      const code = btn.previousElementSibling.textContent.trim();
      navigator.clipboard.writeText(code).then(() => {
        btn.innerText = "copied";
        setTimeout(() => (btn.innerText = "copy"), 2000);
      });
    }
  </script><p>另一种定义函数的语法</p>
<details open>
    <summary>lua</summary><pre
        class="chroma codeblock"
      ><code class="language-lua" data-lang="lua"
          ><span style="display:flex;"><span><span style="color:#66d9ef">local</span> greet <span style="color:#f92672">=</span> <span style="color:#66d9ef">function</span>(name)
</span></span><span style="display:flex;"><span>    print(<span style="color:#e6db74">&#34;Hello, &#34;</span> <span style="color:#f92672">..</span> name)
</span></span><span style="display:flex;"><span><span style="color:#66d9ef">end</span>
</span></span><span style="display:flex;"><span>greet(<span style="color:#e6db74">&#34;World&#34;</span>) <span style="color:#75715e">-- 输出: Hello, World</span></span></span></code
        ><button onclick="copyCode(this)" class="copybtn">copy</button></pre></details>

  <script>
    function copyCode(btn) {
      const code = btn.previousElementSibling.textContent.trim();
      navigator.clipboard.writeText(code).then(() => {
        btn.innerText = "copied";
        setTimeout(() => (btn.innerText = "copy"), 2000);
      });
    }
  </script><p>表成员函数风格模拟对象：</p>
<details open>
    <summary>lua</summary><pre
        class="chroma codeblock"
      ><code class="language-lua" data-lang="lua"
          ><span style="display:flex;"><span><span style="color:#66d9ef">local</span> person <span style="color:#f92672">=</span> {
</span></span><span style="display:flex;"><span>    name <span style="color:#f92672">=</span> <span style="color:#e6db74">&#34;Alice&#34;</span>,
</span></span><span style="display:flex;"><span>    sayHi <span style="color:#f92672">=</span> <span style="color:#66d9ef">function</span>(self)
</span></span><span style="display:flex;"><span>        print(<span style="color:#e6db74">&#34;Hi, I&#39;m &#34;</span> <span style="color:#f92672">..</span> self.name)
</span></span><span style="display:flex;"><span>    <span style="color:#66d9ef">end</span>
</span></span><span style="display:flex;"><span>}
</span></span><span style="display:flex;"><span>person:sayHi() <span style="color:#75715e">-- 输出: Hi, I&#39;m Alice</span>
</span></span><span style="display:flex;"><span><span style="color:#75715e">-- 等价于 person.sayHi(person)</span></span></span></code
        ><button onclick="copyCode(this)" class="copybtn">copy</button></pre></details>

  <script>
    function copyCode(btn) {
      const code = btn.previousElementSibling.textContent.trim();
      navigator.clipboard.writeText(code).then(() => {
        btn.innerText = "copied";
        setTimeout(() => (btn.innerText = "copy"), 2000);
      });
    }
  </script><h2 id="table">
  <a class="anchor inpage" href="#table">##</a>table</h2>
<h3 id="basic">
  <a class="anchor inpage" href="#basic">###</a>basic</h3>
<details open>
    <summary>lua</summary><pre
        class="chroma codeblock"
      ><code class="language-lua" data-lang="lua"
          ><span style="display:flex;"><span><span style="color:#75715e">-- Dict literals have string keys by default:</span>
</span></span><span style="display:flex;"><span>t <span style="color:#f92672">=</span> {key1 <span style="color:#f92672">=</span> <span style="color:#e6db74">&#39;value1&#39;</span>, key2 <span style="color:#f92672">=</span> <span style="color:#66d9ef">false</span>}
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span><span style="color:#75715e">-- String keys can use js-like dot notation:</span>
</span></span><span style="display:flex;"><span>print(t.key1)  <span style="color:#75715e">-- Prints &#39;value1&#39;.</span>
</span></span><span style="display:flex;"><span>t.newKey <span style="color:#f92672">=</span> {}  <span style="color:#75715e">-- Adds a new key/value pair.</span>
</span></span><span style="display:flex;"><span>t.key2 <span style="color:#f92672">=</span> <span style="color:#66d9ef">nil</span>   <span style="color:#75715e">-- Removes key2 from the table.</span>
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span><span style="color:#75715e">-- Literal notation for any (non-nil) value as key:</span>
</span></span><span style="display:flex;"><span>u <span style="color:#f92672">=</span> {[<span style="color:#e6db74">&#39;@!#&#39;</span>] <span style="color:#f92672">=</span> <span style="color:#e6db74">&#39;qbert&#39;</span>, [{}] <span style="color:#f92672">=</span> <span style="color:#ae81ff">1729</span>, [<span style="color:#ae81ff">6.28</span>] <span style="color:#f92672">=</span> <span style="color:#e6db74">&#39;tau&#39;</span>}
</span></span><span style="display:flex;"><span>print(u[<span style="color:#ae81ff">6.28</span>])  <span style="color:#75715e">-- prints &#34;tau&#34;</span>
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span><span style="color:#75715e">-- Key matching is basically by value for numbers</span>
</span></span><span style="display:flex;"><span><span style="color:#75715e">-- and strings, but by identity for tables.</span>
</span></span><span style="display:flex;"><span>a <span style="color:#f92672">=</span> u[<span style="color:#e6db74">&#39;@!#&#39;</span>]  <span style="color:#75715e">-- Now a = &#39;qbert&#39;.</span>
</span></span><span style="display:flex;"><span>b <span style="color:#f92672">=</span> u[{}]     <span style="color:#75715e">-- We might expect 1729, but it&#39;s nil:</span>
</span></span><span style="display:flex;"><span><span style="color:#75715e">-- b = nil since the lookup fails. It fails</span>
</span></span><span style="display:flex;"><span><span style="color:#75715e">-- because the key we used is not the same object</span>
</span></span><span style="display:flex;"><span><span style="color:#75715e">-- as the one used to store the original value. So</span>
</span></span><span style="display:flex;"><span><span style="color:#75715e">-- strings &amp; numbers are more portable keys.</span>
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span><span style="color:#75715e">-- A one-table-param function call needs no parens:</span>
</span></span><span style="display:flex;"><span><span style="color:#66d9ef">function</span> <span style="color:#a6e22e">h</span>(x) print(x.key1) <span style="color:#66d9ef">end</span>
</span></span><span style="display:flex;"><span>h{key1 <span style="color:#f92672">=</span> <span style="color:#e6db74">&#39;Sonmi~451&#39;</span>}  <span style="color:#75715e">-- Prints &#39;Sonmi~451&#39;.</span>
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span><span style="color:#66d9ef">for</span> key, val <span style="color:#66d9ef">in</span> pairs(u) <span style="color:#66d9ef">do</span>  <span style="color:#75715e">-- Table iteration.</span>
</span></span><span style="display:flex;"><span>  print(key, val)
</span></span><span style="display:flex;"><span><span style="color:#66d9ef">end</span>
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span><span style="color:#75715e">-- _G is a special table of all globals.</span>
</span></span><span style="display:flex;"><span>print(_G[<span style="color:#e6db74">&#39;_G&#39;</span>] <span style="color:#f92672">==</span> _G)  <span style="color:#75715e">-- Prints &#39;true&#39;.</span>
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span><span style="color:#75715e">-- Using tables as lists / arrays:</span>
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span><span style="color:#75715e">-- List literals implicitly set up int keys:</span>
</span></span><span style="display:flex;"><span>v <span style="color:#f92672">=</span> {<span style="color:#e6db74">&#39;value1&#39;</span>, <span style="color:#e6db74">&#39;value2&#39;</span>, <span style="color:#ae81ff">1.21</span>, <span style="color:#e6db74">&#39;gigawatts&#39;</span>}
</span></span><span style="display:flex;"><span><span style="color:#66d9ef">for</span> i <span style="color:#f92672">=</span> <span style="color:#ae81ff">1</span>, <span style="color:#f92672">#</span>v <span style="color:#66d9ef">do</span>  <span style="color:#75715e">-- #v is the size of v for lists.</span>
</span></span><span style="display:flex;"><span>  print(v[i])  <span style="color:#75715e">-- Indices start at 1 !! SO CRAZY!</span>
</span></span><span style="display:flex;"><span><span style="color:#66d9ef">end</span>
</span></span><span style="display:flex;"><span><span style="color:#75715e">-- A &#39;list&#39; is not a real type. v is just a table</span>
</span></span><span style="display:flex;"><span><span style="color:#75715e">-- with consecutive integer keys, treated as a list.</span>
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span><span style="color:#75715e">-- 初始化表</span>
</span></span><span style="display:flex;"><span>mytable <span style="color:#f92672">=</span> {}
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span><span style="color:#75715e">-- 指定值</span>
</span></span><span style="display:flex;"><span>mytable[<span style="color:#ae81ff">1</span>]<span style="color:#f92672">=</span> <span style="color:#e6db74">&#34;Lua&#34;</span>
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span><span style="color:#75715e">-- 移除引用</span>
</span></span><span style="display:flex;"><span>mytable <span style="color:#f92672">=</span> <span style="color:#66d9ef">nil</span>
</span></span><span style="display:flex;"><span><span style="color:#75715e">-- lua 垃圾回收会释放内存</span></span></span></code
        ><button onclick="copyCode(this)" class="copybtn">copy</button></pre></details>

  <script>
    function copyCode(btn) {
      const code = btn.previousElementSibling.textContent.trim();
      navigator.clipboard.writeText(code).then(() => {
        btn.innerText = "copied";
        setTimeout(() => (btn.innerText = "copy"), 2000);
      });
    }
  </script><details open>
    <summary>lua</summary><pre
        class="chroma codeblock"
      ><code class="language-lua" data-lang="lua"
          ><span style="display:flex;"><span><span style="color:#75715e">-- 简单的 table</span>
</span></span><span style="display:flex;"><span>mytable <span style="color:#f92672">=</span> {}
</span></span><span style="display:flex;"><span>print(<span style="color:#e6db74">&#34;mytable 的类型是 &#34;</span>,type(mytable))
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span>mytable[<span style="color:#ae81ff">1</span>]<span style="color:#f92672">=</span> <span style="color:#e6db74">&#34;Lua&#34;</span>
</span></span><span style="display:flex;"><span>mytable[<span style="color:#e6db74">&#34;wow&#34;</span>] <span style="color:#f92672">=</span> <span style="color:#e6db74">&#34;修改前&#34;</span>
</span></span><span style="display:flex;"><span>print(<span style="color:#e6db74">&#34;mytable 索引为 1 的元素是 &#34;</span>, mytable[<span style="color:#ae81ff">1</span>])
</span></span><span style="display:flex;"><span>print(<span style="color:#e6db74">&#34;mytable 索引为 wow 的元素是 &#34;</span>, mytable[<span style="color:#e6db74">&#34;wow&#34;</span>])
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span><span style="color:#75715e">-- alternatetable和mytable的是指同一个 table</span>
</span></span><span style="display:flex;"><span>alternatetable <span style="color:#f92672">=</span> mytable
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span>print(<span style="color:#e6db74">&#34;alternatetable 索引为 1 的元素是 &#34;</span>, alternatetable[<span style="color:#ae81ff">1</span>])
</span></span><span style="display:flex;"><span>print(<span style="color:#e6db74">&#34;alternatetable 索引为 wow 的元素是 &#34;</span>, alternatetable[<span style="color:#e6db74">&#34;wow&#34;</span>])
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span>alternatetable[<span style="color:#e6db74">&#34;wow&#34;</span>] <span style="color:#f92672">=</span> <span style="color:#e6db74">&#34;修改后&#34;</span>
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span>print(<span style="color:#e6db74">&#34;mytable 索引为 wow 的元素是 &#34;</span>, mytable[<span style="color:#e6db74">&#34;wow&#34;</span>])
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span><span style="color:#75715e">-- 释放变量</span>
</span></span><span style="display:flex;"><span>alternatetable <span style="color:#f92672">=</span> <span style="color:#66d9ef">nil</span>
</span></span><span style="display:flex;"><span>print(<span style="color:#e6db74">&#34;alternatetable 是 &#34;</span>, alternatetable)
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span><span style="color:#75715e">-- mytable 仍然可以访问</span>
</span></span><span style="display:flex;"><span>print(<span style="color:#e6db74">&#34;mytable 索引为 wow 的元素是 &#34;</span>, mytable[<span style="color:#e6db74">&#34;wow&#34;</span>])
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span>mytable <span style="color:#f92672">=</span> <span style="color:#66d9ef">nil</span>
</span></span><span style="display:flex;"><span>print(<span style="color:#e6db74">&#34;mytable 是 &#34;</span>, mytable)</span></span></code
        ><button onclick="copyCode(this)" class="copybtn">copy</button></pre></details>

  <script>
    function copyCode(btn) {
      const code = btn.previousElementSibling.textContent.trim();
      navigator.clipboard.writeText(code).then(() => {
        btn.innerText = "copied";
        setTimeout(() => (btn.innerText = "copy"), 2000);
      });
    }
  </script><p>输出</p>
<details open>
    <summary>TEXT</summary><pre
        class="codeblock"
      ><code class="language-" data-lang="">mytable 的类型是        table
mytable 索引为 1 的元素是       Lua
mytable 索引为 wow 的元素是     修改前
alternatetable 索引为 1 的元素是        Lua
alternatetable 索引为 wow 的元素是      修改前
mytable 索引为 wow 的元素是     修改后
alternatetable 是       nil
mytable 索引为 wow 的元素是     修改后
mytable 是      nil</code><button onclick="copyCode(this)" class="copybtn">copy</button></pre></details>

  <script>
    function copyCode(btn) {
      const code = btn.previousElementSibling.textContent.trim();
      navigator.clipboard.writeText(code).then(() => {
        btn.innerText = "copied";
        setTimeout(() => (btn.innerText = "copy"), 2000);
      });
    }
  </script><p>当键名是合法标识符时，<code>tbl.text</code> 是 <code>tbl[&quot;text&quot;]</code> 的语法糖。</p>
<h3 id="class-like">
  <a class="anchor inpage" href="#class-like">###</a>class-like</h3>
<details open>
    <summary>lua</summary><pre
        class="chroma codeblock"
      ><code class="language-lua" data-lang="lua"
          ><span style="display:flex;"><span><span style="color:#75715e">-- Explanation for this example is below it.</span>
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span>Dog <span style="color:#f92672">=</span> {}                                   <span style="color:#75715e">-- 1.</span>
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span><span style="color:#66d9ef">function</span> <span style="color:#a6e22e">Dog</span>:<span style="color:#a6e22e">new</span>()                         <span style="color:#75715e">-- 2.</span>
</span></span><span style="display:flex;"><span>  newObj <span style="color:#f92672">=</span> {sound <span style="color:#f92672">=</span> <span style="color:#e6db74">&#39;woof&#39;</span>}                <span style="color:#75715e">-- 3.</span>
</span></span><span style="display:flex;"><span>  self.__index <span style="color:#f92672">=</span> self                      <span style="color:#75715e">-- 4.</span>
</span></span><span style="display:flex;"><span>  <span style="color:#66d9ef">return</span> setmetatable(newObj, self)        <span style="color:#75715e">-- 5.</span>
</span></span><span style="display:flex;"><span><span style="color:#66d9ef">end</span>
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span><span style="color:#66d9ef">function</span> <span style="color:#a6e22e">Dog</span>:<span style="color:#a6e22e">makeSound</span>()                   <span style="color:#75715e">-- 6.</span>
</span></span><span style="display:flex;"><span>  print(<span style="color:#e6db74">&#39;I say &#39;</span> <span style="color:#f92672">..</span> self.sound)
</span></span><span style="display:flex;"><span><span style="color:#66d9ef">end</span>
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span>mrDog <span style="color:#f92672">=</span> Dog:new()                          <span style="color:#75715e">-- 7.</span>
</span></span><span style="display:flex;"><span>mrDog:makeSound()  <span style="color:#75715e">-- &#39;I say woof&#39;         -- 8.</span>
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span><span style="color:#75715e">-- 1. Dog acts like a class; it&#39;s really a table.</span>
</span></span><span style="display:flex;"><span><span style="color:#75715e">-- 2. function tablename:fn(...) is the same as</span>
</span></span><span style="display:flex;"><span><span style="color:#75715e">--    function tablename.fn(self, ...)</span>
</span></span><span style="display:flex;"><span><span style="color:#75715e">--    The : just adds a first arg called self.</span>
</span></span><span style="display:flex;"><span><span style="color:#75715e">--    Read 7 &amp; 8 below for how self gets its value.</span>
</span></span><span style="display:flex;"><span><span style="color:#75715e">-- 3. newObj will be an instance of class Dog.</span>
</span></span><span style="display:flex;"><span><span style="color:#75715e">-- 4. self = the class being instantiated. Often</span>
</span></span><span style="display:flex;"><span><span style="color:#75715e">--    self = Dog, but inheritance can change it.</span>
</span></span><span style="display:flex;"><span><span style="color:#75715e">--    newObj gets self&#39;s functions when we set both</span>
</span></span><span style="display:flex;"><span><span style="color:#75715e">--    newObj&#39;s metatable and self&#39;s __index to self.</span>
</span></span><span style="display:flex;"><span><span style="color:#75715e">-- 5. Reminder: setmetatable returns its first arg.</span>
</span></span><span style="display:flex;"><span><span style="color:#75715e">-- 6. The : works as in 2, but this time we expect</span>
</span></span><span style="display:flex;"><span><span style="color:#75715e">--    self to be an instance instead of a class.</span>
</span></span><span style="display:flex;"><span><span style="color:#75715e">-- 7. Same as Dog.new(Dog), so self = Dog in new().</span>
</span></span><span style="display:flex;"><span><span style="color:#75715e">-- 8. Same as mrDog.makeSound(mrDog); self = mrDog.</span>
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span><span style="color:#75715e">----------------------------------------------------</span>
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span><span style="color:#75715e">-- Inheritance example:</span>
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span>LoudDog <span style="color:#f92672">=</span> Dog:new()                           <span style="color:#75715e">-- 1.</span>
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span><span style="color:#66d9ef">function</span> <span style="color:#a6e22e">LoudDog</span>:<span style="color:#a6e22e">makeSound</span>()
</span></span><span style="display:flex;"><span>  s <span style="color:#f92672">=</span> self.sound <span style="color:#f92672">..</span> <span style="color:#e6db74">&#39; &#39;</span>                       <span style="color:#75715e">-- 2.</span>
</span></span><span style="display:flex;"><span>  print(s <span style="color:#f92672">..</span> s <span style="color:#f92672">..</span> s)
</span></span><span style="display:flex;"><span><span style="color:#66d9ef">end</span>
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span>seymour <span style="color:#f92672">=</span> LoudDog:new()                       <span style="color:#75715e">-- 3.</span>
</span></span><span style="display:flex;"><span>seymour:makeSound()  <span style="color:#75715e">-- &#39;woof woof woof&#39;      -- 4.</span>
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span><span style="color:#75715e">-- 1. LoudDog gets Dog&#39;s methods and variables.</span>
</span></span><span style="display:flex;"><span><span style="color:#75715e">-- 2. self has a &#39;sound&#39; key from new(), see 3.</span>
</span></span><span style="display:flex;"><span><span style="color:#75715e">-- 3. Same as LoudDog.new(LoudDog), and converted to</span>
</span></span><span style="display:flex;"><span><span style="color:#75715e">--    Dog.new(LoudDog) as LoudDog has no &#39;new&#39; key,</span>
</span></span><span style="display:flex;"><span><span style="color:#75715e">--    but does have __index = Dog on its metatable.</span>
</span></span><span style="display:flex;"><span><span style="color:#75715e">--    Result: seymour&#39;s metatable is LoudDog, and</span>
</span></span><span style="display:flex;"><span><span style="color:#75715e">--    LoudDog.__index = LoudDog. So seymour.key will</span>
</span></span><span style="display:flex;"><span><span style="color:#75715e">--    = seymour.key, LoudDog.key, Dog.key, whichever</span>
</span></span><span style="display:flex;"><span><span style="color:#75715e">--    table is the first with the given key.</span>
</span></span><span style="display:flex;"><span><span style="color:#75715e">-- 4. The &#39;makeSound&#39; key is found in LoudDog; this</span>
</span></span><span style="display:flex;"><span><span style="color:#75715e">--    is the same as LoudDog.makeSound(seymour).</span>
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span><span style="color:#75715e">-- If needed, a subclass&#39;s new() is like the base&#39;s:</span>
</span></span><span style="display:flex;"><span><span style="color:#66d9ef">function</span> <span style="color:#a6e22e">LoudDog</span>:<span style="color:#a6e22e">new</span>()
</span></span><span style="display:flex;"><span>  newObj <span style="color:#f92672">=</span> {}
</span></span><span style="display:flex;"><span>  <span style="color:#75715e">-- set up newObj</span>
</span></span><span style="display:flex;"><span>  self.__index <span style="color:#f92672">=</span> self
</span></span><span style="display:flex;"><span>  <span style="color:#66d9ef">return</span> setmetatable(newObj, self)
</span></span><span style="display:flex;"><span><span style="color:#66d9ef">end</span></span></span></code
        ><button onclick="copyCode(this)" class="copybtn">copy</button></pre></details>

  <script>
    function copyCode(btn) {
      const code = btn.previousElementSibling.textContent.trim();
      navigator.clipboard.writeText(code).then(() => {
        btn.innerText = "copied";
        setTimeout(() => (btn.innerText = "copy"), 2000);
      });
    }
  </script><h2 id="module">
  <a class="anchor inpage" href="#module">##</a>module</h2>
<details open>
    <summary>lua</summary><pre
        class="chroma codeblock"
      ><code class="language-lua" data-lang="lua"
          ><span style="display:flex;"><span><span style="color:#66d9ef">local</span> M <span style="color:#f92672">=</span> {}
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span><span style="color:#66d9ef">local</span> <span style="color:#66d9ef">function</span> <span style="color:#a6e22e">sayMyName</span>()
</span></span><span style="display:flex;"><span>  print(<span style="color:#e6db74">&#39;Hrunkner&#39;</span>)
</span></span><span style="display:flex;"><span><span style="color:#66d9ef">end</span>
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span><span style="color:#66d9ef">function</span> <span style="color:#a6e22e">M</span>.<span style="color:#a6e22e">sayHello</span>()
</span></span><span style="display:flex;"><span>  print(<span style="color:#e6db74">&#39;Why hello there&#39;</span>)
</span></span><span style="display:flex;"><span>  sayMyName()
</span></span><span style="display:flex;"><span><span style="color:#66d9ef">end</span>
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span><span style="color:#66d9ef">return</span> M
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span><span style="color:#75715e">-- Another file can use mod.lua&#39;s functionality:</span>
</span></span><span style="display:flex;"><span><span style="color:#66d9ef">local</span> mod <span style="color:#f92672">=</span> require(<span style="color:#e6db74">&#39;mod&#39;</span>)  <span style="color:#75715e">-- Run the file mod.lua.</span>
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span><span style="color:#75715e">-- require is the standard way to include modules.</span>
</span></span><span style="display:flex;"><span><span style="color:#75715e">-- require acts like:     (if not cached; see below)</span>
</span></span><span style="display:flex;"><span><span style="color:#66d9ef">local</span> mod <span style="color:#f92672">=</span> (<span style="color:#66d9ef">function</span> ()
</span></span><span style="display:flex;"><span>  <span style="color:#f92672">&lt;</span>contents of mod.lua<span style="color:#f92672">&gt;</span>
</span></span><span style="display:flex;"><span><span style="color:#66d9ef">end</span>)()
</span></span><span style="display:flex;"><span><span style="color:#75715e">-- It&#39;s like mod.lua is a function body, so that</span>
</span></span><span style="display:flex;"><span><span style="color:#75715e">-- locals inside mod.lua are invisible outside it.</span>
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span><span style="color:#75715e">-- This works because mod here = M in mod.lua:</span>
</span></span><span style="display:flex;"><span>mod.sayHello() <span style="color:#75715e">-- Prints: Why hello there Hrunkner</span>
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span><span style="color:#75715e">-- This is wrong; sayMyName only exists in mod.lua:</span>
</span></span><span style="display:flex;"><span>mod.sayMyName()  <span style="color:#75715e">-- error</span>
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span><span style="color:#75715e">-- require&#39;s return values are cached so a file is</span>
</span></span><span style="display:flex;"><span><span style="color:#75715e">-- run at most once, even when require&#39;d many times.</span>
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span><span style="color:#75715e">-- Suppose mod2.lua contains &#34;print(&#39;Hi!&#39;)&#34;.</span>
</span></span><span style="display:flex;"><span><span style="color:#66d9ef">local</span> a <span style="color:#f92672">=</span> require(<span style="color:#e6db74">&#39;mod2&#39;</span>)  <span style="color:#75715e">-- Prints Hi!</span>
</span></span><span style="display:flex;"><span><span style="color:#66d9ef">local</span> b <span style="color:#f92672">=</span> require(<span style="color:#e6db74">&#39;mod2&#39;</span>)  <span style="color:#75715e">-- Doesn&#39;t print; a=b.</span>
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span><span style="color:#75715e">-- dofile is like require without caching:</span>
</span></span><span style="display:flex;"><span>dofile(<span style="color:#e6db74">&#39;mod2.lua&#39;</span>)  <span style="color:#75715e">--&gt; Hi!</span>
</span></span><span style="display:flex;"><span>dofile(<span style="color:#e6db74">&#39;mod2.lua&#39;</span>)  <span style="color:#75715e">--&gt; Hi! (runs it again)</span>
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span><span style="color:#75715e">-- loadfile loads a lua file but doesn&#39;t run it yet.</span>
</span></span><span style="display:flex;"><span>f <span style="color:#f92672">=</span> loadfile(<span style="color:#e6db74">&#39;mod2.lua&#39;</span>)  <span style="color:#75715e">-- Call f() to run it.</span>
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span><span style="color:#75715e">-- load is loadfile for strings.</span>
</span></span><span style="display:flex;"><span><span style="color:#75715e">-- (loadstring is deprecated, use load instead)</span>
</span></span><span style="display:flex;"><span>g <span style="color:#f92672">=</span> load(<span style="color:#e6db74">&#39;print(343)&#39;</span>)  <span style="color:#75715e">-- Returns a function.</span>
</span></span><span style="display:flex;"><span>g()  <span style="color:#75715e">-- Prints out 343; nothing printed before now.</span></span></span></code
        ><button onclick="copyCode(this)" class="copybtn">copy</button></pre></details>

  <script>
    function copyCode(btn) {
      const code = btn.previousElementSibling.textContent.trim();
      navigator.clipboard.writeText(code).then(() => {
        btn.innerText = "copied";
        setTimeout(() => (btn.innerText = "copy"), 2000);
      });
    }
  </script><h2 id="misc">
  <a class="anchor inpage" href="#misc">##</a>misc</h2>
<h3 id="comment">
  <a class="anchor inpage" href="#comment">###</a>comment</h3>
<details open>
    <summary>shell</summary><pre
        class="chroma codeblock"
      ><code class="language-shell" data-lang="shell"
          ><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span>-- Two dashes start a one-line comment.
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span>--<span style="color:#f92672">[[</span>
</span></span><span style="display:flex;"><span>     Adding two <span style="color:#f92672">[</span><span style="color:#e6db74">&#39;s and ]&#39;</span>s makes it a
</span></span><span style="display:flex;"><span>     multi-line comment.
</span></span><span style="display:flex;"><span>--<span style="color:#f92672">]]</span></span></span></code
        ><button onclick="copyCode(this)" class="copybtn">copy</button></pre></details>

  <script>
    function copyCode(btn) {
      const code = btn.previousElementSibling.textContent.trim();
      navigator.clipboard.writeText(code).then(() => {
        btn.innerText = "copied";
        setTimeout(() => (btn.innerText = "copy"), 2000);
      });
    }
  </script><h2 id="ref">
  <a class="anchor inpage" href="#ref">##</a>ref</h2>
<p>
</p>
<details open>
    <summary>lua</summary><pre
        class="chroma codeblock"
      ><code class="language-lua" data-lang="lua"
          ><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span><span style="color:#75715e">----------------------------------------------------</span>
</span></span><span style="display:flex;"><span><span style="color:#75715e">-- 1. Variables and flow control.</span>
</span></span><span style="display:flex;"><span><span style="color:#75715e">----------------------------------------------------</span>
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span><span style="color:#75715e">-- Blocks are denoted with keywords like do/end:</span>
</span></span><span style="display:flex;"><span><span style="color:#66d9ef">while</span> num <span style="color:#f92672">&lt;</span> <span style="color:#ae81ff">50</span> <span style="color:#66d9ef">do</span>
</span></span><span style="display:flex;"><span>  num <span style="color:#f92672">=</span> num <span style="color:#f92672">+</span> <span style="color:#ae81ff">1</span>  <span style="color:#75715e">-- No ++ or += type operators.</span>
</span></span><span style="display:flex;"><span><span style="color:#66d9ef">end</span>
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span><span style="color:#75715e">-- If clauses:</span>
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span><span style="color:#75715e">----------------------------------------------------</span>
</span></span><span style="display:flex;"><span><span style="color:#75715e">-- 2. Functions.</span>
</span></span><span style="display:flex;"><span><span style="color:#75715e">----------------------------------------------------</span>
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span><span style="color:#75715e">----------------------------------------------------</span>
</span></span><span style="display:flex;"><span><span style="color:#75715e">-- 3. Tables.</span>
</span></span><span style="display:flex;"><span><span style="color:#75715e">----------------------------------------------------</span>
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span><span style="color:#75715e">-- Tables = Lua&#39;s only compound data structure;</span>
</span></span><span style="display:flex;"><span><span style="color:#75715e">--          they are associative arrays.</span>
</span></span><span style="display:flex;"><span><span style="color:#75715e">-- Similar to php arrays or js objects, they are</span>
</span></span><span style="display:flex;"><span><span style="color:#75715e">-- hash-lookup dicts that can also be used as lists.</span>
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span><span style="color:#75715e">-- Using tables as dictionaries / maps:</span>
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span><span style="color:#75715e">-- Dict literals have string keys by default:</span>
</span></span><span style="display:flex;"><span>t <span style="color:#f92672">=</span> {key1 <span style="color:#f92672">=</span> <span style="color:#e6db74">&#39;value1&#39;</span>, key2 <span style="color:#f92672">=</span> <span style="color:#66d9ef">false</span>}
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span><span style="color:#75715e">-- String keys can use js-like dot notation:</span>
</span></span><span style="display:flex;"><span>print(t.key1)  <span style="color:#75715e">-- Prints &#39;value1&#39;.</span>
</span></span><span style="display:flex;"><span>t.newKey <span style="color:#f92672">=</span> {}  <span style="color:#75715e">-- Adds a new key/value pair.</span>
</span></span><span style="display:flex;"><span>t.key2 <span style="color:#f92672">=</span> <span style="color:#66d9ef">nil</span>   <span style="color:#75715e">-- Removes key2 from the table.</span>
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span><span style="color:#75715e">-- Literal notation for any (non-nil) value as key:</span>
</span></span><span style="display:flex;"><span>u <span style="color:#f92672">=</span> {[<span style="color:#e6db74">&#39;@!#&#39;</span>] <span style="color:#f92672">=</span> <span style="color:#e6db74">&#39;qbert&#39;</span>, [{}] <span style="color:#f92672">=</span> <span style="color:#ae81ff">1729</span>, [<span style="color:#ae81ff">6.28</span>] <span style="color:#f92672">=</span> <span style="color:#e6db74">&#39;tau&#39;</span>}
</span></span><span style="display:flex;"><span>print(u[<span style="color:#ae81ff">6.28</span>])  <span style="color:#75715e">-- prints &#34;tau&#34;</span>
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span><span style="color:#75715e">-- Key matching is basically by value for numbers</span>
</span></span><span style="display:flex;"><span><span style="color:#75715e">-- and strings, but by identity for tables.</span>
</span></span><span style="display:flex;"><span>a <span style="color:#f92672">=</span> u[<span style="color:#e6db74">&#39;@!#&#39;</span>]  <span style="color:#75715e">-- Now a = &#39;qbert&#39;.</span>
</span></span><span style="display:flex;"><span>b <span style="color:#f92672">=</span> u[{}]     <span style="color:#75715e">-- We might expect 1729, but it&#39;s nil:</span>
</span></span><span style="display:flex;"><span><span style="color:#75715e">-- b = nil since the lookup fails. It fails</span>
</span></span><span style="display:flex;"><span><span style="color:#75715e">-- because the key we used is not the same object</span>
</span></span><span style="display:flex;"><span><span style="color:#75715e">-- as the one used to store the original value. So</span>
</span></span><span style="display:flex;"><span><span style="color:#75715e">-- strings &amp; numbers are more portable keys.</span>
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span><span style="color:#75715e">-- A one-table-param function call needs no parens:</span>
</span></span><span style="display:flex;"><span><span style="color:#66d9ef">function</span> <span style="color:#a6e22e">h</span>(x) print(x.key1) <span style="color:#66d9ef">end</span>
</span></span><span style="display:flex;"><span>h{key1 <span style="color:#f92672">=</span> <span style="color:#e6db74">&#39;Sonmi~451&#39;</span>}  <span style="color:#75715e">-- Prints &#39;Sonmi~451&#39;.</span>
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span><span style="color:#66d9ef">for</span> key, val <span style="color:#66d9ef">in</span> pairs(u) <span style="color:#66d9ef">do</span>  <span style="color:#75715e">-- Table iteration.</span>
</span></span><span style="display:flex;"><span>  print(key, val)
</span></span><span style="display:flex;"><span><span style="color:#66d9ef">end</span>
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span><span style="color:#75715e">-- _G is a special table of all globals.</span>
</span></span><span style="display:flex;"><span>print(_G[<span style="color:#e6db74">&#39;_G&#39;</span>] <span style="color:#f92672">==</span> _G)  <span style="color:#75715e">-- Prints &#39;true&#39;.</span>
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span><span style="color:#75715e">-- Using tables as lists / arrays:</span>
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span><span style="color:#75715e">-- List literals implicitly set up int keys:</span>
</span></span><span style="display:flex;"><span>v <span style="color:#f92672">=</span> {<span style="color:#e6db74">&#39;value1&#39;</span>, <span style="color:#e6db74">&#39;value2&#39;</span>, <span style="color:#ae81ff">1.21</span>, <span style="color:#e6db74">&#39;gigawatts&#39;</span>}
</span></span><span style="display:flex;"><span><span style="color:#66d9ef">for</span> i <span style="color:#f92672">=</span> <span style="color:#ae81ff">1</span>, <span style="color:#f92672">#</span>v <span style="color:#66d9ef">do</span>  <span style="color:#75715e">-- #v is the size of v for lists.</span>
</span></span><span style="display:flex;"><span>  print(v[i])  <span style="color:#75715e">-- Indices start at 1 !! SO CRAZY!</span>
</span></span><span style="display:flex;"><span><span style="color:#66d9ef">end</span>
</span></span><span style="display:flex;"><span><span style="color:#75715e">-- A &#39;list&#39; is not a real type. v is just a table</span>
</span></span><span style="display:flex;"><span><span style="color:#75715e">-- with consecutive integer keys, treated as a list.</span>
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span><span style="color:#75715e">----------------------------------------------------</span>
</span></span><span style="display:flex;"><span><span style="color:#75715e">-- 3.1 Metatables and metamethods.</span>
</span></span><span style="display:flex;"><span><span style="color:#75715e">----------------------------------------------------</span>
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span><span style="color:#75715e">-- A table can have a metatable that gives the table</span>
</span></span><span style="display:flex;"><span><span style="color:#75715e">-- operator-overloadish behavior. Later we&#39;ll see</span>
</span></span><span style="display:flex;"><span><span style="color:#75715e">-- how metatables support js-prototype behavior.</span>
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span>f1 <span style="color:#f92672">=</span> {a <span style="color:#f92672">=</span> <span style="color:#ae81ff">1</span>, b <span style="color:#f92672">=</span> <span style="color:#ae81ff">2</span>}  <span style="color:#75715e">-- Represents the fraction a/b.</span>
</span></span><span style="display:flex;"><span>f2 <span style="color:#f92672">=</span> {a <span style="color:#f92672">=</span> <span style="color:#ae81ff">2</span>, b <span style="color:#f92672">=</span> <span style="color:#ae81ff">3</span>}
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span><span style="color:#75715e">-- This would fail:</span>
</span></span><span style="display:flex;"><span><span style="color:#75715e">-- s = f1 + f2</span>
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span>metafraction <span style="color:#f92672">=</span> {}
</span></span><span style="display:flex;"><span><span style="color:#66d9ef">function</span> <span style="color:#a6e22e">metafraction</span>.<span style="color:#a6e22e">__add</span>(f1, f2)
</span></span><span style="display:flex;"><span>  sum <span style="color:#f92672">=</span> {}
</span></span><span style="display:flex;"><span>  sum.b <span style="color:#f92672">=</span> f1.b <span style="color:#f92672">*</span> f2.b
</span></span><span style="display:flex;"><span>  sum.a <span style="color:#f92672">=</span> f1.a <span style="color:#f92672">*</span> f2.b <span style="color:#f92672">+</span> f2.a <span style="color:#f92672">*</span> f1.b
</span></span><span style="display:flex;"><span>  <span style="color:#66d9ef">return</span> sum
</span></span><span style="display:flex;"><span><span style="color:#66d9ef">end</span>
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span>setmetatable(f1, metafraction)
</span></span><span style="display:flex;"><span>setmetatable(f2, metafraction)
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span>s <span style="color:#f92672">=</span> f1 <span style="color:#f92672">+</span> f2  <span style="color:#75715e">-- call __add(f1, f2) on f1&#39;s metatable</span>
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span><span style="color:#75715e">-- f1, f2 have no key for their metatable, unlike</span>
</span></span><span style="display:flex;"><span><span style="color:#75715e">-- prototypes in js, so you must retrieve it as in</span>
</span></span><span style="display:flex;"><span><span style="color:#75715e">-- getmetatable(f1). The metatable is a normal table</span>
</span></span><span style="display:flex;"><span><span style="color:#75715e">-- with keys that Lua knows about, like __add.</span>
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span><span style="color:#75715e">-- But the next line fails since s has no metatable:</span>
</span></span><span style="display:flex;"><span><span style="color:#75715e">-- t = s + s</span>
</span></span><span style="display:flex;"><span><span style="color:#75715e">-- Class-like patterns given below would fix this.</span>
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span><span style="color:#75715e">-- An __index on a metatable overloads dot lookups:</span>
</span></span><span style="display:flex;"><span>defaultFavs <span style="color:#f92672">=</span> {animal <span style="color:#f92672">=</span> <span style="color:#e6db74">&#39;gru&#39;</span>, food <span style="color:#f92672">=</span> <span style="color:#e6db74">&#39;donuts&#39;</span>}
</span></span><span style="display:flex;"><span>myFavs <span style="color:#f92672">=</span> {food <span style="color:#f92672">=</span> <span style="color:#e6db74">&#39;pizza&#39;</span>}
</span></span><span style="display:flex;"><span>setmetatable(myFavs, {__index <span style="color:#f92672">=</span> defaultFavs})
</span></span><span style="display:flex;"><span>eatenBy <span style="color:#f92672">=</span> myFavs.animal  <span style="color:#75715e">-- works! thanks, metatable</span>
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span><span style="color:#75715e">-- Direct table lookups that fail will retry using</span>
</span></span><span style="display:flex;"><span><span style="color:#75715e">-- the metatable&#39;s __index value, and this recurses.</span>
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span><span style="color:#75715e">-- An __index value can also be a function(tbl, key)</span>
</span></span><span style="display:flex;"><span><span style="color:#75715e">-- for more customized lookups.</span>
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span><span style="color:#75715e">-- Values of __index,add, .. are called metamethods.</span>
</span></span><span style="display:flex;"><span><span style="color:#75715e">-- Full list. Here a is a table with the metamethod.</span>
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span><span style="color:#75715e">-- __add(a, b)                     for a + b</span>
</span></span><span style="display:flex;"><span><span style="color:#75715e">-- __sub(a, b)                     for a - b</span>
</span></span><span style="display:flex;"><span><span style="color:#75715e">-- __mul(a, b)                     for a * b</span>
</span></span><span style="display:flex;"><span><span style="color:#75715e">-- __div(a, b)                     for a / b</span>
</span></span><span style="display:flex;"><span><span style="color:#75715e">-- __mod(a, b)                     for a % b</span>
</span></span><span style="display:flex;"><span><span style="color:#75715e">-- __pow(a, b)                     for a ^ b</span>
</span></span><span style="display:flex;"><span><span style="color:#75715e">-- __unm(a)                        for -a</span>
</span></span><span style="display:flex;"><span><span style="color:#75715e">-- __concat(a, b)                  for a .. b</span>
</span></span><span style="display:flex;"><span><span style="color:#75715e">-- __len(a)                        for #a</span>
</span></span><span style="display:flex;"><span><span style="color:#75715e">-- __eq(a, b)                      for a == b</span>
</span></span><span style="display:flex;"><span><span style="color:#75715e">-- __lt(a, b)                      for a &lt; b</span>
</span></span><span style="display:flex;"><span><span style="color:#75715e">-- __le(a, b)                      for a &lt;= b</span>
</span></span><span style="display:flex;"><span><span style="color:#75715e">-- __index(a, b)  &lt;fn or a table&gt;  for a.b</span>
</span></span><span style="display:flex;"><span><span style="color:#75715e">-- __newindex(a, b, c)             for a.b = c</span>
</span></span><span style="display:flex;"><span><span style="color:#75715e">-- __call(a, ...)                  for a(...)</span>
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span><span style="color:#75715e">----------------------------------------------------</span>
</span></span><span style="display:flex;"><span><span style="color:#75715e">-- 3.2 Class-like tables and inheritance.</span>
</span></span><span style="display:flex;"><span><span style="color:#75715e">----------------------------------------------------</span>
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span><span style="color:#75715e">-- Classes aren&#39;t built in; there are different ways</span>
</span></span><span style="display:flex;"><span><span style="color:#75715e">-- to make them using tables and metatables.</span>
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span><span style="color:#75715e">----------------------------------------------------</span>
</span></span><span style="display:flex;"><span><span style="color:#75715e">-- 4. Modules.</span>
</span></span><span style="display:flex;"><span><span style="color:#75715e">----------------------------------------------------</span>
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span><span style="color:#75715e">--[[ I&#39;m commenting out this section so the rest of
</span></span></span><span style="display:flex;"><span><span style="color:#75715e">--   this script remains runnable.
</span></span></span><span style="display:flex;"><span><span style="color:#75715e">-- Suppose the file mod.lua looks like this:
</span></span></span><span style="display:flex;"><span><span style="color:#75715e">local M = {}
</span></span></span><span style="display:flex;"><span><span style="color:#75715e">
</span></span></span><span style="display:flex;"><span><span style="color:#75715e">local function sayMyName()
</span></span></span><span style="display:flex;"><span><span style="color:#75715e">  print(&#39;Hrunkner&#39;)
</span></span></span><span style="display:flex;"><span><span style="color:#75715e">end
</span></span></span><span style="display:flex;"><span><span style="color:#75715e">
</span></span></span><span style="display:flex;"><span><span style="color:#75715e">function M.sayHello()
</span></span></span><span style="display:flex;"><span><span style="color:#75715e">  print(&#39;Why hello there&#39;)
</span></span></span><span style="display:flex;"><span><span style="color:#75715e">  sayMyName()
</span></span></span><span style="display:flex;"><span><span style="color:#75715e">end
</span></span></span><span style="display:flex;"><span><span style="color:#75715e">
</span></span></span><span style="display:flex;"><span><span style="color:#75715e">return M
</span></span></span><span style="display:flex;"><span><span style="color:#75715e">
</span></span></span><span style="display:flex;"><span><span style="color:#75715e">-- Another file can use mod.lua&#39;s functionality:
</span></span></span><span style="display:flex;"><span><span style="color:#75715e">local mod = require(&#39;mod&#39;)  -- Run the file mod.lua.
</span></span></span><span style="display:flex;"><span><span style="color:#75715e">
</span></span></span><span style="display:flex;"><span><span style="color:#75715e">-- require is the standard way to include modules.
</span></span></span><span style="display:flex;"><span><span style="color:#75715e">-- require acts like:     (if not cached; see below)
</span></span></span><span style="display:flex;"><span><span style="color:#75715e">local mod = (function ()
</span></span></span><span style="display:flex;"><span><span style="color:#75715e">  &lt;contents of mod.lua&gt;
</span></span></span><span style="display:flex;"><span><span style="color:#75715e">end)()
</span></span></span><span style="display:flex;"><span><span style="color:#75715e">-- It&#39;s like mod.lua is a function body, so that
</span></span></span><span style="display:flex;"><span><span style="color:#75715e">-- locals inside mod.lua are invisible outside it.
</span></span></span><span style="display:flex;"><span><span style="color:#75715e">
</span></span></span><span style="display:flex;"><span><span style="color:#75715e">-- This works because mod here = M in mod.lua:
</span></span></span><span style="display:flex;"><span><span style="color:#75715e">mod.sayHello() -- Prints: Why hello there Hrunkner
</span></span></span><span style="display:flex;"><span><span style="color:#75715e">
</span></span></span><span style="display:flex;"><span><span style="color:#75715e">-- This is wrong; sayMyName only exists in mod.lua:
</span></span></span><span style="display:flex;"><span><span style="color:#75715e">mod.sayMyName()  -- error
</span></span></span><span style="display:flex;"><span><span style="color:#75715e">
</span></span></span><span style="display:flex;"><span><span style="color:#75715e">-- require&#39;s return values are cached so a file is
</span></span></span><span style="display:flex;"><span><span style="color:#75715e">-- run at most once, even when require&#39;d many times.
</span></span></span><span style="display:flex;"><span><span style="color:#75715e">
</span></span></span><span style="display:flex;"><span><span style="color:#75715e">-- Suppose mod2.lua contains &#34;print(&#39;Hi!&#39;)&#34;.
</span></span></span><span style="display:flex;"><span><span style="color:#75715e">local a = require(&#39;mod2&#39;)  -- Prints Hi!
</span></span></span><span style="display:flex;"><span><span style="color:#75715e">local b = require(&#39;mod2&#39;)  -- Doesn&#39;t print; a=b.
</span></span></span><span style="display:flex;"><span><span style="color:#75715e">
</span></span></span><span style="display:flex;"><span><span style="color:#75715e">-- dofile is like require without caching:
</span></span></span><span style="display:flex;"><span><span style="color:#75715e">dofile(&#39;mod2.lua&#39;)  --&gt; Hi!
</span></span></span><span style="display:flex;"><span><span style="color:#75715e">dofile(&#39;mod2.lua&#39;)  --&gt; Hi! (runs it again)
</span></span></span><span style="display:flex;"><span><span style="color:#75715e">
</span></span></span><span style="display:flex;"><span><span style="color:#75715e">-- loadfile loads a lua file but doesn&#39;t run it yet.
</span></span></span><span style="display:flex;"><span><span style="color:#75715e">f = loadfile(&#39;mod2.lua&#39;)  -- Call f() to run it.
</span></span></span><span style="display:flex;"><span><span style="color:#75715e">
</span></span></span><span style="display:flex;"><span><span style="color:#75715e">-- load is loadfile for strings.
</span></span></span><span style="display:flex;"><span><span style="color:#75715e">-- (loadstring is deprecated, use load instead)
</span></span></span><span style="display:flex;"><span><span style="color:#75715e">g = load(&#39;print(343)&#39;)  -- Returns a function.
</span></span></span><span style="display:flex;"><span><span style="color:#75715e">g()  -- Prints out 343; nothing printed before now.
</span></span></span><span style="display:flex;"><span><span style="color:#75715e">
</span></span></span><span style="display:flex;"><span><span style="color:#75715e">--]]</span></span></span></code
        ><button onclick="copyCode(this)" class="copybtn">copy</button></pre></details>

  <script>
    function copyCode(btn) {
      const code = btn.previousElementSibling.textContent.trim();
      navigator.clipboard.writeText(code).then(() => {
        btn.innerText = "copied";
        setTimeout(() => (btn.innerText = "copy"), 2000);
      });
    }
  </script>]]></content:encoded></item><item><title>caldav协议</title><link>https://hiraethecho.github.io/docs/dev/caldav/</link><pubDate>Mon, 30 Jun 2025 00:00:00 +0000</pubDate><author>wyz2016zxc@outlook.com(Hiraeth)</author><guid>https://hiraethecho.github.io/docs/dev/caldav/</guid><description>caldav是一个基于webdav的日历协议，可以用来同步日历数据。它是一个开放的标准，允许不同的日历应用程序和服务之间进行互操作。</description><content:encoded><![CDATA[<h1 id="caldav">
  <a class="anchor inpage" href="#caldav">#</a>Caldav</h1>
<h2 id="caldav-1">
  <a class="anchor inpage" href="#caldav-1">##</a>caldav</h2>
<p>caldav是一个基于webdav的日历协议，可以用来同步日历数据。它是一个开放的标准，允许不同的日历应用程序和服务之间进行互操作。</p>
<p>包括calendar、todo、event等。</p>
<h2 id="manage">
  <a class="anchor inpage" href="#manage">##</a>manage</h2>
<h3 id="todoman">
  <a class="anchor inpage" href="#todoman">###</a>todoman</h3>
<h3 id="khal">
  <a class="anchor inpage" href="#khal">###</a>khal</h3>
<h3 id="apple">
  <a class="anchor inpage" href="#apple">###</a>apple</h3>
<p>原生日历和提醒事项应用程序可以通过CalDAV协议与服务器进行同步。</p>
<h2 id="host-a-caldav">
  <a class="anchor inpage" href="#host-a-caldav">##</a>host a caldav</h2>
<h3 id="radicale">
  <a class="anchor inpage" href="#radicale">###</a>radicale</h3>
<h4 id="install-and-configurations">
  <a class="anchor inpage" href="#install-and-configurations">####</a>Install and configurations</h4>
<p>ref: 
:</p>
<p>Install radicale: 建议用包管理器安装，可以帮助解决依赖，以及创建<code>radicale</code>用户、创建文件夹之类的杂事。比如</p>
<details open>
    <summary>sh</summary><pre
        class="chroma codeblock"
      ><code class="language-sh" data-lang="sh"
          ><span style="display:flex;"><span>sudo dnf install radicale</span></span></code
        ><button onclick="copyCode(this)" class="copybtn">copy</button></pre></details>

  <script>
    function copyCode(btn) {
      const code = btn.previousElementSibling.textContent.trim();
      navigator.clipboard.writeText(code).then(() => {
        btn.innerText = "copied";
        setTimeout(() => (btn.innerText = "copy"), 2000);
      });
    }
  </script><p>configurations:</p>
<details open>
    <summary>TEXT</summary><pre
        class="codeblock"
      ><code class="language-" data-lang=""># /etc/radicale/config

[server]
hosts = [::]:5242, 0.0.0.0:5242 # ipv6, ipv4的host，从任何ip地址都可以访问
# hosts = localhost:5242 # 只允许本地地址访问
[auth]
type = htpasswd
htpasswd_encryption = autodetect
htpasswd_filename = /etc/radicale/users
[storage]
filesystem_folder = /var/lib/radicale/collections</code><button onclick="copyCode(this)" class="copybtn">copy</button></pre></details>

  <script>
    function copyCode(btn) {
      const code = btn.previousElementSibling.textContent.trim();
      navigator.clipboard.writeText(code).then(() => {
        btn.innerText = "copied";
        setTimeout(() => (btn.innerText = "copy"), 2000);
      });
    }
  </script><p>set a user and passwd:</p>
<details open>
    <summary>shell</summary><pre
        class="chroma codeblock"
      ><code class="language-shell" data-lang="shell"
          ><span style="display:flex;"><span>htpasswd -5 -c /path/to/users user1</span></span></code
        ><button onclick="copyCode(this)" class="copybtn">copy</button></pre></details>

  <script>
    function copyCode(btn) {
      const code = btn.previousElementSibling.textContent.trim();
      navigator.clipboard.writeText(code).then(() => {
        btn.innerText = "copied";
        setTimeout(() => (btn.innerText = "copy"), 2000);
      });
    }
  </script><p>Start as a systemd service:</p>
<details open>
    <summary>TEXT</summary><pre
        class="codeblock"
      ><code class="language-" data-lang=""># /etc/systemd/system/radicale.service
[Unit]
Description=A simple CalDAV (calendar) and CardDAV (contact) server
After=network.target
Requires=network.target

[Service]
ExecStart=/usr/bin/radicale --config /etc/radicale/confif
Restart=on-failure
User=radicale
# Deny other users access to the calendar data
UMask=0027
# Optional security settings
PrivateTmp=true
ProtectSystem=strict
ProtectHome=true
PrivateDevices=true
ProtectKernelTunables=true
ProtectKernelModules=true
ProtectControlGroups=true
NoNewPrivileges=true
ReadWritePaths=/var/lib/radicale/ /var/cache/radicale/

[Install]
WantedBy=multi-user.target</code><button onclick="copyCode(this)" class="copybtn">copy</button></pre></details>

  <script>
    function copyCode(btn) {
      const code = btn.previousElementSibling.textContent.trim();
      navigator.clipboard.writeText(code).then(() => {
        btn.innerText = "copied";
        setTimeout(() => (btn.innerText = "copy"), 2000);
      });
    }
  </script><p>这样在<code>http://localhost:5242/</code>就可以访问web页面，可以创建collection等。</p>
<h4 id="host">
  <a class="anchor inpage" href="#host">####</a>host</h4>
<p>用<code>cloudflare</code>的zero trust - network - tunnel来将radicale服务暴露到公网。记得选https。</p>
<h3 id="baikal">
  <a class="anchor inpage" href="#baikal">###</a>baikal</h3>
<h2 id="connect-a-caldav">
  <a class="anchor inpage" href="#connect-a-caldav">##</a>connect a caldav</h2>
<h3 id="from-linux">
  <a class="anchor inpage" href="#from-linux">###</a>from linux</h3>
<p>vdirsync</p>
<h3 id="from-apple-to-caldav-server">
  <a class="anchor inpage" href="#from-apple-to-caldav-server">###</a>from apple to caldav server</h3>
<h3 id="to-apple-caldav">
  <a class="anchor inpage" href="#to-apple-caldav">###</a>To apple caldav</h3>
<p>ref:</p>
<ul>
<li>
</li>
<li>
</li>
</ul>
<p>云上贵州服务器</p>
<details open>
    <summary>TEXT</summary><pre
        class="codeblock"
      ><code class="language-" data-lang="">https://&lt;server-id&gt;-caldav.icloud.com.cn/&lt;user-id&gt;/calendars/&lt;calendar-id&gt;/</code><button onclick="copyCode(this)" class="copybtn">copy</button></pre></details>

  <script>
    function copyCode(btn) {
      const code = btn.previousElementSibling.textContent.trim();
      navigator.clipboard.writeText(code).then(() => {
        btn.innerText = "copied";
        setTimeout(() => (btn.innerText = "copy"), 2000);
      });
    }
  </script><p>在网页版icloud的日历界面打开开发者工具，然后找<code>Network</code>里的<code>Get</code>请求，过滤<code>XHR</code>，然后找类似 <code>https://&lt;server-id&gt;-calendarws.icloud.com.cn/ca/eventdetail/&lt;calendar-id&gt;/&lt;event-id&gt;?clientBuildNumber=&lt;some-random-text&gt;&amp;clientId=&lt;some-random-text&gt;&amp;clientMasteringNumber=&lt;some-random-text&gt;&amp;clientVersion=&lt;some-random-text&gt;&amp;dsid=&lt;user-id&gt;&amp;lang=&lt;some-random-text&gt;&amp;requestID=&lt;some-random-text&gt;&amp;usertz=&lt;some-random-text&gt;</code>的内容。</p>
<p>用 
 将<code>icloud</code>的日历同步到本地，以<code>.ics</code>格式存储。</p>
<details open>
    <summary>conf</summary><pre
        class="codeblock"
      ><code class="language-conf" data-lang="conf">[storage cal]
type = &#34;caldav&#34;
url = &#34;https://caldav.icloud.com/&#34;
username = &#34;...&#34;
password = &#34;...&#34;

[storage card]
type = &#34;carddav&#34;
url = &#34;https://contacts.icloud.com/&#34;
username = &#34;...&#34;
password = &#34;...&#34;</code><button onclick="copyCode(this)" class="copybtn">copy</button></pre></details>

  <script>
    function copyCode(btn) {
      const code = btn.previousElementSibling.textContent.trim();
      navigator.clipboard.writeText(code).then(() => {
        btn.innerText = "copied";
        setTimeout(() => (btn.innerText = "copy"), 2000);
      });
    }
  </script><p>这里<code>username</code>就是用户名，而<code>password</code>是双重认证后再生成的app密码。服务器的话中国应该要<code>url = &quot;https://caldav.icloud.com.cn/&quot;</code></p>
<p>但是有两个问题：</p>
<ul>
<li>不支持<code>VTODO</code>格式，apple的提醒事项似乎不是这个协议。</li>
<li><code>icloud</code>如果有多个日历的话，标识id很长，难以记忆或使用，例如<code>87BBBA05-934B-4D5A-BB27-771A9CD413A2</code>。或者其中一个会被记为<code>home</code>，但是不知道什么规则。例如同步到<code>.local/share/calendars</code>后
<details open>
    <summary>TEXT</summary><pre
        class="codeblock"
      ><code class="language-" data-lang="">~/.local/share/calendars
├── 87BBBA05-934B-4D5A-BB27-771A9CD413A2
└── home</code><button onclick="copyCode(this)" class="copybtn">copy</button></pre></details>

  <script>
    function copyCode(btn) {
      const code = btn.previousElementSibling.textContent.trim();
      navigator.clipboard.writeText(code).then(() => {
        btn.innerText = "copied";
        setTimeout(() => (btn.innerText = "copy"), 2000);
      });
    }
  </script></li>
</ul>
]]></content:encoded></item><item><title>pake打包web应用</title><link>https://hiraethecho.github.io/docs/dev/pake/</link><pubDate>Sun, 08 Jun 2025 00:00:00 +0000</pubDate><author>wyz2016zxc@outlook.com(Hiraeth)</author><guid>https://hiraethecho.github.io/docs/dev/pake/</guid><description>&lt;h1 id="pake打包web应用"&gt;
&lt;a class="anchor inpage" href="#pake%e6%89%93%e5%8c%85web%e5%ba%94%e7%94%a8"&gt;#&lt;/a&gt;pake打包web应用&lt;/h1&gt;
&lt;p&gt;
可以将web转化为桌面应用，比&lt;code&gt;electron&lt;/code&gt;更轻量。&lt;/p&gt;
&lt;h2 id="安装pake"&gt;
&lt;a class="anchor inpage" href="#%e5%ae%89%e8%a3%85pake"&gt;##&lt;/a&gt;安装pake&lt;/h2&gt;
&lt;p&gt;用户级安装：&lt;/p&gt;
&lt;details open&gt;
&lt;summary&gt;TEXT&lt;/summary&gt;&lt;pre
class="codeblock"
&gt;&lt;code class="language-" data-lang=""&gt;npm -g install pake-cli&lt;/code&gt;&lt;button onclick="copyCode(this)" class="copybtn"&gt;copy&lt;/button&gt;&lt;/pre&gt;&lt;/details&gt;
&lt;script&gt;
function copyCode(btn) {
const code = btn.previousElementSibling.textContent.trim();
navigator.clipboard.writeText(code).then(() =&gt; {
btn.innerText = "copied";
setTimeout(() =&gt; (btn.innerText = "copy"), 2000);
});
}
&lt;/script&gt;&lt;p&gt;需要&lt;code&gt;rust&lt;/code&gt;等工具链&lt;/p&gt;</description><content:encoded><![CDATA[<h1 id="pake打包web应用">
  <a class="anchor inpage" href="#pake%e6%89%93%e5%8c%85web%e5%ba%94%e7%94%a8">#</a>pake打包web应用</h1>
<p>
可以将web转化为桌面应用，比<code>electron</code>更轻量。</p>
<h2 id="安装pake">
  <a class="anchor inpage" href="#%e5%ae%89%e8%a3%85pake">##</a>安装pake</h2>
<p>用户级安装：</p>
<details open>
    <summary>TEXT</summary><pre
        class="codeblock"
      ><code class="language-" data-lang="">npm -g install pake-cli</code><button onclick="copyCode(this)" class="copybtn">copy</button></pre></details>

  <script>
    function copyCode(btn) {
      const code = btn.previousElementSibling.textContent.trim();
      navigator.clipboard.writeText(code).then(() => {
        btn.innerText = "copied";
        setTimeout(() => (btn.innerText = "copy"), 2000);
      });
    }
  </script><p>需要<code>rust</code>等工具链</p>
<h2 id="打包web应用">
  <a class="anchor inpage" href="#%e6%89%93%e5%8c%85web%e5%ba%94%e7%94%a8">##</a>打包web应用</h2>
<p>例如</p>
<details open>
    <summary>TEXT</summary><pre
        class="codeblock"
      ><code class="language-" data-lang="">pake chat.deepseek.com --name deepseek --width 1080 --height 1920 --show-system-tray --icon 512x512-RGBA.png</code><button onclick="copyCode(this)" class="copybtn">copy</button></pre></details>

  <script>
    function copyCode(btn) {
      const code = btn.previousElementSibling.textContent.trim();
      navigator.clipboard.writeText(code).then(() => {
        btn.innerText = "copied";
        setTimeout(() => (btn.innerText = "copy"), 2000);
      });
    }
  </script><p>要注意的是分辨率设置，以及icon格式为512x512的png，似乎必须是<code>RGBA</code></p>
<p>会得到<code>deepseek.deb</code>，内部结构为</p>
<details open>
    <summary>deb</summary><pre
        class="codeblock"
      ><code class="language-deb" data-lang="deb">control.tar.gz
data.tar.gz
debian-binary</code><button onclick="copyCode(this)" class="copybtn">copy</button></pre></details>

  <script>
    function copyCode(btn) {
      const code = btn.previousElementSibling.textContent.trim();
      navigator.clipboard.writeText(code).then(() => {
        btn.innerText = "copied";
        setTimeout(() => (btn.innerText = "copy"), 2000);
      });
    }
  </script><p>主要程序在<code>data.tar.gz</code>里面，用<code>tar -xvf data.tar.gz</code>得到</p>
<details open>
    <summary>usr</summary><pre
        class="codeblock"
      ><code class="language-usr" data-lang="usr"> usr
├──  bin
│   └──  pake
├──  lib
│   └──  deepseek
│       └──  png
│           └──  deepseek_512.png
└──  share
    ├──  applications
    │   └──  deepseek.desktop
    └──  icons
        └──  hicolor
            └──  512x512
                └──  apps
                    └──  pake.png</code><button onclick="copyCode(this)" class="copybtn">copy</button></pre></details>

  <script>
    function copyCode(btn) {
      const code = btn.previousElementSibling.textContent.trim();
      navigator.clipboard.writeText(code).then(() => {
        btn.innerText = "copied";
        setTimeout(() => (btn.innerText = "copy"), 2000);
      });
    }
  </script><p>其中<code>usr/bin/pake</code>是单二进制文件，可以直接运行<code>./usr/bin/pake</code>。其他的是快捷方式<code>usr/share/application/deepseek.desktop</code>和图标等。</p>
<h2 id="on-arch">
  <a class="anchor inpage" href="#on-arch">##</a>On Arch</h2>
<p>在<code>archlinux</code>上可以将其做成<code>.zst</code>格式的包，用<code>pacman</code>管理。</p>
<p>把下面内容写入<code>PKGBUILD</code>文件</p>
<details open>
    <summary>TEXT</summary><pre
        class="codeblock"
      ><code class="language-" data-lang=""># Maintainer: hiraethecho &lt;wyz2016zxc at outlook dot com&gt;
pkgname=&#34;${_appname}-pake&#34;
pkgver=1.0.0
pkgrel=1
pkgdesc=&#34;${_appname} pake&#34;
arch=(&#39;x86_64&#39;)
license=(&#39;MIT&#39;)
conflicts=(&#34;${_appname}-pake&#34;)
depends=(
    &#39;gtk3&#39;
    &#39;webkit2gtk-4.1&#39;
)
source=(
  ${_appname}.deb
)
sha256sums=(&#39;SKIP&#39;)
prepare() {
    bsdtar -xf &#34;${srcdir}/data.&#34;*
    sed -e &#34;
        s/Exec=pake/Exec=${_appname}/g
        s|Icon=pake|Icon=${_appname}|g
    &#34; -i &#34;${srcdir}/usr/share/applications/${_appname}.desktop&#34;
    mv ${srcdir}/usr/share/icons/hicolor/*/apps/pake.png ${srcdir}/usr/share/icons/pake.png
}
package() {
    install -Dm755 &#34;${srcdir}/usr/bin/pake&#34; &#34;${pkgdir}/usr/bin/${_appname}&#34;
    install -Dm644 &#34;${srcdir}/usr/share/applications/${_appname}.desktop&#34; &#34;${pkgdir}/usr/share/applications/${_appname}.desktop&#34;
    install -Dm644 &#34;${srcdir}/usr/share/icons/pake.png&#34; &#34;${pkgdir}/usr/share/pixmaps/${_appname}.png&#34;
}</code><button onclick="copyCode(this)" class="copybtn">copy</button></pre></details>

  <script>
    function copyCode(btn) {
      const code = btn.previousElementSibling.textContent.trim();
      navigator.clipboard.writeText(code).then(() => {
        btn.innerText = "copied";
        setTimeout(() => (btn.innerText = "copy"), 2000);
      });
    }
  </script><p>然后执行这个shell脚本，注意<code>-i</code> <code>-w</code> <code>-n</code>选项</p>
<details open>
    <summary>pake2zst</summary><pre
        class="codeblock"
      ><code class="language-pake2zst" data-lang="pake2zst">#!/usr/bin/bash
# generate a zst from pake
url=&#34;&#34;
icon=&#34;&#34;
name=&#34;&#34;
while getopts &#34;:n:i:w:&#34; opt; do
  case $opt in
  n) name=&#34;$OPTARG&#34; ;;
  i) icon=&#34;$OPTARG&#34; ;;
  w) url=&#34;$OPTARG&#34; ;;
  \?)
    echo &#34;无效选项: -$OPTARG&#34; &gt;&amp;2
    ;;
  esac
done

echo -e &#34;$url $icon $name&#34;
# pake $url --icon $icon --height=1080 --width=1920 --show-system-tray --name $appname
sed -i &#34;/pkgdesc/a\\url=${url}&#34; PKGBUILD
sed -i &#34;/pkgname/i\\_appname=${name}&#34; PKGBUILD
makepkg</code><button onclick="copyCode(this)" class="copybtn">copy</button></pre></details>

  <script>
    function copyCode(btn) {
      const code = btn.previousElementSibling.textContent.trim();
      navigator.clipboard.writeText(code).then(() => {
        btn.innerText = "copied";
        setTimeout(() => (btn.innerText = "copy"), 2000);
      });
    }
  </script><p>这样就会生成一个<code>.zst</code>包，用<code>pacman -U name-pake-1.0.0-1-x86_64.pkg.tar.zst</code>即可。</p>
]]></content:encoded></item><item><title>awk</title><link>https://hiraethecho.github.io/docs/dev/awk/</link><pubDate>Mon, 05 May 2025 00:00:00 +0000</pubDate><author>wyz2016zxc@outlook.com(Hiraeth)</author><guid>https://hiraethecho.github.io/docs/dev/awk/</guid><description>&lt;h1 id="awk"&gt;
&lt;a class="anchor inpage" href="#awk"&gt;#&lt;/a&gt;awk&lt;/h1&gt;
&lt;h2 id="tldr"&gt;
&lt;a class="anchor inpage" href="#tldr"&gt;##&lt;/a&gt;tldr&lt;/h2&gt;
&lt;p&gt;A versatile programming language for working on files.
More information:
.&lt;/p&gt;
&lt;p&gt;Print the fifth column (a.k.a. field) in a space-separated file:&lt;/p&gt;
&lt;details open&gt;
&lt;summary&gt;TEXT&lt;/summary&gt;&lt;pre
class="codeblock"
&gt;&lt;code class="language-" data-lang=""&gt;awk &amp;#39;{print $5}&amp;#39; path/to/file&lt;/code&gt;&lt;button onclick="copyCode(this)" class="copybtn"&gt;copy&lt;/button&gt;&lt;/pre&gt;&lt;/details&gt;
&lt;script&gt;
function copyCode(btn) {
const code = btn.previousElementSibling.textContent.trim();
navigator.clipboard.writeText(code).then(() =&gt; {
btn.innerText = "copied";
setTimeout(() =&gt; (btn.innerText = "copy"), 2000);
});
}
&lt;/script&gt;&lt;p&gt;Print the second column of the lines containing &amp;ldquo;foo&amp;rdquo; in a space-separated file:&lt;/p&gt;
&lt;details open&gt;
&lt;summary&gt;TEXT&lt;/summary&gt;&lt;pre
class="codeblock"
&gt;&lt;code class="language-" data-lang=""&gt;awk &amp;#39;/foo/ {print $2}&amp;#39; path/to/file&lt;/code&gt;&lt;button onclick="copyCode(this)" class="copybtn"&gt;copy&lt;/button&gt;&lt;/pre&gt;&lt;/details&gt;
&lt;script&gt;
function copyCode(btn) {
const code = btn.previousElementSibling.textContent.trim();
navigator.clipboard.writeText(code).then(() =&gt; {
btn.innerText = "copied";
setTimeout(() =&gt; (btn.innerText = "copy"), 2000);
});
}
&lt;/script&gt;&lt;p&gt;Print the last column of each line in a file, using a comma (instead of space) as a field separator:&lt;/p&gt;</description><content:encoded><![CDATA[<h1 id="awk">
  <a class="anchor inpage" href="#awk">#</a>awk</h1>
<h2 id="tldr">
  <a class="anchor inpage" href="#tldr">##</a>tldr</h2>
<p>A versatile programming language for working on files.
More information: 
.</p>
<p>Print the fifth column (a.k.a. field) in a space-separated file:</p>
<details open>
    <summary>TEXT</summary><pre
        class="codeblock"
      ><code class="language-" data-lang="">awk &#39;{print $5}&#39; path/to/file</code><button onclick="copyCode(this)" class="copybtn">copy</button></pre></details>

  <script>
    function copyCode(btn) {
      const code = btn.previousElementSibling.textContent.trim();
      navigator.clipboard.writeText(code).then(() => {
        btn.innerText = "copied";
        setTimeout(() => (btn.innerText = "copy"), 2000);
      });
    }
  </script><p>Print the second column of the lines containing &ldquo;foo&rdquo; in a space-separated file:</p>
<details open>
    <summary>TEXT</summary><pre
        class="codeblock"
      ><code class="language-" data-lang="">awk &#39;/foo/ {print $2}&#39; path/to/file</code><button onclick="copyCode(this)" class="copybtn">copy</button></pre></details>

  <script>
    function copyCode(btn) {
      const code = btn.previousElementSibling.textContent.trim();
      navigator.clipboard.writeText(code).then(() => {
        btn.innerText = "copied";
        setTimeout(() => (btn.innerText = "copy"), 2000);
      });
    }
  </script><p>Print the last column of each line in a file, using a comma (instead of space) as a field separator:</p>
<details open>
    <summary>TEXT</summary><pre
        class="codeblock"
      ><code class="language-" data-lang="">awk -F &#39;,&#39; &#39;{print $NF}&#39; path/to/file</code><button onclick="copyCode(this)" class="copybtn">copy</button></pre></details>

  <script>
    function copyCode(btn) {
      const code = btn.previousElementSibling.textContent.trim();
      navigator.clipboard.writeText(code).then(() => {
        btn.innerText = "copied";
        setTimeout(() => (btn.innerText = "copy"), 2000);
      });
    }
  </script><p>Sum the values in the first column of a file and print the total:</p>
<details open>
    <summary>TEXT</summary><pre
        class="codeblock"
      ><code class="language-" data-lang="">awk &#39;{s&#43;=$1} END {print s}&#39; path/to/file</code><button onclick="copyCode(this)" class="copybtn">copy</button></pre></details>

  <script>
    function copyCode(btn) {
      const code = btn.previousElementSibling.textContent.trim();
      navigator.clipboard.writeText(code).then(() => {
        btn.innerText = "copied";
        setTimeout(() => (btn.innerText = "copy"), 2000);
      });
    }
  </script><p>Print every third line starting from the first line:</p>
<details open>
    <summary>TEXT</summary><pre
        class="codeblock"
      ><code class="language-" data-lang="">awk &#39;NR%3==1&#39; path/to/file</code><button onclick="copyCode(this)" class="copybtn">copy</button></pre></details>

  <script>
    function copyCode(btn) {
      const code = btn.previousElementSibling.textContent.trim();
      navigator.clipboard.writeText(code).then(() => {
        btn.innerText = "copied";
        setTimeout(() => (btn.innerText = "copy"), 2000);
      });
    }
  </script><p>Print different values based on conditions:</p>
<details open>
    <summary>TEXT</summary><pre
        class="codeblock"
      ><code class="language-" data-lang="">awk &#39;{if ($1 == &#34;foo&#34;) print &#34;Exact match foo&#34;; else if ($1 ~ &#34;bar&#34;) print &#34;Partial match bar&#34;; else print &#34;Baz&#34;}&#39; path/to/file</code><button onclick="copyCode(this)" class="copybtn">copy</button></pre></details>

  <script>
    function copyCode(btn) {
      const code = btn.previousElementSibling.textContent.trim();
      navigator.clipboard.writeText(code).then(() => {
        btn.innerText = "copied";
        setTimeout(() => (btn.innerText = "copy"), 2000);
      });
    }
  </script><p>Print all the lines which the 10th column value is between a min and a max:</p>
<details open>
    <summary>TEXT</summary><pre
        class="codeblock"
      ><code class="language-" data-lang="">awk &#39;($10 &gt;= min_value &amp;&amp; $10 &lt;= max_value)&#39;</code><button onclick="copyCode(this)" class="copybtn">copy</button></pre></details>

  <script>
    function copyCode(btn) {
      const code = btn.previousElementSibling.textContent.trim();
      navigator.clipboard.writeText(code).then(() => {
        btn.innerText = "copied";
        setTimeout(() => (btn.innerText = "copy"), 2000);
      });
    }
  </script><p>Print table of users with UID &gt;=1000 with header and formatted output, using colon as separator (<code>%-20s</code> mean: 20 left-align string characters, <code>%6s</code> means: 6 right-align string characters):</p>
<details open>
    <summary>TEXT</summary><pre
        class="codeblock"
      ><code class="language-" data-lang="">awk &#39;BEGIN {FS=&#34;:&#34;;printf &#34;%-20s %6s %25s\n&#34;, &#34;Name&#34;, &#34;UID&#34;, &#34;Shell&#34;} $4 &gt;= 1000 {printf &#34;%-20s %6d %25s\n&#34;, $1, $4, $7}&#39; /etc/passwd</code><button onclick="copyCode(this)" class="copybtn">copy</button></pre></details>

  <script>
    function copyCode(btn) {
      const code = btn.previousElementSibling.textContent.trim();
      navigator.clipboard.writeText(code).then(() => {
        btn.innerText = "copied";
        setTimeout(() => (btn.innerText = "copy"), 2000);
      });
    }
  </script><h2 id="getting-started">
  <a class="anchor inpage" href="#getting-started">##</a>Getting Started</h2>
<h3 id="have-a-try">
  <a class="anchor inpage" href="#have-a-try">###</a>Have a try</h3>
<details open>
    <summary>shell</summary><pre
        class="chroma codeblock"
      ><code class="language-shell" data-lang="shell"
          ><span style="display:flex;"><span>$ awk -F: <span style="color:#e6db74">&#39;{print $1, $NF}&#39;</span> /etc/passwd</span></span></code
        ><button onclick="copyCode(this)" class="copybtn">copy</button></pre></details>

  <script>
    function copyCode(btn) {
      const code = btn.previousElementSibling.textContent.trim();
      navigator.clipboard.writeText(code).then(() => {
        btn.innerText = "copied";
        setTimeout(() => (btn.innerText = "copy"), 2000);
      });
    }
  </script><table>
  <thead>
      <tr>
          <th>-</th>
          <th>-</th>
      </tr>
  </thead>
  <tbody>
      <tr>
          <td><code>-F:</code></td>
          <td>Colon as a separator</td>
      </tr>
      <tr>
          <td><code>{...}</code></td>
          <td>Awk program</td>
      </tr>
      <tr>
          <td><code>print</code></td>
          <td>Prints the current record</td>
      </tr>
      <tr>
          <td><code>$1</code></td>
          <td>First field</td>
      </tr>
      <tr>
          <td><code>$NF</code></td>
          <td>Last field</td>
      </tr>
      <tr>
          <td><code>/etc/passwd</code></td>
          <td>Input data file</td>
      </tr>
  </tbody>
</table>
<h3 id="awk-program">
  <a class="anchor inpage" href="#awk-program">###</a>Awk program</h3>
<details open>
    <summary>TEXT</summary><pre
        class="codeblock"
      ><code class="language-" data-lang="">BEGIN          {&lt;initializations&gt;}
   &lt;pattern 1&gt; {&lt;program actions&gt;}
   &lt;pattern 2&gt; {&lt;program actions&gt;}
   ...
END            {&lt; final actions &gt;}</code><button onclick="copyCode(this)" class="copybtn">copy</button></pre></details>

  <script>
    function copyCode(btn) {
      const code = btn.previousElementSibling.textContent.trim();
      navigator.clipboard.writeText(code).then(() => {
        btn.innerText = "copied";
        setTimeout(() => (btn.innerText = "copy"), 2000);
      });
    }
  </script><h4 id="example">
  <a class="anchor inpage" href="#example">####</a>Example</h4>
<details open>
    <summary>TEXT</summary><pre
        class="codeblock"
      ><code class="language-" data-lang="">awk &#39;
    BEGIN { print &#34;\n&gt;&gt;&gt;Start&#34; }
    !/(login|shutdown)/ { print NR, $0 }
    END { print &#34;&lt;&lt;&lt;END\n&#34; }
&#39; /etc/passwd</code><button onclick="copyCode(this)" class="copybtn">copy</button></pre></details>

  <script>
    function copyCode(btn) {
      const code = btn.previousElementSibling.textContent.trim();
      navigator.clipboard.writeText(code).then(() => {
        btn.innerText = "copied";
        setTimeout(() => (btn.innerText = "copy"), 2000);
      });
    }
  </script><h3 id="variables">
  <a class="anchor inpage" href="#variables">###</a>Variables</h3>
<details open>
    <summary>bash</summary><pre
        class="chroma codeblock"
      ><code class="language-bash" data-lang="bash"
          ><span style="display:flex;"><span>          $1      $2/<span style="color:#66d9ef">$(</span>NF-1<span style="color:#66d9ef">)</span>    $3/$NF
</span></span><span style="display:flex;"><span>           ▼          ▼           ▼
</span></span><span style="display:flex;"><span>        ┌──────┬──────────────────┬───────┐
</span></span><span style="display:flex;"><span>$0/NR ▶ │  ID  │  WEBSITE         │  URI  │
</span></span><span style="display:flex;"><span>        ├──────┼──────────────────┼───────┤
</span></span><span style="display:flex;"><span>$0/NR ▶ │  <span style="color:#ae81ff">1</span>   │  cheatsheets.zip │  awk  │
</span></span><span style="display:flex;"><span>        ├──────┼──────────────────┼───────┤
</span></span><span style="display:flex;"><span>$0/NR ▶ │  <span style="color:#ae81ff">2</span>   │  google.com      │  <span style="color:#ae81ff">25</span>   │
</span></span><span style="display:flex;"><span>        └──────┴──────────────────┴───────┘</span></span></code
        ><button onclick="copyCode(this)" class="copybtn">copy</button></pre></details>

  <script>
    function copyCode(btn) {
      const code = btn.previousElementSibling.textContent.trim();
      navigator.clipboard.writeText(code).then(() => {
        btn.innerText = "copied";
        setTimeout(() => (btn.innerText = "copy"), 2000);
      });
    }
  </script><details open>
    <summary>TEXT</summary><pre
        class="codeblock"
      ><code class="language-" data-lang=""># First and last field
awk -F: &#39;{print $1,$NF}&#39; /etc/passwd

# With line number
awk -F: &#39;{print NR, $0}&#39; /etc/passwd

# Second last field
awk -F: &#39;{print $(NF-1)}&#39; /etc/passwd

# Custom string
awk -F: &#39;{print $1 &#34;=&#34; $6}&#39; /etc/passwd</code><button onclick="copyCode(this)" class="copybtn">copy</button></pre></details>

  <script>
    function copyCode(btn) {
      const code = btn.previousElementSibling.textContent.trim();
      navigator.clipboard.writeText(code).then(() => {
        btn.innerText = "copied";
        setTimeout(() => (btn.innerText = "copy"), 2000);
      });
    }
  </script><h3 id="awk-program-examples">
  <a class="anchor inpage" href="#awk-program-examples">###</a>Awk program examples</h3>
<details open>
    <summary>TEXT</summary><pre
        class="codeblock"
      ><code class="language-" data-lang="">awk &#39;BEGIN {print &#34;hello world&#34;}&#39;        # Prints &#34;hello world&#34;
awk -F: &#39;{print $1}&#39; /etc/passwd         # -F: Specify field separator

# /pattern/ Execute actions only for matched pattern
awk -F: &#39;/root/ {print $1}&#39; /etc/passwd

# BEGIN block is executed once at the start
awk -F: &#39;BEGIN { print &#34;uid&#34;} { print $1 }&#39; /etc/passwd

# END block is executed once at the end
awk -F: &#39;{print $1} END { print &#34;-done-&#34;}&#39; /etc/passwd</code><button onclick="copyCode(this)" class="copybtn">copy</button></pre></details>

  <script>
    function copyCode(btn) {
      const code = btn.previousElementSibling.textContent.trim();
      navigator.clipboard.writeText(code).then(() => {
        btn.innerText = "copied";
        setTimeout(() => (btn.innerText = "copy"), 2000);
      });
    }
  </script><h3 id="conditions">
  <a class="anchor inpage" href="#conditions">###</a>Conditions</h3>
<details open>
    <summary>TEXT</summary><pre
        class="codeblock"
      ><code class="language-" data-lang="">awk -F: &#39;$3&gt;30 {print $1}&#39; /etc/passwd</code><button onclick="copyCode(this)" class="copybtn">copy</button></pre></details>

  <script>
    function copyCode(btn) {
      const code = btn.previousElementSibling.textContent.trim();
      navigator.clipboard.writeText(code).then(() => {
        btn.innerText = "copied";
        setTimeout(() => (btn.innerText = "copy"), 2000);
      });
    }
  </script><h3 id="generate-1000-spaces">
  <a class="anchor inpage" href="#generate-1000-spaces">###</a>Generate 1000 spaces</h3>
<details open>
    <summary>TEXT</summary><pre
        class="codeblock"
      ><code class="language-" data-lang="">awk &#39;BEGIN{
    while (a&#43;&#43; &lt; 1000)
        s=s &#34; &#34;;
    print s
}&#39;</code><button onclick="copyCode(this)" class="copybtn">copy</button></pre></details>

  <script>
    function copyCode(btn) {
      const code = btn.previousElementSibling.textContent.trim();
      navigator.clipboard.writeText(code).then(() => {
        btn.innerText = "copied";
        setTimeout(() => (btn.innerText = "copy"), 2000);
      });
    }
  </script><h3 id="arrays">
  <a class="anchor inpage" href="#arrays">###</a>Arrays</h3>
<details open>
    <summary>TEXT</summary><pre
        class="codeblock"
      ><code class="language-" data-lang="">awk &#39;BEGIN {
   fruits[&#34;mango&#34;] = &#34;yellow&#34;;
   fruits[&#34;orange&#34;] = &#34;orange&#34;
   for(fruit in fruits) {
     print &#34;The color of &#34; fruit &#34; is &#34; fruits[fruit]
   }
}&#39;</code><button onclick="copyCode(this)" class="copybtn">copy</button></pre></details>

  <script>
    function copyCode(btn) {
      const code = btn.previousElementSibling.textContent.trim();
      navigator.clipboard.writeText(code).then(() => {
        btn.innerText = "copied";
        setTimeout(() => (btn.innerText = "copy"), 2000);
      });
    }
  </script><h3 id="functions">
  <a class="anchor inpage" href="#functions">###</a>Functions</h3>
<details open>
    <summary>TEXT</summary><pre
        class="codeblock"
      ><code class="language-" data-lang=""># =&gt; 5
awk &#39;BEGIN{print length(&#34;hello&#34;)}&#39;
# =&gt; HELLO
awk &#39;BEGIN{print toupper(&#34;hello&#34;)}&#39;
# =&gt; hel
awk &#39;BEGIN{print substr(&#34;hello&#34;, 1, 3)}&#39;</code><button onclick="copyCode(this)" class="copybtn">copy</button></pre></details>

  <script>
    function copyCode(btn) {
      const code = btn.previousElementSibling.textContent.trim();
      navigator.clipboard.writeText(code).then(() => {
        btn.innerText = "copied";
        setTimeout(() => (btn.innerText = "copy"), 2000);
      });
    }
  </script><h2 id="awk-variables">
  <a class="anchor inpage" href="#awk-variables">##</a>Awk Variables</h2>
<h3 id="build-in-variables">
  <a class="anchor inpage" href="#build-in-variables">###</a>Build-in variables</h3>
<table>
  <thead>
      <tr>
          <th>-</th>
          <th>-</th>
      </tr>
  </thead>
  <tbody>
      <tr>
          <td><code>$0</code></td>
          <td>Whole line</td>
      </tr>
      <tr>
          <td><code>$1, $2...$NF</code></td>
          <td>First, second… last field</td>
      </tr>
      <tr>
          <td><code>NR</code></td>
          <td><code>N</code>umber of <code>R</code>ecords</td>
      </tr>
      <tr>
          <td><code>NF</code></td>
          <td><code>N</code>umber of <code>F</code>ields</td>
      </tr>
      <tr>
          <td><code>OFS</code></td>
          <td><code>O</code>utput <code>F</code>ield <code>S</code>eparator <br> <em>(default &quot; &ldquo;)</em></td>
      </tr>
      <tr>
          <td><code>FS</code></td>
          <td>input <code>F</code>ield <code>S</code>eparator <br> <em>(default &quot; &ldquo;)</em></td>
      </tr>
      <tr>
          <td><code>ORS</code></td>
          <td><code>O</code>utput <code>R</code>ecord <code>S</code>eparator <br> <em>(default &ldquo;\n&rdquo;)</em></td>
      </tr>
      <tr>
          <td><code>RS</code></td>
          <td>input <code>R</code>ecord <code>S</code>eparator <br> <em>(default &ldquo;\n&rdquo;)</em></td>
      </tr>
      <tr>
          <td><code>FILENAME</code></td>
          <td>Name of the file</td>
      </tr>
  </tbody>
</table>
<h3 id="expressions">
  <a class="anchor inpage" href="#expressions">###</a>Expressions</h3>
<table>
  <thead>
      <tr>
          <th>-</th>
          <th>-</th>
      </tr>
  </thead>
  <tbody>
      <tr>
          <td><code>$1 == &quot;root&quot;</code></td>
          <td>First field equals root</td>
      </tr>
      <tr>
          <td><code>{print $(NF-1)}</code></td>
          <td>Second last field</td>
      </tr>
      <tr>
          <td><code>NR!=1{print $0}</code></td>
          <td>From 2nd record</td>
      </tr>
      <tr>
          <td><code>NR &gt; 3</code></td>
          <td>From 4th record</td>
      </tr>
      <tr>
          <td><code>NR == 1</code></td>
          <td>First record</td>
      </tr>
      <tr>
          <td><code>END{print NR}</code></td>
          <td>Total records</td>
      </tr>
      <tr>
          <td><code>BEGIN{print OFMT}</code></td>
          <td>Output format</td>
      </tr>
      <tr>
          <td><code>{print NR, $0}</code></td>
          <td>Line number</td>
      </tr>
      <tr>
          <td><code>{print NR &quot;	&quot; $0}</code></td>
          <td>Line number (tab)</td>
      </tr>
      <tr>
          <td><code>{$1 = NR; print}</code></td>
          <td>Replace 1st field with line number</td>
      </tr>
      <tr>
          <td><code>$NF &gt; 4</code></td>
          <td>Last field &gt; 4</td>
      </tr>
      <tr>
          <td><code>NR % 2 == 0</code></td>
          <td>Even records</td>
      </tr>
      <tr>
          <td><code>NR==10, NR==20</code></td>
          <td>Records 10 to 20</td>
      </tr>
      <tr>
          <td><code>BEGIN{print ARGC}</code></td>
          <td>Total arguments</td>
      </tr>
      <tr>
          <td><code>ORS=NR%5?&quot;,&quot;:&quot;\n&quot;</code></td>
          <td>Concatenate records</td>
      </tr>
  </tbody>
</table>
<h3 id="examples">
  <a class="anchor inpage" href="#examples">###</a>Examples</h3>
<p>Print sum and average</p>
<details open>
    <summary>TEXT</summary><pre
        class="codeblock"
      ><code class="language-" data-lang="">awk -F: &#39;{sum &#43;= $3}
     END { print sum, sum/NR }
&#39; /etc/passwd</code><button onclick="copyCode(this)" class="copybtn">copy</button></pre></details>

  <script>
    function copyCode(btn) {
      const code = btn.previousElementSibling.textContent.trim();
      navigator.clipboard.writeText(code).then(() => {
        btn.innerText = "copied";
        setTimeout(() => (btn.innerText = "copy"), 2000);
      });
    }
  </script><p>Printing parameters</p>
<details open>
    <summary>TEXT</summary><pre
        class="codeblock"
      ><code class="language-" data-lang="">awk &#39;BEGIN {
    for (i = 1; i &lt; ARGC; i&#43;&#43;)
        print ARGV[i] }&#39; a b c</code><button onclick="copyCode(this)" class="copybtn">copy</button></pre></details>

  <script>
    function copyCode(btn) {
      const code = btn.previousElementSibling.textContent.trim();
      navigator.clipboard.writeText(code).then(() => {
        btn.innerText = "copied";
        setTimeout(() => (btn.innerText = "copy"), 2000);
      });
    }
  </script><p>Output field separator as a comma</p>
<details open>
    <summary>TEXT</summary><pre
        class="codeblock"
      ><code class="language-" data-lang="">awk &#39;BEGIN { FS=&#34;:&#34;;OFS=&#34;,&#34;}
    {print $1,$2,$3,$4}&#39; /etc/passwd</code><button onclick="copyCode(this)" class="copybtn">copy</button></pre></details>

  <script>
    function copyCode(btn) {
      const code = btn.previousElementSibling.textContent.trim();
      navigator.clipboard.writeText(code).then(() => {
        btn.innerText = "copied";
        setTimeout(() => (btn.innerText = "copy"), 2000);
      });
    }
  </script><p>Position of match</p>
<details open>
    <summary>TEXT</summary><pre
        class="codeblock"
      ><code class="language-" data-lang="">awk &#39;BEGIN {
    if (match(&#34;One Two Three&#34;, &#34;Tw&#34;))
        print RSTART }&#39;</code><button onclick="copyCode(this)" class="copybtn">copy</button></pre></details>

  <script>
    function copyCode(btn) {
      const code = btn.previousElementSibling.textContent.trim();
      navigator.clipboard.writeText(code).then(() => {
        btn.innerText = "copied";
        setTimeout(() => (btn.innerText = "copy"), 2000);
      });
    }
  </script><p>Length of match</p>
<details open>
    <summary>TEXT</summary><pre
        class="codeblock"
      ><code class="language-" data-lang="">awk &#39;BEGIN {
    if (match(&#34;One Two Three&#34;, &#34;re&#34;))
        print RLENGTH }&#39;</code><button onclick="copyCode(this)" class="copybtn">copy</button></pre></details>

  <script>
    function copyCode(btn) {
      const code = btn.previousElementSibling.textContent.trim();
      navigator.clipboard.writeText(code).then(() => {
        btn.innerText = "copied";
        setTimeout(() => (btn.innerText = "copy"), 2000);
      });
    }
  </script><h3 id="environment-variables">
  <a class="anchor inpage" href="#environment-variables">###</a>Environment Variables</h3>
<table>
  <thead>
      <tr>
          <th>-</th>
          <th>-</th>
      </tr>
  </thead>
  <tbody>
      <tr>
          <td><code>ARGC</code></td>
          <td>Number or arguments</td>
      </tr>
      <tr>
          <td><code>ARGV</code></td>
          <td>Array of arguments</td>
      </tr>
      <tr>
          <td><code>FNR</code></td>
          <td><code>F</code>ile <code>N</code>umber of <code>R</code>ecords</td>
      </tr>
      <tr>
          <td><code>OFMT</code></td>
          <td>Format for numbers <br> <em>(default &ldquo;%.6g&rdquo;)</em></td>
      </tr>
      <tr>
          <td><code>RSTART</code></td>
          <td>Location in the string</td>
      </tr>
      <tr>
          <td><code>RLENGTH</code></td>
          <td>Length of match</td>
      </tr>
      <tr>
          <td><code>SUBSEP</code></td>
          <td>Multi-dimensional array separator <br> <em>(default &ldquo;\034&rdquo;)</em></td>
      </tr>
      <tr>
          <td><code>ARGIND</code></td>
          <td>Argument Index</td>
      </tr>
  </tbody>
</table>
<h3 id="gnu-awk-only">
  <a class="anchor inpage" href="#gnu-awk-only">###</a>GNU awk only</h3>
<table>
  <thead>
      <tr>
          <th>-</th>
          <th>-</th>
      </tr>
  </thead>
  <tbody>
      <tr>
          <td><code>ENVIRON</code></td>
          <td>Environment variables</td>
      </tr>
      <tr>
          <td><code>IGNORECASE</code></td>
          <td>Ignore case</td>
      </tr>
      <tr>
          <td><code>CONVFMT</code></td>
          <td>Conversion format</td>
      </tr>
      <tr>
          <td><code>ERRNO</code></td>
          <td>System errors</td>
      </tr>
      <tr>
          <td><code>FIELDWIDTHS</code></td>
          <td>Fixed width fields</td>
      </tr>
  </tbody>
</table>
<h3 id="defining-variable">
  <a class="anchor inpage" href="#defining-variable">###</a>Defining variable</h3>
<details open>
    <summary>TEXT</summary><pre
        class="codeblock"
      ><code class="language-" data-lang="">awk -v var1=&#34;Hello&#34; -v var2=&#34;Wold&#34; &#39;
    END {print var1, var2}
&#39; &lt;/dev/null</code><button onclick="copyCode(this)" class="copybtn">copy</button></pre></details>

  <script>
    function copyCode(btn) {
      const code = btn.previousElementSibling.textContent.trim();
      navigator.clipboard.writeText(code).then(() => {
        btn.innerText = "copied";
        setTimeout(() => (btn.innerText = "copy"), 2000);
      });
    }
  </script><h4 id="use-shell-variables">
  <a class="anchor inpage" href="#use-shell-variables">####</a>Use shell variables</h4>
<details open>
    <summary>TEXT</summary><pre
        class="codeblock"
      ><code class="language-" data-lang="">awk -v varName=&#34;$PWD&#34; &#39;
    END {print varName}&#39; &lt;/dev/null</code><button onclick="copyCode(this)" class="copybtn">copy</button></pre></details>

  <script>
    function copyCode(btn) {
      const code = btn.previousElementSibling.textContent.trim();
      navigator.clipboard.writeText(code).then(() => {
        btn.innerText = "copied";
        setTimeout(() => (btn.innerText = "copy"), 2000);
      });
    }
  </script><h2 id="awk-operators">
  <a class="anchor inpage" href="#awk-operators">##</a>Awk Operators</h2>
<h3 id="operators">
  <a class="anchor inpage" href="#operators">###</a>Operators</h3>
<table>
  <thead>
      <tr>
          <th>-</th>
          <th>-</th>
      </tr>
  </thead>
  <tbody>
      <tr>
          <td><code>{print $1}</code></td>
          <td>First field</td>
      </tr>
      <tr>
          <td><code>$2 == &quot;foo&quot;</code></td>
          <td>Equals</td>
      </tr>
      <tr>
          <td><code>$2 != &quot;foo&quot;</code></td>
          <td>Not equals</td>
      </tr>
      <tr>
          <td><code>&quot;foo&quot; in array</code></td>
          <td>In array</td>
      </tr>
  </tbody>
</table>
<h4 id="regular-expression">
  <a class="anchor inpage" href="#regular-expression">####</a>Regular expression</h4>
<table>
  <thead>
      <tr>
          <th>-</th>
          <th>-</th>
      </tr>
  </thead>
  <tbody>
      <tr>
          <td><code>/regex/</code></td>
          <td>Line matches</td>
      </tr>
      <tr>
          <td><code>!/regex/</code></td>
          <td>Line not matches</td>
      </tr>
      <tr>
          <td><code>$1 ~ /regex/</code></td>
          <td>Field matches</td>
      </tr>
      <tr>
          <td><code>$1 !~ /regex/</code></td>
          <td>Field not matches</td>
      </tr>
  </tbody>
</table>
<h4 id="more-conditions">
  <a class="anchor inpage" href="#more-conditions">####</a>More conditions</h4>
<table>
  <thead>
      <tr>
          <th>-</th>
          <th>-</th>
      </tr>
  </thead>
  <tbody>
      <tr>
          <td><code>($2 &lt;= 4 || $3 &lt; 20)</code></td>
          <td>Or</td>
      </tr>
      <tr>
          <td><code>($1 == 4 &amp;&amp; $3 &lt; 20)</code></td>
          <td>And</td>
      </tr>
  </tbody>
</table>
<h3 id="operations">
  <a class="anchor inpage" href="#operations">###</a>Operations</h3>
<h4 id="arithmetic-operations">
  <a class="anchor inpage" href="#arithmetic-operations">####</a>Arithmetic operations</h4>
<ul>
<li><code>+</code></li>
<li><code>-</code></li>
<li><code>*</code></li>
<li><code>/</code></li>
<li><code>%</code></li>
<li><code>++</code></li>
<li><code>--</code></li>
</ul>
<h4 id="shorthand-assignments">
  <a class="anchor inpage" href="#shorthand-assignments">####</a>Shorthand assignments</h4>
<ul>
<li><code>+=</code></li>
<li><code>-=</code></li>
<li><code>*=</code></li>
<li><code>/=</code></li>
<li><code>%=</code></li>
</ul>
<h4 id="comparison-operators">
  <a class="anchor inpage" href="#comparison-operators">####</a>Comparison operators</h4>
<ul>
<li><code>==</code></li>
<li><code>!=</code></li>
<li><code>&lt;</code></li>
<li><code>&gt;</code></li>
<li><code>&lt;=</code></li>
<li><code>&gt;=</code></li>
</ul>
<h3 id="examples-1">
  <a class="anchor inpage" href="#examples-1">###</a>Examples</h3>
<details open>
    <summary>TEXT</summary><pre
        class="codeblock"
      ><code class="language-" data-lang="">awk &#39;BEGIN {
    if (&#34;foo&#34; ~ &#34;^fo&#43;$&#34;)
        print &#34;Fooey!&#34;;
}&#39;</code><button onclick="copyCode(this)" class="copybtn">copy</button></pre></details>

  <script>
    function copyCode(btn) {
      const code = btn.previousElementSibling.textContent.trim();
      navigator.clipboard.writeText(code).then(() => {
        btn.innerText = "copied";
        setTimeout(() => (btn.innerText = "copy"), 2000);
      });
    }
  </script><h4 id="not-match">
  <a class="anchor inpage" href="#not-match">####</a>Not match</h4>
<details open>
    <summary>TEXT</summary><pre
        class="codeblock"
      ><code class="language-" data-lang="">awk &#39;BEGIN {
    if (&#34;boo&#34; !~ &#34;^fo&#43;$&#34;)
        print &#34;Boo!&#34;;
}&#39;</code><button onclick="copyCode(this)" class="copybtn">copy</button></pre></details>

  <script>
    function copyCode(btn) {
      const code = btn.previousElementSibling.textContent.trim();
      navigator.clipboard.writeText(code).then(() => {
        btn.innerText = "copied";
        setTimeout(() => (btn.innerText = "copy"), 2000);
      });
    }
  </script><h4 id="if-in-array">
  <a class="anchor inpage" href="#if-in-array">####</a>if in array</h4>
<details open>
    <summary>TEXT</summary><pre
        class="codeblock"
      ><code class="language-" data-lang="">awk &#39;BEGIN {
    assoc[&#34;foo&#34;] = &#34;bar&#34;;
    assoc[&#34;bar&#34;] = &#34;baz&#34;;
    if (&#34;foo&#34; in assoc)
        print &#34;Fooey!&#34;;
}&#39;</code><button onclick="copyCode(this)" class="copybtn">copy</button></pre></details>

  <script>
    function copyCode(btn) {
      const code = btn.previousElementSibling.textContent.trim();
      navigator.clipboard.writeText(code).then(() => {
        btn.innerText = "copied";
        setTimeout(() => (btn.innerText = "copy"), 2000);
      });
    }
  </script><h2 id="awk-functions">
  <a class="anchor inpage" href="#awk-functions">##</a>Awk Functions</h2>
<h3 id="common-functions">
  <a class="anchor inpage" href="#common-functions">###</a>Common functions</h3>
<table>
  <thead>
      <tr>
          <th>Function</th>
          <th>Description</th>
      </tr>
  </thead>
  <tbody>
      <tr>
          <td><code>index(s,t)</code></td>
          <td>Position in string s where string t occurs, 0 if not found</td>
      </tr>
      <tr>
          <td><code>length(s)</code></td>
          <td>Length of string s (or $0 if no arg)</td>
      </tr>
      <tr>
          <td><code>rand</code></td>
          <td>Random number between 0 and 1</td>
      </tr>
      <tr>
          <td><code>substr(s,index,len)</code></td>
          <td>Return len-char substring of s that begins at index (counted from 1)</td>
      </tr>
      <tr>
          <td><code>srand</code></td>
          <td>Set seed for rand and return previous seed</td>
      </tr>
      <tr>
          <td><code>int(x)</code></td>
          <td>Truncate x to integer value</td>
      </tr>
      <tr>
          <td><code>split(s,a,fs)</code></td>
          <td>Split string s into array a split by fs, returning length of a</td>
      </tr>
      <tr>
          <td><code>match(s,r)</code></td>
          <td>Position in string s where regex r occurs, or 0 if not found</td>
      </tr>
      <tr>
          <td><code>sub(r,t,s)</code></td>
          <td>Substitute t for first occurrence of regex r in string s (or $0 if s not given)</td>
      </tr>
      <tr>
          <td><code>gsub(r,t,s)</code></td>
          <td>Substitute t for all occurrences of regex r in string s</td>
      </tr>
      <tr>
          <td><code>system(cmd)</code></td>
          <td>Execute cmd and return exit status</td>
      </tr>
      <tr>
          <td><code>tolower(s)</code></td>
          <td>String s to lowercase</td>
      </tr>
      <tr>
          <td><code>toupper(s)</code></td>
          <td>String s to uppercase</td>
      </tr>
      <tr>
          <td><code>getline</code></td>
          <td>Set $0 to next input record from current input file.</td>
      </tr>
  </tbody>
</table>
<h3 id="user-defined-function">
  <a class="anchor inpage" href="#user-defined-function">###</a>User defined function</h3>
<details open>
    <summary>TEXT</summary><pre
        class="codeblock"
      ><code class="language-" data-lang="">awk &#39;
    # Returns minimum number
    function find_min(num1, num2){
       if (num1 &lt; num2)
       return num1
       return num2
    }
    # Returns maximum number
    function find_max(num1, num2){
       if (num1 &gt; num2)
       return num1
       return num2
    }
    # Main function
    function main(num1, num2){
       result = find_min(num1, num2)
       print &#34;Minimum =&#34;, result

       result = find_max(num1, num2)
       print &#34;Maximum =&#34;, result
    }
    # Script execution starts here
    BEGIN {
       main(10, 60)
    }
&#39;</code><button onclick="copyCode(this)" class="copybtn">copy</button></pre></details>

  <script>
    function copyCode(btn) {
      const code = btn.previousElementSibling.textContent.trim();
      navigator.clipboard.writeText(code).then(() => {
        btn.innerText = "copied";
        setTimeout(() => (btn.innerText = "copy"), 2000);
      });
    }
  </script><h2 id="awk-arrays">
  <a class="anchor inpage" href="#awk-arrays">##</a>Awk Arrays</h2>
<h3 id="array-with-index">
  <a class="anchor inpage" href="#array-with-index">###</a>Array with index</h3>
<details open>
    <summary>TEXT</summary><pre
        class="codeblock"
      ><code class="language-" data-lang="">awk &#39;BEGIN {
    arr[0] = &#34;foo&#34;;
    arr[1] = &#34;bar&#34;;
    print(arr[0]); # =&gt; foo
    delete arr[0];
    print(arr[0]); # =&gt; &#34;&#34;
}&#39;</code><button onclick="copyCode(this)" class="copybtn">copy</button></pre></details>

  <script>
    function copyCode(btn) {
      const code = btn.previousElementSibling.textContent.trim();
      navigator.clipboard.writeText(code).then(() => {
        btn.innerText = "copied";
        setTimeout(() => (btn.innerText = "copy"), 2000);
      });
    }
  </script><h3 id="array-with-key">
  <a class="anchor inpage" href="#array-with-key">###</a>Array with key</h3>
<details open>
    <summary>TEXT</summary><pre
        class="codeblock"
      ><code class="language-" data-lang="">awk &#39;BEGIN {
    assoc[&#34;foo&#34;] = &#34;bar&#34;;
    assoc[&#34;bar&#34;] = &#34;baz&#34;;
    print(&#34;baz&#34; in assoc); # =&gt; 0
    print(&#34;foo&#34; in assoc); # =&gt; 1
}&#39;</code><button onclick="copyCode(this)" class="copybtn">copy</button></pre></details>

  <script>
    function copyCode(btn) {
      const code = btn.previousElementSibling.textContent.trim();
      navigator.clipboard.writeText(code).then(() => {
        btn.innerText = "copied";
        setTimeout(() => (btn.innerText = "copy"), 2000);
      });
    }
  </script><h3 id="array-with-split">
  <a class="anchor inpage" href="#array-with-split">###</a>Array with split</h3>
<details open>
    <summary>TEXT</summary><pre
        class="codeblock"
      ><code class="language-" data-lang="">awk &#39;BEGIN {
    split(&#34;foo:bar:baz&#34;, arr, &#34;:&#34;);
    for (key in arr)
        print arr[key];
}&#39;</code><button onclick="copyCode(this)" class="copybtn">copy</button></pre></details>

  <script>
    function copyCode(btn) {
      const code = btn.previousElementSibling.textContent.trim();
      navigator.clipboard.writeText(code).then(() => {
        btn.innerText = "copied";
        setTimeout(() => (btn.innerText = "copy"), 2000);
      });
    }
  </script><h3 id="array-with-asort">
  <a class="anchor inpage" href="#array-with-asort">###</a>Array with asort</h3>
<details open>
    <summary>TEXT</summary><pre
        class="codeblock"
      ><code class="language-" data-lang="">awk &#39;BEGIN {
    arr[0] = 3
    arr[1] = 2
    arr[2] = 4
    n = asort(arr)
    for (i = 1; i &lt;= n ; i&#43;&#43;)
        print(arr[i])
}&#39;</code><button onclick="copyCode(this)" class="copybtn">copy</button></pre></details>

  <script>
    function copyCode(btn) {
      const code = btn.previousElementSibling.textContent.trim();
      navigator.clipboard.writeText(code).then(() => {
        btn.innerText = "copied";
        setTimeout(() => (btn.innerText = "copy"), 2000);
      });
    }
  </script><h3 id="multi-dimensional">
  <a class="anchor inpage" href="#multi-dimensional">###</a>Multi-dimensional</h3>
<details open>
    <summary>TEXT</summary><pre
        class="codeblock"
      ><code class="language-" data-lang="">awk &#39;BEGIN {
    multidim[0,0] = &#34;foo&#34;;
    multidim[0,1] = &#34;bar&#34;;
    multidim[1,0] = &#34;baz&#34;;
    multidim[1,1] = &#34;boo&#34;;
}&#39;</code><button onclick="copyCode(this)" class="copybtn">copy</button></pre></details>

  <script>
    function copyCode(btn) {
      const code = btn.previousElementSibling.textContent.trim();
      navigator.clipboard.writeText(code).then(() => {
        btn.innerText = "copied";
        setTimeout(() => (btn.innerText = "copy"), 2000);
      });
    }
  </script><h3 id="multi-dimensional-iteration">
  <a class="anchor inpage" href="#multi-dimensional-iteration">###</a>Multi-dimensional iteration</h3>
<details open>
    <summary>TEXT</summary><pre
        class="codeblock"
      ><code class="language-" data-lang="">awk &#39;BEGIN {
    array[1,2]=3;
    array[2,3]=5;
    for (comb in array) {
        split(comb,sep,SUBSEP);
        print sep[1], sep[2],
        array[sep[1],sep[2]]
    }
}&#39;</code><button onclick="copyCode(this)" class="copybtn">copy</button></pre></details>

  <script>
    function copyCode(btn) {
      const code = btn.previousElementSibling.textContent.trim();
      navigator.clipboard.writeText(code).then(() => {
        btn.innerText = "copied";
        setTimeout(() => (btn.innerText = "copy"), 2000);
      });
    }
  </script><h2 id="awk-conditions">
  <a class="anchor inpage" href="#awk-conditions">##</a>Awk Conditions</h2>
<h3 id="if-else-statement">
  <a class="anchor inpage" href="#if-else-statement">###</a>if-else statement</h3>
<details open>
    <summary>TEXT</summary><pre
        class="codeblock"
      ><code class="language-" data-lang="">awk -v count=2 &#39;BEGIN {
    if (count == 1)
        print &#34;Yes&#34;;
    else
        print &#34;Huh?&#34;;
}&#39;</code><button onclick="copyCode(this)" class="copybtn">copy</button></pre></details>

  <script>
    function copyCode(btn) {
      const code = btn.previousElementSibling.textContent.trim();
      navigator.clipboard.writeText(code).then(() => {
        btn.innerText = "copied";
        setTimeout(() => (btn.innerText = "copy"), 2000);
      });
    }
  </script><h4 id="ternary-operator">
  <a class="anchor inpage" href="#ternary-operator">####</a>Ternary operator</h4>
<details open>
    <summary>TEXT</summary><pre
        class="codeblock"
      ><code class="language-" data-lang="">awk -v count=2 &#39;BEGIN {
    print (count==1) ? &#34;Yes&#34; : &#34;Huh?&#34;;
}&#39;</code><button onclick="copyCode(this)" class="copybtn">copy</button></pre></details>

  <script>
    function copyCode(btn) {
      const code = btn.previousElementSibling.textContent.trim();
      navigator.clipboard.writeText(code).then(() => {
        btn.innerText = "copied";
        setTimeout(() => (btn.innerText = "copy"), 2000);
      });
    }
  </script><h3 id="exists">
  <a class="anchor inpage" href="#exists">###</a>Exists</h3>
<details open>
    <summary>TEXT</summary><pre
        class="codeblock"
      ><code class="language-" data-lang="">awk &#39;BEGIN {
    assoc[&#34;foo&#34;] = &#34;bar&#34;;
    assoc[&#34;bar&#34;] = &#34;baz&#34;;
    if (&#34;foo&#34; in assoc)
        print &#34;Fooey!&#34;;
}&#39;</code><button onclick="copyCode(this)" class="copybtn">copy</button></pre></details>

  <script>
    function copyCode(btn) {
      const code = btn.previousElementSibling.textContent.trim();
      navigator.clipboard.writeText(code).then(() => {
        btn.innerText = "copied";
        setTimeout(() => (btn.innerText = "copy"), 2000);
      });
    }
  </script><h4 id="not-exists">
  <a class="anchor inpage" href="#not-exists">####</a>Not exists</h4>
<details open>
    <summary>TEXT</summary><pre
        class="codeblock"
      ><code class="language-" data-lang="">awk &#39;BEGIN {
    assoc[&#34;foo&#34;] = &#34;bar&#34;;
    assoc[&#34;bar&#34;] = &#34;baz&#34;;
    if (&#34;Huh&#34; in assoc == 0 )
        print &#34;Huh!&#34;;
}&#39;</code><button onclick="copyCode(this)" class="copybtn">copy</button></pre></details>

  <script>
    function copyCode(btn) {
      const code = btn.previousElementSibling.textContent.trim();
      navigator.clipboard.writeText(code).then(() => {
        btn.innerText = "copied";
        setTimeout(() => (btn.innerText = "copy"), 2000);
      });
    }
  </script><h3 id="switch">
  <a class="anchor inpage" href="#switch">###</a>switch</h3>
<details open>
    <summary>TEXT</summary><pre
        class="codeblock"
      ><code class="language-" data-lang="">awk -F: &#39;{
    switch (NR * 2 &#43; 1) {
        case 3:
        case &#34;11&#34;:
            print NR - 1
            break

        case /2[[:digit:]]&#43;/:
            print NR

        default:
            print NR &#43; 1

        case -1:
            print NR * -1
    }
}&#39; /etc/passwd</code><button onclick="copyCode(this)" class="copybtn">copy</button></pre></details>

  <script>
    function copyCode(btn) {
      const code = btn.previousElementSibling.textContent.trim();
      navigator.clipboard.writeText(code).then(() => {
        btn.innerText = "copied";
        setTimeout(() => (btn.innerText = "copy"), 2000);
      });
    }
  </script><h2 id="awk-loops">
  <a class="anchor inpage" href="#awk-loops">##</a>Awk Loops</h2>
<h3 id="fori">
  <a class="anchor inpage" href="#fori">###</a>for&hellip;i</h3>
<details open>
    <summary>TEXT</summary><pre
        class="codeblock"
      ><code class="language-" data-lang="">awk &#39;BEGIN {
    for (i = 0; i &lt; 10; i&#43;&#43;)
        print &#34;i=&#34; i;
}&#39;</code><button onclick="copyCode(this)" class="copybtn">copy</button></pre></details>

  <script>
    function copyCode(btn) {
      const code = btn.previousElementSibling.textContent.trim();
      navigator.clipboard.writeText(code).then(() => {
        btn.innerText = "copied";
        setTimeout(() => (btn.innerText = "copy"), 2000);
      });
    }
  </script><h4 id="powers-of-two-between-1-and-100">
  <a class="anchor inpage" href="#powers-of-two-between-1-and-100">####</a>Powers of two between 1 and 100</h4>
<details open>
    <summary>TEXT</summary><pre
        class="codeblock"
      ><code class="language-" data-lang="">awk &#39;BEGIN {
    for (i = 1; i &lt;= 100; i *= 2)
        print i
}&#39;</code><button onclick="copyCode(this)" class="copybtn">copy</button></pre></details>

  <script>
    function copyCode(btn) {
      const code = btn.previousElementSibling.textContent.trim();
      navigator.clipboard.writeText(code).then(() => {
        btn.innerText = "copied";
        setTimeout(() => (btn.innerText = "copy"), 2000);
      });
    }
  </script><h3 id="forin">
  <a class="anchor inpage" href="#forin">###</a>for&hellip;in</h3>
<details open>
    <summary>TEXT</summary><pre
        class="codeblock"
      ><code class="language-" data-lang="">awk &#39;BEGIN {
    assoc[&#34;key1&#34;] = &#34;val1&#34;
    assoc[&#34;key2&#34;] = &#34;val2&#34;
    for (key in assoc)
        print assoc[key];
}&#39;</code><button onclick="copyCode(this)" class="copybtn">copy</button></pre></details>

  <script>
    function copyCode(btn) {
      const code = btn.previousElementSibling.textContent.trim();
      navigator.clipboard.writeText(code).then(() => {
        btn.innerText = "copied";
        setTimeout(() => (btn.innerText = "copy"), 2000);
      });
    }
  </script><h4 id="arguments">
  <a class="anchor inpage" href="#arguments">####</a>Arguments</h4>
<details open>
    <summary>TEXT</summary><pre
        class="codeblock"
      ><code class="language-" data-lang="">awk &#39;BEGIN {
    for (argnum in ARGV)
        print ARGV[argnum];
}&#39; a b c</code><button onclick="copyCode(this)" class="copybtn">copy</button></pre></details>

  <script>
    function copyCode(btn) {
      const code = btn.previousElementSibling.textContent.trim();
      navigator.clipboard.writeText(code).then(() => {
        btn.innerText = "copied";
        setTimeout(() => (btn.innerText = "copy"), 2000);
      });
    }
  </script><h3 id="examples-2">
  <a class="anchor inpage" href="#examples-2">###</a>Examples</h3>
<h4 id="reverse-records">
  <a class="anchor inpage" href="#reverse-records">####</a>Reverse records</h4>
<details open>
    <summary>TEXT</summary><pre
        class="codeblock"
      ><code class="language-" data-lang="">awk -F: &#39;{ x[NR] = $0 }
    END {
        for (i = NR; i &gt; 0; i--)
        print x[i]
    }
&#39; /etc/passwd</code><button onclick="copyCode(this)" class="copybtn">copy</button></pre></details>

  <script>
    function copyCode(btn) {
      const code = btn.previousElementSibling.textContent.trim();
      navigator.clipboard.writeText(code).then(() => {
        btn.innerText = "copied";
        setTimeout(() => (btn.innerText = "copy"), 2000);
      });
    }
  </script><h4 id="reverse-fields">
  <a class="anchor inpage" href="#reverse-fields">####</a>Reverse fields</h4>
<details open>
    <summary>TEXT</summary><pre
        class="codeblock"
      ><code class="language-" data-lang="">awk -F: &#39;{
    for (i = NF; i &gt; 0; i--)
        printf(&#34;%s &#34;,$i);
    print &#34;&#34;
}&#39; /etc/passwd</code><button onclick="copyCode(this)" class="copybtn">copy</button></pre></details>

  <script>
    function copyCode(btn) {
      const code = btn.previousElementSibling.textContent.trim();
      navigator.clipboard.writeText(code).then(() => {
        btn.innerText = "copied";
        setTimeout(() => (btn.innerText = "copy"), 2000);
      });
    }
  </script><h4 id="sum-by-record">
  <a class="anchor inpage" href="#sum-by-record">####</a>Sum by record</h4>
<details open>
    <summary>TEXT</summary><pre
        class="codeblock"
      ><code class="language-" data-lang="">awk -F: &#39;{
    s=0;
    for (i = 1; i &lt;= NF; i&#43;&#43;)
        s &#43;= $i;
    print s
}&#39; /etc/passwd</code><button onclick="copyCode(this)" class="copybtn">copy</button></pre></details>

  <script>
    function copyCode(btn) {
      const code = btn.previousElementSibling.textContent.trim();
      navigator.clipboard.writeText(code).then(() => {
        btn.innerText = "copied";
        setTimeout(() => (btn.innerText = "copy"), 2000);
      });
    }
  </script><h4 id="sum-whole-file">
  <a class="anchor inpage" href="#sum-whole-file">####</a>Sum whole file</h4>
<details open>
    <summary>TEXT</summary><pre
        class="codeblock"
      ><code class="language-" data-lang="">awk -F: &#39;
    {for (i = 1; i &lt;= NF; i&#43;&#43;)
        s &#43;= $i;
    };
    END{print s}
&#39; /etc/passwd</code><button onclick="copyCode(this)" class="copybtn">copy</button></pre></details>

  <script>
    function copyCode(btn) {
      const code = btn.previousElementSibling.textContent.trim();
      navigator.clipboard.writeText(code).then(() => {
        btn.innerText = "copied";
        setTimeout(() => (btn.innerText = "copy"), 2000);
      });
    }
  </script><h3 id="while">
  <a class="anchor inpage" href="#while">###</a>while</h3>
<details open>
    <summary>TEXT</summary><pre
        class="codeblock"
      ><code class="language-" data-lang="">awk &#39;BEGIN {
    while (a &lt; 10) {
        print &#34;- &#34; &#34; concatenation: &#34; a
        a&#43;&#43;;
    }
}&#39;</code><button onclick="copyCode(this)" class="copybtn">copy</button></pre></details>

  <script>
    function copyCode(btn) {
      const code = btn.previousElementSibling.textContent.trim();
      navigator.clipboard.writeText(code).then(() => {
        btn.innerText = "copied";
        setTimeout(() => (btn.innerText = "copy"), 2000);
      });
    }
  </script><h4 id="dowhile">
  <a class="anchor inpage" href="#dowhile">####</a>do&hellip;while</h4>
<details open>
    <summary>TEXT</summary><pre
        class="codeblock"
      ><code class="language-" data-lang="">awk &#39;{
    i = 1
    do {
        print $0
        i&#43;&#43;
    } while (i &lt;= 5)
}&#39; /etc/passwd</code><button onclick="copyCode(this)" class="copybtn">copy</button></pre></details>

  <script>
    function copyCode(btn) {
      const code = btn.previousElementSibling.textContent.trim();
      navigator.clipboard.writeText(code).then(() => {
        btn.innerText = "copied";
        setTimeout(() => (btn.innerText = "copy"), 2000);
      });
    }
  </script><h3 id="break">
  <a class="anchor inpage" href="#break">###</a>Break</h3>
<details open>
    <summary>TEXT</summary><pre
        class="codeblock"
      ><code class="language-" data-lang="">awk &#39;BEGIN {
    break_num = 5
    for (i = 0; i &lt; 10; i&#43;&#43;) {
        print i
        if (i == break_num)
            break
    }
}&#39;</code><button onclick="copyCode(this)" class="copybtn">copy</button></pre></details>

  <script>
    function copyCode(btn) {
      const code = btn.previousElementSibling.textContent.trim();
      navigator.clipboard.writeText(code).then(() => {
        btn.innerText = "copied";
        setTimeout(() => (btn.innerText = "copy"), 2000);
      });
    }
  </script><h3 id="continue">
  <a class="anchor inpage" href="#continue">###</a>Continue</h3>
<details open>
    <summary>TEXT</summary><pre
        class="codeblock"
      ><code class="language-" data-lang="">awk &#39;BEGIN {
    for (x = 0; x &lt;= 10; x&#43;&#43;) {
        if (x == 5 || x == 6)
            continue
        printf &#34;%d &#34;, x
    }
    print &#34;&#34;
}&#39;</code><button onclick="copyCode(this)" class="copybtn">copy</button></pre></details>

  <script>
    function copyCode(btn) {
      const code = btn.previousElementSibling.textContent.trim();
      navigator.clipboard.writeText(code).then(() => {
        btn.innerText = "copied";
        setTimeout(() => (btn.innerText = "copy"), 2000);
      });
    }
  </script><h2 id="awk-formatted-printing">
  <a class="anchor inpage" href="#awk-formatted-printing">##</a>Awk Formatted Printing</h2>
<h3 id="usage">
  <a class="anchor inpage" href="#usage">###</a>Usage</h3>
<h4 id="right-align">
  <a class="anchor inpage" href="#right-align">####</a>Right align</h4>
<details open>
    <summary>TEXT</summary><pre
        class="codeblock"
      ><code class="language-" data-lang="">awk &#39;BEGIN{printf &#34;|%10s|\n&#34;, &#34;hello&#34;}&#39;

|     hello|</code><button onclick="copyCode(this)" class="copybtn">copy</button></pre></details>

  <script>
    function copyCode(btn) {
      const code = btn.previousElementSibling.textContent.trim();
      navigator.clipboard.writeText(code).then(() => {
        btn.innerText = "copied";
        setTimeout(() => (btn.innerText = "copy"), 2000);
      });
    }
  </script><h4 id="left-align">
  <a class="anchor inpage" href="#left-align">####</a>Left align</h4>
<details open>
    <summary>TEXT</summary><pre
        class="codeblock"
      ><code class="language-" data-lang="">awk &#39;BEGIN{printf &#34;|%-10s|\n&#34;, &#34;hello&#34;}&#39;

|hello     |</code><button onclick="copyCode(this)" class="copybtn">copy</button></pre></details>

  <script>
    function copyCode(btn) {
      const code = btn.previousElementSibling.textContent.trim();
      navigator.clipboard.writeText(code).then(() => {
        btn.innerText = "copied";
        setTimeout(() => (btn.innerText = "copy"), 2000);
      });
    }
  </script><h3 id="common-specifiers">
  <a class="anchor inpage" href="#common-specifiers">###</a>Common specifiers</h3>
<table>
  <thead>
      <tr>
          <th>Character</th>
          <th>Description</th>
      </tr>
  </thead>
  <tbody>
      <tr>
          <td><code>c</code></td>
          <td>ASCII character</td>
      </tr>
      <tr>
          <td><code>d</code></td>
          <td>Decimal integer</td>
      </tr>
      <tr>
          <td><code>e</code>, <code>E</code>, <code>f</code></td>
          <td>Floating-point format</td>
      </tr>
      <tr>
          <td><code>o</code></td>
          <td>Unsigned octal value</td>
      </tr>
      <tr>
          <td><code>s</code></td>
          <td>String</td>
      </tr>
      <tr>
          <td><code>%</code></td>
          <td>Literal %</td>
      </tr>
  </tbody>
</table>
<h3 id="space">
  <a class="anchor inpage" href="#space">###</a>Space</h3>
<details open>
    <summary>TEXT</summary><pre
        class="codeblock"
      ><code class="language-" data-lang="">awk -F: &#39;{
    printf &#34;%-10s %s\n&#34;, $1, $(NF-1)
}&#39; /etc/passwd | head -n 3</code><button onclick="copyCode(this)" class="copybtn">copy</button></pre></details>

  <script>
    function copyCode(btn) {
      const code = btn.previousElementSibling.textContent.trim();
      navigator.clipboard.writeText(code).then(() => {
        btn.innerText = "copied";
        setTimeout(() => (btn.innerText = "copy"), 2000);
      });
    }
  </script><p>Outputs</p>
<details open>
    <summary>sh</summary><pre
        class="chroma codeblock"
      ><code class="language-sh" data-lang="sh"
          ><span style="display:flex;"><span>root       /root
</span></span><span style="display:flex;"><span>bin        /bin
</span></span><span style="display:flex;"><span>daemon     /sbin</span></span></code
        ><button onclick="copyCode(this)" class="copybtn">copy</button></pre></details>

  <script>
    function copyCode(btn) {
      const code = btn.previousElementSibling.textContent.trim();
      navigator.clipboard.writeText(code).then(() => {
        btn.innerText = "copied";
        setTimeout(() => (btn.innerText = "copy"), 2000);
      });
    }
  </script><h3 id="header">
  <a class="anchor inpage" href="#header">###</a>Header</h3>
<details open>
    <summary>TEXT</summary><pre
        class="codeblock"
      ><code class="language-" data-lang="">awk -F: &#39;BEGIN {
    printf &#34;%-10s %s\n&#34;, &#34;User&#34;, &#34;Home&#34;
    printf &#34;%-10s %s\n&#34;, &#34;----&#34;,&#34;----&#34;}
    { printf &#34;%-10s %s\n&#34;, $1, $(NF-1) }
&#39; /etc/passwd | head -n 5</code><button onclick="copyCode(this)" class="copybtn">copy</button></pre></details>

  <script>
    function copyCode(btn) {
      const code = btn.previousElementSibling.textContent.trim();
      navigator.clipboard.writeText(code).then(() => {
        btn.innerText = "copied";
        setTimeout(() => (btn.innerText = "copy"), 2000);
      });
    }
  </script><p>Outputs</p>
<details open>
    <summary>TEXT</summary><pre
        class="codeblock"
      ><code class="language-" data-lang="">User       Home
----       ----
root       /root
bin        /bin
daemon     /sbin</code><button onclick="copyCode(this)" class="copybtn">copy</button></pre></details>

  <script>
    function copyCode(btn) {
      const code = btn.previousElementSibling.textContent.trim();
      navigator.clipboard.writeText(code).then(() => {
        btn.innerText = "copied";
        setTimeout(() => (btn.innerText = "copy"), 2000);
      });
    }
  </script><h2 id="miscellaneous">
  <a class="anchor inpage" href="#miscellaneous">##</a>Miscellaneous</h2>
<h3 id="regex-metacharacters">
  <a class="anchor inpage" href="#regex-metacharacters">###</a>Regex Metacharacters</h3>
<ul>
<li><code>\</code></li>
<li><code>^</code></li>
<li><code>$</code></li>
<li><code>.</code></li>
<li><code>[</code></li>
<li><code>]</code></li>
<li><code>|</code></li>
<li><code>(</code></li>
<li><code>)</code></li>
<li><code>*</code></li>
<li><code>+</code></li>
<li><code>?</code></li>
</ul>
<h3 id="escape-sequences">
  <a class="anchor inpage" href="#escape-sequences">###</a>Escape Sequences</h3>
<table>
  <thead>
      <tr>
          <th>-</th>
          <th>-</th>
      </tr>
  </thead>
  <tbody>
      <tr>
          <td><code>\b</code></td>
          <td>Backspace</td>
      </tr>
      <tr>
          <td><code>\f</code></td>
          <td>Form feed</td>
      </tr>
      <tr>
          <td><code>\n</code></td>
          <td>Newline (line feed)</td>
      </tr>
      <tr>
          <td><code>\r</code></td>
          <td>Carriage return</td>
      </tr>
      <tr>
          <td><code>\t</code></td>
          <td>Horizontal tab</td>
      </tr>
      <tr>
          <td><code>\v</code></td>
          <td>Vertical tab</td>
      </tr>
  </tbody>
</table>
<h3 id="run-script">
  <a class="anchor inpage" href="#run-script">###</a>Run script</h3>
<details open>
    <summary>sh</summary><pre
        class="chroma codeblock"
      ><code class="language-sh" data-lang="sh"
          ><span style="display:flex;"><span>$ cat demo.awk
</span></span><span style="display:flex;"><span><span style="color:#75715e">#!/usr/bin/awk -f</span>
</span></span><span style="display:flex;"><span>BEGIN <span style="color:#f92672">{</span> x <span style="color:#f92672">=</span> <span style="color:#ae81ff">23</span> <span style="color:#f92672">}</span>
</span></span><span style="display:flex;"><span>      <span style="color:#f92672">{</span> x <span style="color:#f92672">+=</span> <span style="color:#ae81ff">2</span> <span style="color:#f92672">}</span>
</span></span><span style="display:flex;"><span>END   <span style="color:#f92672">{</span> print x <span style="color:#f92672">}</span>
</span></span><span style="display:flex;"><span>$ awk -f demo.awk /etc/passwd
</span></span><span style="display:flex;"><span><span style="color:#ae81ff">69</span></span></span></code
        ><button onclick="copyCode(this)" class="copybtn">copy</button></pre></details>

  <script>
    function copyCode(btn) {
      const code = btn.previousElementSibling.textContent.trim();
      navigator.clipboard.writeText(code).then(() => {
        btn.innerText = "copied";
        setTimeout(() => (btn.innerText = "copy"), 2000);
      });
    }
  </script><h2 id="also-see">
  <a class="anchor inpage" href="#also-see">##</a>Also see</h2>
<ul>
<li>

<em>(www-zeuthen.desy.de)</em></li>
<li>
 <em>(gist.github.com)</em></li>
</ul>
]]></content:encoded></item><item><title>grep</title><link>https://hiraethecho.github.io/docs/dev/grep/</link><pubDate>Mon, 05 May 2025 00:00:00 +0000</pubDate><author>wyz2016zxc@outlook.com(Hiraeth)</author><guid>https://hiraethecho.github.io/docs/dev/grep/</guid><description>&lt;h2 id="grep"&gt;
&lt;a class="anchor inpage" href="#grep"&gt;##&lt;/a&gt;grep&lt;/h2&gt;
&lt;p&gt;ref:
&lt;/p&gt;
&lt;h2 id="count-occurrence--c"&gt;
&lt;a class="anchor inpage" href="#count-occurrence--c"&gt;##&lt;/a&gt;Count Occurrence: &lt;code&gt;-c&lt;/code&gt;&lt;/h2&gt;
&lt;details open&gt;
&lt;summary&gt;TEXT&lt;/summary&gt;&lt;pre
class="codeblock"
&gt;&lt;code class="language-" data-lang=""&gt;$ cat example.txt | grep -c good
2&lt;/code&gt;&lt;button onclick="copyCode(this)" class="copybtn"&gt;copy&lt;/button&gt;&lt;/pre&gt;&lt;/details&gt;
&lt;script&gt;
function copyCode(btn) {
const code = btn.previousElementSibling.textContent.trim();
navigator.clipboard.writeText(code).then(() =&gt; {
btn.innerText = "copied";
setTimeout(() =&gt; (btn.innerText = "copy"), 2000);
});
}
&lt;/script&gt;&lt;h2 id="get-context--c"&gt;
&lt;a class="anchor inpage" href="#get-context--c"&gt;##&lt;/a&gt;Get Context: &lt;code&gt;-C&lt;/code&gt;&lt;/h2&gt;
&lt;p&gt;Set &lt;code&gt;--context=0&lt;/code&gt; to print that line alone&lt;/p&gt;
&lt;details open&gt;
&lt;summary&gt;TEXT&lt;/summary&gt;&lt;pre
class="codeblock"
&gt;&lt;code class="language-" data-lang=""&gt;$ cat example.txt | grep --context=0 &amp;#34;good luck&amp;#34;
good luck&lt;/code&gt;&lt;button onclick="copyCode(this)" class="copybtn"&gt;copy&lt;/button&gt;&lt;/pre&gt;&lt;/details&gt;
&lt;script&gt;
function copyCode(btn) {
const code = btn.previousElementSibling.textContent.trim();
navigator.clipboard.writeText(code).then(() =&gt; {
btn.innerText = "copied";
setTimeout(() =&gt; (btn.innerText = "copy"), 2000);
});
}
&lt;/script&gt;&lt;p&gt;Set &lt;code&gt;--context=1&lt;/code&gt; to print 1 line below and 1 line above&lt;/p&gt;</description></item><item><title>sed cheatsheet</title><link>https://hiraethecho.github.io/docs/dev/sed/</link><pubDate>Thu, 01 May 2025 00:00:00 +0000</pubDate><author>wyz2016zxc@outlook.com(Hiraeth)</author><guid>https://hiraethecho.github.io/docs/dev/sed/</guid><description>&lt;h1 id="sed"&gt;
&lt;a class="anchor inpage" href="#sed"&gt;#&lt;/a&gt;sed&lt;/h1&gt;
&lt;h2 id="tldr"&gt;
&lt;a class="anchor inpage" href="#tldr"&gt;##&lt;/a&gt;tldr&lt;/h2&gt;
&lt;details open&gt;
&lt;summary&gt;sh&lt;/summary&gt;&lt;pre
class="chroma codeblock"
&gt;&lt;code class="language-sh" data-lang="sh"
&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;sed -i &lt;span style="color:#e6db74"&gt;&amp;#34;[range]s/[patern]/[replacement]/[options]&amp;#34;&lt;/span&gt; file_*
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;sed -i &lt;span style="color:#e6db74"&gt;&amp;#34;2,5s|[patern]|[replacement]|[options]&amp;#34;&lt;/span&gt; file_*&lt;/span&gt;&lt;/span&gt;&lt;/code
&gt;&lt;button onclick="copyCode(this)" class="copybtn"&gt;copy&lt;/button&gt;&lt;/pre&gt;&lt;/details&gt;
&lt;script&gt;
function copyCode(btn) {
const code = btn.previousElementSibling.textContent.trim();
navigator.clipboard.writeText(code).then(() =&gt; {
btn.innerText = "copied";
setTimeout(() =&gt; (btn.innerText = "copy"), 2000);
});
}
&lt;/script&gt;&lt;h3 id="search-for-text"&gt;
&lt;a class="anchor inpage" href="#search-for-text"&gt;###&lt;/a&gt;Search for text&lt;/h3&gt;
&lt;p&gt;Search for a string and only print the lines that were matched&lt;/p&gt;
&lt;details open&gt;
&lt;summary&gt;sh&lt;/summary&gt;&lt;pre
class="chroma codeblock"
&gt;&lt;code class="language-sh" data-lang="sh"
&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;$ sed -n &lt;span style="color:#e6db74"&gt;&amp;#39;/hello/p&amp;#39;&lt;/span&gt; file.txt&lt;/span&gt;&lt;/span&gt;&lt;/code
&gt;&lt;button onclick="copyCode(this)" class="copybtn"&gt;copy&lt;/button&gt;&lt;/pre&gt;&lt;/details&gt;
&lt;script&gt;
function copyCode(btn) {
const code = btn.previousElementSibling.textContent.trim();
navigator.clipboard.writeText(code).then(() =&gt; {
btn.innerText = "copied";
setTimeout(() =&gt; (btn.innerText = "copy"), 2000);
});
}
&lt;/script&gt;&lt;p&gt;Case insensitive search&lt;/p&gt;</description><content:encoded><![CDATA[<h1 id="sed">
  <a class="anchor inpage" href="#sed">#</a>sed</h1>
<h2 id="tldr">
  <a class="anchor inpage" href="#tldr">##</a>tldr</h2>
<details open>
    <summary>sh</summary><pre
        class="chroma codeblock"
      ><code class="language-sh" data-lang="sh"
          ><span style="display:flex;"><span>sed -i <span style="color:#e6db74">&#34;[range]s/[patern]/[replacement]/[options]&#34;</span> file_*
</span></span><span style="display:flex;"><span>sed -i <span style="color:#e6db74">&#34;2,5s|[patern]|[replacement]|[options]&#34;</span> file_*</span></span></code
        ><button onclick="copyCode(this)" class="copybtn">copy</button></pre></details>

  <script>
    function copyCode(btn) {
      const code = btn.previousElementSibling.textContent.trim();
      navigator.clipboard.writeText(code).then(() => {
        btn.innerText = "copied";
        setTimeout(() => (btn.innerText = "copy"), 2000);
      });
    }
  </script><h3 id="search-for-text">
  <a class="anchor inpage" href="#search-for-text">###</a>Search for text</h3>
<p>Search for a string and only print the lines that were matched</p>
<details open>
    <summary>sh</summary><pre
        class="chroma codeblock"
      ><code class="language-sh" data-lang="sh"
          ><span style="display:flex;"><span>$ sed -n <span style="color:#e6db74">&#39;/hello/p&#39;</span> file.txt</span></span></code
        ><button onclick="copyCode(this)" class="copybtn">copy</button></pre></details>

  <script>
    function copyCode(btn) {
      const code = btn.previousElementSibling.textContent.trim();
      navigator.clipboard.writeText(code).then(() => {
        btn.innerText = "copied";
        setTimeout(() => (btn.innerText = "copy"), 2000);
      });
    }
  </script><p>Case insensitive search</p>
<details open>
    <summary>sh</summary><pre
        class="chroma codeblock"
      ><code class="language-sh" data-lang="sh"
          ><span style="display:flex;"><span>$ sed -n <span style="color:#e6db74">&#39;/hello/Ip&#39;</span> file.txt</span></span></code
        ><button onclick="copyCode(this)" class="copybtn">copy</button></pre></details>

  <script>
    function copyCode(btn) {
      const code = btn.previousElementSibling.textContent.trim();
      navigator.clipboard.writeText(code).then(() => {
        btn.innerText = "copied";
        setTimeout(() => (btn.innerText = "copy"), 2000);
      });
    }
  </script><h3 id="sed-usage">
  <a class="anchor inpage" href="#sed-usage">###</a>Sed Usage</h3>
<p>Syntax</p>
<details open>
    <summary>shell</summary><pre
        class="chroma codeblock"
      ><code class="language-shell" data-lang="shell"
          ><span style="display:flex;"><span>$ sed <span style="color:#f92672">[</span>options<span style="color:#f92672">]</span> command <span style="color:#f92672">[</span>input-file<span style="color:#f92672">]</span></span></span></code
        ><button onclick="copyCode(this)" class="copybtn">copy</button></pre></details>

  <script>
    function copyCode(btn) {
      const code = btn.previousElementSibling.textContent.trim();
      navigator.clipboard.writeText(code).then(() => {
        btn.innerText = "copied";
        setTimeout(() => (btn.innerText = "copy"), 2000);
      });
    }
  </script><p>With pipeline</p>
<details open>
    <summary>sh</summary><pre
        class="chroma codeblock"
      ><code class="language-sh" data-lang="sh"
          ><span style="display:flex;"><span>$ cat report.txt | sed <span style="color:#e6db74">&#39;s/Nick/John/g&#39;</span></span></span></code
        ><button onclick="copyCode(this)" class="copybtn">copy</button></pre></details>

  <script>
    function copyCode(btn) {
      const code = btn.previousElementSibling.textContent.trim();
      navigator.clipboard.writeText(code).then(() => {
        btn.innerText = "copied";
        setTimeout(() => (btn.innerText = "copy"), 2000);
      });
    }
  </script><details open>
    <summary>sh</summary><pre
        class="chroma codeblock"
      ><code class="language-sh" data-lang="sh"
          ><span style="display:flex;"><span>$ echo <span style="color:#e6db74">&#39;123abc&#39;</span> | sed <span style="color:#e6db74">&#39;s/[0-9]+//g&#39;</span></span></span></code
        ><button onclick="copyCode(this)" class="copybtn">copy</button></pre></details>

  <script>
    function copyCode(btn) {
      const code = btn.previousElementSibling.textContent.trim();
      navigator.clipboard.writeText(code).then(() => {
        btn.innerText = "copied";
        setTimeout(() => (btn.innerText = "copy"), 2000);
      });
    }
  </script><h3 id="option-examples">
  <a class="anchor inpage" href="#option-examples">###</a>Option Examples</h3>
<table>
  <thead>
      <tr>
          <th>Option</th>
          <th>Example</th>
          <th>Description</th>
      </tr>
  </thead>
  <tbody>
      <tr>
          <td><code>-i</code></td>
          <td>sed -ibak &rsquo;s/On/Off/&rsquo; php.ini</td>
          <td>Backup and modify input file directly</td>
      </tr>
      <tr>
          <td><code>-E</code></td>
          <td>sed -E &rsquo;s/[0-9]+//g&rsquo; input-file</td>
          <td>Use extended regular expressions</td>
      </tr>
      <tr>
          <td><code>-n</code></td>
          <td>sed -n &lsquo;3 p&rsquo; config.conf</td>
          <td>Suppress default pattern space printing</td>
      </tr>
      <tr>
          <td><code>-f</code></td>
          <td>sed -f script.sed config.conf</td>
          <td>Execute sed script file</td>
      </tr>
      <tr>
          <td><code>-e</code></td>
          <td>sed -e &lsquo;command1&rsquo; -e &lsquo;command2&rsquo; input-file</td>
          <td>Execute multiple sed commands</td>
      </tr>
  </tbody>
</table>
<h3 id="multiple-commands">
  <a class="anchor inpage" href="#multiple-commands">###</a>Multiple commands</h3>
<details open>
    <summary>sh</summary><pre
        class="chroma codeblock"
      ><code class="language-sh" data-lang="sh"
          ><span style="display:flex;"><span>$ echo <span style="color:#e6db74">&#34;hello world&#34;</span> | sed -e <span style="color:#e6db74">&#39;s/h/H/g&#39;</span> -e <span style="color:#e6db74">&#39;s/w/W/g&#39;</span>
</span></span><span style="display:flex;"><span>Hello World</span></span></code
        ><button onclick="copyCode(this)" class="copybtn">copy</button></pre></details>

  <script>
    function copyCode(btn) {
      const code = btn.previousElementSibling.textContent.trim();
      navigator.clipboard.writeText(code).then(() => {
        btn.innerText = "copied";
        setTimeout(() => (btn.innerText = "copy"), 2000);
      });
    }
  </script><p>Use <code>-e</code> to execute multiple sed commands</p>
<h3 id="sed-script">
  <a class="anchor inpage" href="#sed-script">###</a>Sed script</h3>
<details open>
    <summary>sh</summary><pre
        class="chroma codeblock"
      ><code class="language-sh" data-lang="sh"
          ><span style="display:flex;"><span>$ echo <span style="color:#e6db74">&#39;s/h/H/g&#39;</span> &gt;&gt; hello.sed
</span></span><span style="display:flex;"><span>$ echo <span style="color:#e6db74">&#39;s/w/W/g&#39;</span> &gt;&gt; hello.sed
</span></span><span style="display:flex;"><span>$ echo <span style="color:#e6db74">&#34;hello world&#34;</span> | sed -f hello.sed
</span></span><span style="display:flex;"><span>Hello World</span></span></code
        ><button onclick="copyCode(this)" class="copybtn">copy</button></pre></details>

  <script>
    function copyCode(btn) {
      const code = btn.previousElementSibling.textContent.trim();
      navigator.clipboard.writeText(code).then(() => {
        btn.innerText = "copied";
        setTimeout(() => (btn.innerText = "copy"), 2000);
      });
    }
  </script><p>Use <code>-f</code> to execute sed script file</p>
<h3 id="examples">
  <a class="anchor inpage" href="#examples">###</a>Examples</h3>
<details open>
    <summary>sh</summary><pre
        class="chroma codeblock"
      ><code class="language-sh" data-lang="sh"
          ><span style="display:flex;"><span>$ sed <span style="color:#e6db74">&#39;s/old/new/g&#39;</span> file.txt
</span></span><span style="display:flex;"><span>$ sed <span style="color:#e6db74">&#39;s/old/new/g&#39;</span> file.txt &gt; new.txt
</span></span><span style="display:flex;"><span>$ sed <span style="color:#e6db74">&#39;s/old/new/g&#39;</span> -i file.txt
</span></span><span style="display:flex;"><span>$ sed <span style="color:#e6db74">&#39;s/old/new/g&#39;</span> -i.backup file.txt</span></span></code
        ><button onclick="copyCode(this)" class="copybtn">copy</button></pre></details>

  <script>
    function copyCode(btn) {
      const code = btn.previousElementSibling.textContent.trim();
      navigator.clipboard.writeText(code).then(() => {
        btn.innerText = "copied";
        setTimeout(() => (btn.innerText = "copy"), 2000);
      });
    }
  </script><h3 id="sed-usage-1">
  <a class="anchor inpage" href="#sed-usage-1">###</a>Sed Usage</h3>
<p>Syntax</p>
<details open>
    <summary>shell</summary><pre
        class="chroma codeblock"
      ><code class="language-shell" data-lang="shell"
          ><span style="display:flex;"><span>$ sed <span style="color:#f92672">[</span>options<span style="color:#f92672">]</span> command <span style="color:#f92672">[</span>input-file<span style="color:#f92672">]</span></span></span></code
        ><button onclick="copyCode(this)" class="copybtn">copy</button></pre></details>

  <script>
    function copyCode(btn) {
      const code = btn.previousElementSibling.textContent.trim();
      navigator.clipboard.writeText(code).then(() => {
        btn.innerText = "copied";
        setTimeout(() => (btn.innerText = "copy"), 2000);
      });
    }
  </script><p>With pipeline</p>
<details open>
    <summary>sh</summary><pre
        class="chroma codeblock"
      ><code class="language-sh" data-lang="sh"
          ><span style="display:flex;"><span>$ cat report.txt | sed <span style="color:#e6db74">&#39;s/Nick/John/g&#39;</span></span></span></code
        ><button onclick="copyCode(this)" class="copybtn">copy</button></pre></details>

  <script>
    function copyCode(btn) {
      const code = btn.previousElementSibling.textContent.trim();
      navigator.clipboard.writeText(code).then(() => {
        btn.innerText = "copied";
        setTimeout(() => (btn.innerText = "copy"), 2000);
      });
    }
  </script><details open>
    <summary>sh</summary><pre
        class="chroma codeblock"
      ><code class="language-sh" data-lang="sh"
          ><span style="display:flex;"><span>$ echo <span style="color:#e6db74">&#39;123abc&#39;</span> | sed <span style="color:#e6db74">&#39;s/[0-9]+//g&#39;</span></span></span></code
        ><button onclick="copyCode(this)" class="copybtn">copy</button></pre></details>

  <script>
    function copyCode(btn) {
      const code = btn.previousElementSibling.textContent.trim();
      navigator.clipboard.writeText(code).then(() => {
        btn.innerText = "copied";
        setTimeout(() => (btn.innerText = "copy"), 2000);
      });
    }
  </script><h3 id="option-examples-1">
  <a class="anchor inpage" href="#option-examples-1">###</a>Option Examples</h3>
<table>
  <thead>
      <tr>
          <th>Option</th>
          <th>Example</th>
          <th>Description</th>
      </tr>
  </thead>
  <tbody>
      <tr>
          <td><code>-i</code></td>
          <td>sed -ibak &rsquo;s/On/Off/&rsquo; php.ini</td>
          <td>Backup and modify input file directly</td>
      </tr>
      <tr>
          <td><code>-E</code></td>
          <td>sed -E &rsquo;s/[0-9]+//g&rsquo; input-file</td>
          <td>Use extended regular expressions</td>
      </tr>
      <tr>
          <td><code>-n</code></td>
          <td>sed -n &lsquo;3 p&rsquo; config.conf</td>
          <td>Suppress default pattern space printing</td>
      </tr>
      <tr>
          <td><code>-f</code></td>
          <td>sed -f script.sed config.conf</td>
          <td>Execute sed script file</td>
      </tr>
      <tr>
          <td><code>-e</code></td>
          <td>sed -e &lsquo;command1&rsquo; -e &lsquo;command2&rsquo; input-file</td>
          <td>Execute multiple sed commands</td>
      </tr>
  </tbody>
</table>
<h3 id="multiple-commands-1">
  <a class="anchor inpage" href="#multiple-commands-1">###</a>Multiple commands</h3>
<details open>
    <summary>sh</summary><pre
        class="chroma codeblock"
      ><code class="language-sh" data-lang="sh"
          ><span style="display:flex;"><span>$ echo <span style="color:#e6db74">&#34;hello world&#34;</span> | sed -e <span style="color:#e6db74">&#39;s/h/H/g&#39;</span> -e <span style="color:#e6db74">&#39;s/w/W/g&#39;</span>
</span></span><span style="display:flex;"><span>Hello World</span></span></code
        ><button onclick="copyCode(this)" class="copybtn">copy</button></pre></details>

  <script>
    function copyCode(btn) {
      const code = btn.previousElementSibling.textContent.trim();
      navigator.clipboard.writeText(code).then(() => {
        btn.innerText = "copied";
        setTimeout(() => (btn.innerText = "copy"), 2000);
      });
    }
  </script><p>Use <code>-e</code> to execute multiple sed commands</p>
<h3 id="sed-script-1">
  <a class="anchor inpage" href="#sed-script-1">###</a>Sed script</h3>
<details open>
    <summary>sh</summary><pre
        class="chroma codeblock"
      ><code class="language-sh" data-lang="sh"
          ><span style="display:flex;"><span>$ echo <span style="color:#e6db74">&#39;s/h/H/g&#39;</span> &gt;&gt; hello.sed
</span></span><span style="display:flex;"><span>$ echo <span style="color:#e6db74">&#39;s/w/W/g&#39;</span> &gt;&gt; hello.sed
</span></span><span style="display:flex;"><span>$ echo <span style="color:#e6db74">&#34;hello world&#34;</span> | sed -f hello.sed
</span></span><span style="display:flex;"><span>Hello World</span></span></code
        ><button onclick="copyCode(this)" class="copybtn">copy</button></pre></details>

  <script>
    function copyCode(btn) {
      const code = btn.previousElementSibling.textContent.trim();
      navigator.clipboard.writeText(code).then(() => {
        btn.innerText = "copied";
        setTimeout(() => (btn.innerText = "copy"), 2000);
      });
    }
  </script><p>Use <code>-f</code> to execute sed script file</p>
<h3 id="examples-1">
  <a class="anchor inpage" href="#examples-1">###</a>Examples</h3>
<details open>
    <summary>sh</summary><pre
        class="chroma codeblock"
      ><code class="language-sh" data-lang="sh"
          ><span style="display:flex;"><span>$ sed <span style="color:#e6db74">&#39;s/old/new/g&#39;</span> file.txt
</span></span><span style="display:flex;"><span>$ sed <span style="color:#e6db74">&#39;s/old/new/g&#39;</span> file.txt &gt; new.txt
</span></span><span style="display:flex;"><span>$ sed <span style="color:#e6db74">&#39;s/old/new/g&#39;</span> -i file.txt
</span></span><span style="display:flex;"><span>$ sed <span style="color:#e6db74">&#39;s/old/new/g&#39;</span> -i.backup file.txt</span></span></code
        ><button onclick="copyCode(this)" class="copybtn">copy</button></pre></details>

  <script>
    function copyCode(btn) {
      const code = btn.previousElementSibling.textContent.trim();
      navigator.clipboard.writeText(code).then(() => {
        btn.innerText = "copied";
        setTimeout(() => (btn.innerText = "copy"), 2000);
      });
    }
  </script><h2 id="sed-commands">
  <a class="anchor inpage" href="#sed-commands">##</a>Sed commands</h2>
<h3 id="commands">
  <a class="anchor inpage" href="#commands">###</a>Commands</h3>
<table>
  <thead>
      <tr>
          <th>Command</th>
          <th>Example</th>
          <th>Description</th>
      </tr>
  </thead>
  <tbody>
      <tr>
          <td><code>p</code></td>
          <td>sed -n &lsquo;1,4 p&rsquo; input.txt</td>
          <td>Print lines 1-4</td>
      </tr>
      <tr>
          <td><code>p</code></td>
          <td>sed -n -e &lsquo;1,4 p&rsquo; -e &lsquo;6,7 p&rsquo; input.txt</td>
          <td>Print lines 1-4 and 6-7</td>
      </tr>
      <tr>
          <td><code>d</code></td>
          <td>sed &lsquo;1,4 d&rsquo; input.txt</td>
          <td>Print lines except 1-4</td>
      </tr>
      <tr>
          <td><code>w</code></td>
          <td>sed -n &lsquo;1,4 w output.txt&rsquo; input.txt</td>
          <td>Write pattern space to file</td>
      </tr>
      <tr>
          <td><code>a</code></td>
          <td>sed &lsquo;2 a new-line&rsquo; input.txt</td>
          <td>Append line after</td>
      </tr>
      <tr>
          <td><code>i</code></td>
          <td>sed &lsquo;2 i new-line&rsquo; input.txt</td>
          <td>Insert line before</td>
      </tr>
  </tbody>
</table>
<h3 id="space-commands">
  <a class="anchor inpage" href="#space-commands">###</a>Space commands</h3>
<table>
  <thead>
      <tr>
          <th>Command</th>
          <th>Description</th>
      </tr>
  </thead>
  <tbody>
      <tr>
          <td><code>n</code></td>
          <td>Print pattern space, empty pattern space, and read next line</td>
      </tr>
      <tr>
          <td><code>x</code></td>
          <td>Swap pattern space with hold space</td>
      </tr>
      <tr>
          <td><code>h</code></td>
          <td>Copy pattern space to hold space</td>
      </tr>
      <tr>
          <td><code>H</code></td>
          <td>Append pattern space to hold space</td>
      </tr>
      <tr>
          <td><code>g</code></td>
          <td>Copy hold space to pattern space</td>
      </tr>
      <tr>
          <td><code>G</code></td>
          <td>Append hold space to pattern space</td>
      </tr>
  </tbody>
</table>
<h3 id="flags">
  <a class="anchor inpage" href="#flags">###</a>Flags</h3>
<details open>
    <summary>sh</summary><pre
        class="chroma codeblock"
      ><code class="language-sh" data-lang="sh"
          ><span style="display:flex;"><span>$ sed <span style="color:#e6db74">&#39;s/old/new/[flags]&#39;</span> <span style="color:#f92672">[</span>input-file<span style="color:#f92672">]</span></span></span></code
        ><button onclick="copyCode(this)" class="copybtn">copy</button></pre></details>

  <script>
    function copyCode(btn) {
      const code = btn.previousElementSibling.textContent.trim();
      navigator.clipboard.writeText(code).then(() => {
        btn.innerText = "copied";
        setTimeout(() => (btn.innerText = "copy"), 2000);
      });
    }
  </script><hr>
<table>
  <thead>
      <tr>
          <th>Flag</th>
          <th>Description</th>
      </tr>
  </thead>
  <tbody>
      <tr>
          <td><code>g</code></td>
          <td>Global substitution</td>
      </tr>
      <tr>
          <td><code>1,2...</code></td>
          <td>Substitute the nth occurrence</td>
      </tr>
      <tr>
          <td><code>p</code></td>
          <td>Print only the substituted line</td>
      </tr>
      <tr>
          <td><code>w</code></td>
          <td>Write only the substituted line to a file</td>
      </tr>
      <tr>
          <td><code>I</code></td>
          <td>Ignore case while searching</td>
      </tr>
      <tr>
          <td><code>e</code></td>
          <td>Substitute and execute in the command line</td>
      </tr>
  </tbody>
</table>
<h3 id="loops-commands">
  <a class="anchor inpage" href="#loops-commands">###</a>Loops commands</h3>
<table>
  <thead>
      <tr>
          <th>Command</th>
          <th>Description</th>
      </tr>
  </thead>
  <tbody>
      <tr>
          <td><code>b label</code></td>
          <td>Branch to a label (for looping)</td>
      </tr>
      <tr>
          <td><code>t label</code></td>
          <td>Branch to a label only on successful substitution<br>(for looping)</td>
      </tr>
      <tr>
          <td><code>:label</code></td>
          <td>Label for the b and t commands (for looping)</td>
      </tr>
      <tr>
          <td><code>N</code></td>
          <td>Append next line to pattern space</td>
      </tr>
      <tr>
          <td><code>P</code></td>
          <td>Print 1st line in multi-line</td>
      </tr>
      <tr>
          <td><code>D</code></td>
          <td>Delete 1st line in multi-line</td>
      </tr>
  </tbody>
</table>
<h3 id="misc-flags">
  <a class="anchor inpage" href="#misc-flags">###</a>Misc Flags</h3>
<table>
  <thead>
      <tr>
          <th>Flag</th>
          <th>Description</th>
      </tr>
  </thead>
  <tbody>
      <tr>
          <td><code>/ | ^ @ ! #</code></td>
          <td>Substitution delimiter can be any character</td>
      </tr>
      <tr>
          <td><code>&amp;</code></td>
          <td>Gets the matched pattern</td>
      </tr>
      <tr>
          <td><code>( ) \1 \2 \3</code></td>
          <td>Group using <code>(</code> and <code>)</code>.<br>Use <code>\1</code>, <code>\2</code> in replacement to refer the group</td>
      </tr>
  </tbody>
</table>
<h2 id="sed-examples">
  <a class="anchor inpage" href="#sed-examples">##</a>Sed examples</h2>
<h3 id="replacing-text">
  <a class="anchor inpage" href="#replacing-text">###</a>Replacing text</h3>
<p>Replace all occurrences of a string</p>
<details open>
    <summary>sh</summary><pre
        class="chroma codeblock"
      ><code class="language-sh" data-lang="sh"
          ><span style="display:flex;"><span>$ sed <span style="color:#e6db74">&#39;s/old/new/g&#39;</span> file.txt</span></span></code
        ><button onclick="copyCode(this)" class="copybtn">copy</button></pre></details>

  <script>
    function copyCode(btn) {
      const code = btn.previousElementSibling.textContent.trim();
      navigator.clipboard.writeText(code).then(() => {
        btn.innerText = "copied";
        setTimeout(() => (btn.innerText = "copy"), 2000);
      });
    }
  </script><p>Replace only the nth occurrence of a string</p>
<details open>
    <summary>sh</summary><pre
        class="chroma codeblock"
      ><code class="language-sh" data-lang="sh"
          ><span style="display:flex;"><span>$ sed <span style="color:#e6db74">&#39;s/old/new/2&#39;</span> file.txt</span></span></code
        ><button onclick="copyCode(this)" class="copybtn">copy</button></pre></details>

  <script>
    function copyCode(btn) {
      const code = btn.previousElementSibling.textContent.trim();
      navigator.clipboard.writeText(code).then(() => {
        btn.innerText = "copied";
        setTimeout(() => (btn.innerText = "copy"), 2000);
      });
    }
  </script><p>Replace a string only on the 5th line</p>
<details open>
    <summary>sh</summary><pre
        class="chroma codeblock"
      ><code class="language-sh" data-lang="sh"
          ><span style="display:flex;"><span>$ sed <span style="color:#e6db74">&#39;5 s/old/new/&#39;</span> file.txt</span></span></code
        ><button onclick="copyCode(this)" class="copybtn">copy</button></pre></details>

  <script>
    function copyCode(btn) {
      const code = btn.previousElementSibling.textContent.trim();
      navigator.clipboard.writeText(code).then(() => {
        btn.innerText = "copied";
        setTimeout(() => (btn.innerText = "copy"), 2000);
      });
    }
  </script><p>Replace &ldquo;world&rdquo; with &ldquo;universe&rdquo; but only if the line begins with &ldquo;hello&rdquo;</p>
<details open>
    <summary>sh</summary><pre
        class="chroma codeblock"
      ><code class="language-sh" data-lang="sh"
          ><span style="display:flex;"><span>$ sed <span style="color:#e6db74">&#39;/hello/s/world/universe/&#39;</span> file.txt</span></span></code
        ><button onclick="copyCode(this)" class="copybtn">copy</button></pre></details>

  <script>
    function copyCode(btn) {
      const code = btn.previousElementSibling.textContent.trim();
      navigator.clipboard.writeText(code).then(() => {
        btn.innerText = "copied";
        setTimeout(() => (btn.innerText = "copy"), 2000);
      });
    }
  </script><p>Remove &ldquo;&quot; from the end of each line</p>
<details open>
    <summary>sh</summary><pre
        class="chroma codeblock"
      ><code class="language-sh" data-lang="sh"
          ><span style="display:flex;"><span>$ sed <span style="color:#e6db74">&#39;s/\\$//&#39;</span> file.txt</span></span></code
        ><button onclick="copyCode(this)" class="copybtn">copy</button></pre></details>

  <script>
    function copyCode(btn) {
      const code = btn.previousElementSibling.textContent.trim();
      navigator.clipboard.writeText(code).then(() => {
        btn.innerText = "copied";
        setTimeout(() => (btn.innerText = "copy"), 2000);
      });
    }
  </script><p>Remove all whitespace from beginning of each line</p>
<details open>
    <summary>sh</summary><pre
        class="chroma codeblock"
      ><code class="language-sh" data-lang="sh"
          ><span style="display:flex;"><span>$ sed <span style="color:#e6db74">&#39;s/^\s*//&#39;</span> file.txt</span></span></code
        ><button onclick="copyCode(this)" class="copybtn">copy</button></pre></details>

  <script>
    function copyCode(btn) {
      const code = btn.previousElementSibling.textContent.trim();
      navigator.clipboard.writeText(code).then(() => {
        btn.innerText = "copied";
        setTimeout(() => (btn.innerText = "copy"), 2000);
      });
    }
  </script><p>Remove comments. Even those that are at the end of a line</p>
<details open>
    <summary>sh</summary><pre
        class="chroma codeblock"
      ><code class="language-sh" data-lang="sh"
          ><span style="display:flex;"><span>$ sed <span style="color:#e6db74">&#39;s/#.*$//&#39;</span> file.txt</span></span></code
        ><button onclick="copyCode(this)" class="copybtn">copy</button></pre></details>

  <script>
    function copyCode(btn) {
      const code = btn.previousElementSibling.textContent.trim();
      navigator.clipboard.writeText(code).then(() => {
        btn.innerText = "copied";
        setTimeout(() => (btn.innerText = "copy"), 2000);
      });
    }
  </script><h3 id="search-for-text-1">
  <a class="anchor inpage" href="#search-for-text-1">###</a>Search for text</h3>
<p>Search for a string and only print the lines that were matched</p>
<details open>
    <summary>sh</summary><pre
        class="chroma codeblock"
      ><code class="language-sh" data-lang="sh"
          ><span style="display:flex;"><span>$ sed -n <span style="color:#e6db74">&#39;/hello/p&#39;</span> file.txt</span></span></code
        ><button onclick="copyCode(this)" class="copybtn">copy</button></pre></details>

  <script>
    function copyCode(btn) {
      const code = btn.previousElementSibling.textContent.trim();
      navigator.clipboard.writeText(code).then(() => {
        btn.innerText = "copied";
        setTimeout(() => (btn.innerText = "copy"), 2000);
      });
    }
  </script><p>Case insensitive search</p>
<details open>
    <summary>sh</summary><pre
        class="chroma codeblock"
      ><code class="language-sh" data-lang="sh"
          ><span style="display:flex;"><span>$ sed -n <span style="color:#e6db74">&#39;/hello/Ip&#39;</span> file.txt</span></span></code
        ><button onclick="copyCode(this)" class="copybtn">copy</button></pre></details>

  <script>
    function copyCode(btn) {
      const code = btn.previousElementSibling.textContent.trim();
      navigator.clipboard.writeText(code).then(() => {
        btn.innerText = "copied";
        setTimeout(() => (btn.innerText = "copy"), 2000);
      });
    }
  </script><p>Search for a string but only output lines that do not match</p>
<details open>
    <summary>sh</summary><pre
        class="chroma codeblock"
      ><code class="language-sh" data-lang="sh"
          ><span style="display:flex;"><span>$ sed -n <span style="color:#e6db74">&#39;/hello/!p&#39;</span> file.txt</span></span></code
        ><button onclick="copyCode(this)" class="copybtn">copy</button></pre></details>

  <script>
    function copyCode(btn) {
      const code = btn.previousElementSibling.textContent.trim();
      navigator.clipboard.writeText(code).then(() => {
        btn.innerText = "copied";
        setTimeout(() => (btn.innerText = "copy"), 2000);
      });
    }
  </script><h3 id="appending-lines">
  <a class="anchor inpage" href="#appending-lines">###</a>Appending lines</h3>
<p>Append line after line 2</p>
<details open>
    <summary>sh</summary><pre
        class="chroma codeblock"
      ><code class="language-sh" data-lang="sh"
          ><span style="display:flex;"><span>$ sed <span style="color:#e6db74">&#39;2a Text after line 2&#39;</span> file.txt</span></span></code
        ><button onclick="copyCode(this)" class="copybtn">copy</button></pre></details>

  <script>
    function copyCode(btn) {
      const code = btn.previousElementSibling.textContent.trim();
      navigator.clipboard.writeText(code).then(() => {
        btn.innerText = "copied";
        setTimeout(() => (btn.innerText = "copy"), 2000);
      });
    }
  </script><p>Append line at the end of the file</p>
<details open>
    <summary>sh</summary><pre
        class="chroma codeblock"
      ><code class="language-sh" data-lang="sh"
          ><span style="display:flex;"><span>$ sed <span style="color:#e6db74">&#39;$a THE END!&#39;</span> file.txt</span></span></code
        ><button onclick="copyCode(this)" class="copybtn">copy</button></pre></details>

  <script>
    function copyCode(btn) {
      const code = btn.previousElementSibling.textContent.trim();
      navigator.clipboard.writeText(code).then(() => {
        btn.innerText = "copied";
        setTimeout(() => (btn.innerText = "copy"), 2000);
      });
    }
  </script><p>Append line after every 3rd line starting from line 3</p>
<details open>
    <summary>sh</summary><pre
        class="chroma codeblock"
      ><code class="language-sh" data-lang="sh"
          ><span style="display:flex;"><span>$ sed <span style="color:#e6db74">&#39;3~3a Some text&#39;</span> file.txt</span></span></code
        ><button onclick="copyCode(this)" class="copybtn">copy</button></pre></details>

  <script>
    function copyCode(btn) {
      const code = btn.previousElementSibling.textContent.trim();
      navigator.clipboard.writeText(code).then(() => {
        btn.innerText = "copied";
        setTimeout(() => (btn.innerText = "copy"), 2000);
      });
    }
  </script><h3 id="numbering">
  <a class="anchor inpage" href="#numbering">###</a>Numbering</h3>
<p>Number line of a file (simple left alignment)</p>
<details open>
    <summary>sh</summary><pre
        class="chroma codeblock"
      ><code class="language-sh" data-lang="sh"
          ><span style="display:flex;"><span>$ sed <span style="color:#f92672">=</span> file.txt | sed <span style="color:#e6db74">&#39;N;s/\n/\t/&#39;</span></span></span></code
        ><button onclick="copyCode(this)" class="copybtn">copy</button></pre></details>

  <script>
    function copyCode(btn) {
      const code = btn.previousElementSibling.textContent.trim();
      navigator.clipboard.writeText(code).then(() => {
        btn.innerText = "copied";
        setTimeout(() => (btn.innerText = "copy"), 2000);
      });
    }
  </script><p>Number line of a file (number on left, right-aligned)</p>
<details open>
    <summary>sh</summary><pre
        class="chroma codeblock"
      ><code class="language-sh" data-lang="sh"
          ><span style="display:flex;"><span>$ sed <span style="color:#f92672">=</span> file.txt | sed <span style="color:#e6db74">&#39;N; s/^/   /; s/ *\(.\{6,\}\)\n/\1  /&#39;</span></span></span></code
        ><button onclick="copyCode(this)" class="copybtn">copy</button></pre></details>

  <script>
    function copyCode(btn) {
      const code = btn.previousElementSibling.textContent.trim();
      navigator.clipboard.writeText(code).then(() => {
        btn.innerText = "copied";
        setTimeout(() => (btn.innerText = "copy"), 2000);
      });
    }
  </script><p>Number line of file, but only print numbers if line is not blank</p>
<details open>
    <summary>sh</summary><pre
        class="chroma codeblock"
      ><code class="language-sh" data-lang="sh"
          ><span style="display:flex;"><span>$ sed <span style="color:#e6db74">&#39;/./=&#39;</span> file.txt | sed <span style="color:#e6db74">&#39;/./N; s/\n/ /&#39;</span></span></span></code
        ><button onclick="copyCode(this)" class="copybtn">copy</button></pre></details>

  <script>
    function copyCode(btn) {
      const code = btn.previousElementSibling.textContent.trim();
      navigator.clipboard.writeText(code).then(() => {
        btn.innerText = "copied";
        setTimeout(() => (btn.innerText = "copy"), 2000);
      });
    }
  </script><p>Count lines (emulates &ldquo;wc -l&rdquo;)</p>
<details open>
    <summary>sh</summary><pre
        class="chroma codeblock"
      ><code class="language-sh" data-lang="sh"
          ><span style="display:flex;"><span>$ sed -n <span style="color:#e6db74">&#39;$=&#39;</span></span></span></code
        ><button onclick="copyCode(this)" class="copybtn">copy</button></pre></details>

  <script>
    function copyCode(btn) {
      const code = btn.previousElementSibling.textContent.trim();
      navigator.clipboard.writeText(code).then(() => {
        btn.innerText = "copied";
        setTimeout(() => (btn.innerText = "copy"), 2000);
      });
    }
  </script><h3 id="prepending-lines">
  <a class="anchor inpage" href="#prepending-lines">###</a>Prepending lines</h3>
<p>Insert text before line 5</p>
<details open>
    <summary>sh</summary><pre
        class="chroma codeblock"
      ><code class="language-sh" data-lang="sh"
          ><span style="display:flex;"><span>$ sed <span style="color:#e6db74">&#39;5i line number five&#39;</span> file.txt</span></span></code
        ><button onclick="copyCode(this)" class="copybtn">copy</button></pre></details>

  <script>
    function copyCode(btn) {
      const code = btn.previousElementSibling.textContent.trim();
      navigator.clipboard.writeText(code).then(() => {
        btn.innerText = "copied";
        setTimeout(() => (btn.innerText = "copy"), 2000);
      });
    }
  </script><p>Insert &ldquo;Example: &quot; before each line that contains &ldquo;hello&rdquo;</p>
<details open>
    <summary>sh</summary><pre
        class="chroma codeblock"
      ><code class="language-sh" data-lang="sh"
          ><span style="display:flex;"><span>$ sed <span style="color:#e6db74">&#39;/hello/i Example: &#39;</span> file.txt</span></span></code
        ><button onclick="copyCode(this)" class="copybtn">copy</button></pre></details>

  <script>
    function copyCode(btn) {
      const code = btn.previousElementSibling.textContent.trim();
      navigator.clipboard.writeText(code).then(() => {
        btn.innerText = "copied";
        setTimeout(() => (btn.innerText = "copy"), 2000);
      });
    }
  </script><h3 id="deleting-lines">
  <a class="anchor inpage" href="#deleting-lines">###</a>Deleting lines</h3>
<p>Delete line 5-7 in file</p>
<details open>
    <summary>sh</summary><pre
        class="chroma codeblock"
      ><code class="language-sh" data-lang="sh"
          ><span style="display:flex;"><span>$ sed <span style="color:#e6db74">&#39;5,7d&#39;</span> file.txt</span></span></code
        ><button onclick="copyCode(this)" class="copybtn">copy</button></pre></details>

  <script>
    function copyCode(btn) {
      const code = btn.previousElementSibling.textContent.trim();
      navigator.clipboard.writeText(code).then(() => {
        btn.innerText = "copied";
        setTimeout(() => (btn.innerText = "copy"), 2000);
      });
    }
  </script><p>Delete every 2nd line starting with line 3</p>
<details open>
    <summary>sh</summary><pre
        class="chroma codeblock"
      ><code class="language-sh" data-lang="sh"
          ><span style="display:flex;"><span>$ sed <span style="color:#e6db74">&#39;3~2d&#39;</span> file.txt</span></span></code
        ><button onclick="copyCode(this)" class="copybtn">copy</button></pre></details>

  <script>
    function copyCode(btn) {
      const code = btn.previousElementSibling.textContent.trim();
      navigator.clipboard.writeText(code).then(() => {
        btn.innerText = "copied";
        setTimeout(() => (btn.innerText = "copy"), 2000);
      });
    }
  </script><p>Delete the last line in file</p>
<details open>
    <summary>sh</summary><pre
        class="chroma codeblock"
      ><code class="language-sh" data-lang="sh"
          ><span style="display:flex;"><span>$ sed <span style="color:#e6db74">&#39;$d&#39;</span> file.txt</span></span></code
        ><button onclick="copyCode(this)" class="copybtn">copy</button></pre></details>

  <script>
    function copyCode(btn) {
      const code = btn.previousElementSibling.textContent.trim();
      navigator.clipboard.writeText(code).then(() => {
        btn.innerText = "copied";
        setTimeout(() => (btn.innerText = "copy"), 2000);
      });
    }
  </script><p>Delete lines starting with &ldquo;Hello&rdquo;</p>
<details open>
    <summary>sh</summary><pre
        class="chroma codeblock"
      ><code class="language-sh" data-lang="sh"
          ><span style="display:flex;"><span>$ sed <span style="color:#e6db74">&#39;/^Hello/d&#39;</span> file.txt</span></span></code
        ><button onclick="copyCode(this)" class="copybtn">copy</button></pre></details>

  <script>
    function copyCode(btn) {
      const code = btn.previousElementSibling.textContent.trim();
      navigator.clipboard.writeText(code).then(() => {
        btn.innerText = "copied";
        setTimeout(() => (btn.innerText = "copy"), 2000);
      });
    }
  </script><p>Delete all empty lines</p>
<details open>
    <summary>sh</summary><pre
        class="chroma codeblock"
      ><code class="language-sh" data-lang="sh"
          ><span style="display:flex;"><span>$ sed <span style="color:#e6db74">&#39;/^$/d&#39;</span> file.txt</span></span></code
        ><button onclick="copyCode(this)" class="copybtn">copy</button></pre></details>

  <script>
    function copyCode(btn) {
      const code = btn.previousElementSibling.textContent.trim();
      navigator.clipboard.writeText(code).then(() => {
        btn.innerText = "copied";
        setTimeout(() => (btn.innerText = "copy"), 2000);
      });
    }
  </script><p>Delete lines starting with &ldquo;#&rdquo;</p>
<details open>
    <summary>sh</summary><pre
        class="chroma codeblock"
      ><code class="language-sh" data-lang="sh"
          ><span style="display:flex;"><span>$ sed <span style="color:#e6db74">&#39;/^#/d&#39;</span> file.txt</span></span></code
        ><button onclick="copyCode(this)" class="copybtn">copy</button></pre></details>

  <script>
    function copyCode(btn) {
      const code = btn.previousElementSibling.textContent.trim();
      navigator.clipboard.writeText(code).then(() => {
        btn.innerText = "copied";
        setTimeout(() => (btn.innerText = "copy"), 2000);
      });
    }
  </script><h3 id="file-spacing">
  <a class="anchor inpage" href="#file-spacing">###</a>File spacing</h3>
<p>Double space</p>
<details open>
    <summary>sh</summary><pre
        class="chroma codeblock"
      ><code class="language-sh" data-lang="sh"
          ><span style="display:flex;"><span>$ sed G</span></span></code
        ><button onclick="copyCode(this)" class="copybtn">copy</button></pre></details>

  <script>
    function copyCode(btn) {
      const code = btn.previousElementSibling.textContent.trim();
      navigator.clipboard.writeText(code).then(() => {
        btn.innerText = "copied";
        setTimeout(() => (btn.innerText = "copy"), 2000);
      });
    }
  </script><p>Delete all blank lines and double space</p>
<details open>
    <summary>sh</summary><pre
        class="chroma codeblock"
      ><code class="language-sh" data-lang="sh"
          ><span style="display:flex;"><span>$ sed <span style="color:#e6db74">&#39;/^$/d;G&#39;</span></span></span></code
        ><button onclick="copyCode(this)" class="copybtn">copy</button></pre></details>

  <script>
    function copyCode(btn) {
      const code = btn.previousElementSibling.textContent.trim();
      navigator.clipboard.writeText(code).then(() => {
        btn.innerText = "copied";
        setTimeout(() => (btn.innerText = "copy"), 2000);
      });
    }
  </script><p>Triple space a file</p>
<details open>
    <summary>sh</summary><pre
        class="chroma codeblock"
      ><code class="language-sh" data-lang="sh"
          ><span style="display:flex;"><span>$ sed <span style="color:#e6db74">&#39;G;G&#39;</span></span></span></code
        ><button onclick="copyCode(this)" class="copybtn">copy</button></pre></details>

  <script>
    function copyCode(btn) {
      const code = btn.previousElementSibling.textContent.trim();
      navigator.clipboard.writeText(code).then(() => {
        btn.innerText = "copied";
        setTimeout(() => (btn.innerText = "copy"), 2000);
      });
    }
  </script><p>Undo double-spacing</p>
<details open>
    <summary>sh</summary><pre
        class="chroma codeblock"
      ><code class="language-sh" data-lang="sh"
          ><span style="display:flex;"><span>$ sed <span style="color:#e6db74">&#39;n;d&#39;</span></span></span></code
        ><button onclick="copyCode(this)" class="copybtn">copy</button></pre></details>

  <script>
    function copyCode(btn) {
      const code = btn.previousElementSibling.textContent.trim();
      navigator.clipboard.writeText(code).then(() => {
        btn.innerText = "copied";
        setTimeout(() => (btn.innerText = "copy"), 2000);
      });
    }
  </script><p>Insert a blank line above line which matches &ldquo;regex&rdquo;</p>
<details open>
    <summary>sh</summary><pre
        class="chroma codeblock"
      ><code class="language-sh" data-lang="sh"
          ><span style="display:flex;"><span>$ sed <span style="color:#e6db74">&#39;/regex/{x;p;x;}&#39;</span></span></span></code
        ><button onclick="copyCode(this)" class="copybtn">copy</button></pre></details>

  <script>
    function copyCode(btn) {
      const code = btn.previousElementSibling.textContent.trim();
      navigator.clipboard.writeText(code).then(() => {
        btn.innerText = "copied";
        setTimeout(() => (btn.innerText = "copy"), 2000);
      });
    }
  </script><p>Insert a blank line below line which matches &ldquo;regex&rdquo;</p>
<details open>
    <summary>sh</summary><pre
        class="chroma codeblock"
      ><code class="language-sh" data-lang="sh"
          ><span style="display:flex;"><span>$ sed <span style="color:#e6db74">&#39;/regex/G&#39;</span></span></span></code
        ><button onclick="copyCode(this)" class="copybtn">copy</button></pre></details>

  <script>
    function copyCode(btn) {
      const code = btn.previousElementSibling.textContent.trim();
      navigator.clipboard.writeText(code).then(() => {
        btn.innerText = "copied";
        setTimeout(() => (btn.innerText = "copy"), 2000);
      });
    }
  </script><p>Insert a blank line around line which matches &ldquo;regex&rdquo;</p>
<details open>
    <summary>sh</summary><pre
        class="chroma codeblock"
      ><code class="language-sh" data-lang="sh"
          ><span style="display:flex;"><span>$ sed <span style="color:#e6db74">&#39;/regex/{x;p;x;G;}&#39;</span></span></span></code
        ><button onclick="copyCode(this)" class="copybtn">copy</button></pre></details>

  <script>
    function copyCode(btn) {
      const code = btn.previousElementSibling.textContent.trim();
      navigator.clipboard.writeText(code).then(() => {
        btn.innerText = "copied";
        setTimeout(() => (btn.innerText = "copy"), 2000);
      });
    }
  </script><h2 id="also-see">
  <a class="anchor inpage" href="#also-see">##</a>Also see</h2>
<ul>
<li>
 <em>(gist.github.com)</em>
<blockquote class="alert"><p>本文由 
 转码， 原文地址 

Sed is a stream editor, this sed cheat sheet contains sed commands and some common sed tricks.</p>
</blockquote></li>
</ul>
<h3 id="replacing-text-1">
  <a class="anchor inpage" href="#replacing-text-1">###</a>Replacing text</h3>
<p>Replace all occurrences of a string</p>
<details open>
    <summary>TEXT</summary><pre
        class="codeblock"
      ><code class="language-" data-lang="">$ sed &#39;s/old/new/g&#39; file.txt</code><button onclick="copyCode(this)" class="copybtn">copy</button></pre></details>

  <script>
    function copyCode(btn) {
      const code = btn.previousElementSibling.textContent.trim();
      navigator.clipboard.writeText(code).then(() => {
        btn.innerText = "copied";
        setTimeout(() => (btn.innerText = "copy"), 2000);
      });
    }
  </script><p>Replace only the nth occurrence of a string</p>
<details open>
    <summary>TEXT</summary><pre
        class="codeblock"
      ><code class="language-" data-lang="">$ sed &#39;s/old/new/2&#39; file.txt</code><button onclick="copyCode(this)" class="copybtn">copy</button></pre></details>

  <script>
    function copyCode(btn) {
      const code = btn.previousElementSibling.textContent.trim();
      navigator.clipboard.writeText(code).then(() => {
        btn.innerText = "copied";
        setTimeout(() => (btn.innerText = "copy"), 2000);
      });
    }
  </script><p>Replace replace a string only on the 5th line</p>
<details open>
    <summary>TEXT</summary><pre
        class="codeblock"
      ><code class="language-" data-lang="">$ sed &#39;5 s/old/new/&#39; file.txt</code><button onclick="copyCode(this)" class="copybtn">copy</button></pre></details>

  <script>
    function copyCode(btn) {
      const code = btn.previousElementSibling.textContent.trim();
      navigator.clipboard.writeText(code).then(() => {
        btn.innerText = "copied";
        setTimeout(() => (btn.innerText = "copy"), 2000);
      });
    }
  </script><p>Replace &ldquo;world&rdquo; with &ldquo;universe&rdquo; but only if the line begins with &ldquo;hello&rdquo;</p>
<details open>
    <summary>TEXT</summary><pre
        class="codeblock"
      ><code class="language-" data-lang="">$ sed &#39;/hello/s/world/universe/&#39; file.txt</code><button onclick="copyCode(this)" class="copybtn">copy</button></pre></details>

  <script>
    function copyCode(btn) {
      const code = btn.previousElementSibling.textContent.trim();
      navigator.clipboard.writeText(code).then(() => {
        btn.innerText = "copied";
        setTimeout(() => (btn.innerText = "copy"), 2000);
      });
    }
  </script><p>Remove &quot;&rdquo; from the end of each line</p>
<details open>
    <summary>TEXT</summary><pre
        class="codeblock"
      ><code class="language-" data-lang="">$ sed &#39;s/\\$//&#39; file.txt</code><button onclick="copyCode(this)" class="copybtn">copy</button></pre></details>

  <script>
    function copyCode(btn) {
      const code = btn.previousElementSibling.textContent.trim();
      navigator.clipboard.writeText(code).then(() => {
        btn.innerText = "copied";
        setTimeout(() => (btn.innerText = "copy"), 2000);
      });
    }
  </script><p>Remove all whitespace from beginning of each line</p>
<details open>
    <summary>TEXT</summary><pre
        class="codeblock"
      ><code class="language-" data-lang="">$ sed &#39;s/^\s*//&#39; file.txt</code><button onclick="copyCode(this)" class="copybtn">copy</button></pre></details>

  <script>
    function copyCode(btn) {
      const code = btn.previousElementSibling.textContent.trim();
      navigator.clipboard.writeText(code).then(() => {
        btn.innerText = "copied";
        setTimeout(() => (btn.innerText = "copy"), 2000);
      });
    }
  </script><p>Remove comments. Even those that are at the end of a line</p>
<details open>
    <summary>TEXT</summary><pre
        class="codeblock"
      ><code class="language-" data-lang="">$ sed &#39;s/#.*$//&#39; file.txt</code><button onclick="copyCode(this)" class="copybtn">copy</button></pre></details>

  <script>
    function copyCode(btn) {
      const code = btn.previousElementSibling.textContent.trim();
      navigator.clipboard.writeText(code).then(() => {
        btn.innerText = "copied";
        setTimeout(() => (btn.innerText = "copy"), 2000);
      });
    }
  </script><h3 id="search-for-text-2">
  <a class="anchor inpage" href="#search-for-text-2">###</a>Search for text</h3>
<p>Search for a string and only print the lines that were matched</p>
<details open>
    <summary>TEXT</summary><pre
        class="codeblock"
      ><code class="language-" data-lang="">$ sed -n &#39;/hello/p&#39; file.txt</code><button onclick="copyCode(this)" class="copybtn">copy</button></pre></details>

  <script>
    function copyCode(btn) {
      const code = btn.previousElementSibling.textContent.trim();
      navigator.clipboard.writeText(code).then(() => {
        btn.innerText = "copied";
        setTimeout(() => (btn.innerText = "copy"), 2000);
      });
    }
  </script><p>Case insensitive search</p>
<details open>
    <summary>TEXT</summary><pre
        class="codeblock"
      ><code class="language-" data-lang="">$ sed -n &#39;/hello/Ip&#39; file.txt</code><button onclick="copyCode(this)" class="copybtn">copy</button></pre></details>

  <script>
    function copyCode(btn) {
      const code = btn.previousElementSibling.textContent.trim();
      navigator.clipboard.writeText(code).then(() => {
        btn.innerText = "copied";
        setTimeout(() => (btn.innerText = "copy"), 2000);
      });
    }
  </script><p>Search for a string but only output lines that do not match</p>
<details open>
    <summary>TEXT</summary><pre
        class="codeblock"
      ><code class="language-" data-lang="">$ sed -n &#39;/hello/!p&#39; file.txt</code><button onclick="copyCode(this)" class="copybtn">copy</button></pre></details>

  <script>
    function copyCode(btn) {
      const code = btn.previousElementSibling.textContent.trim();
      navigator.clipboard.writeText(code).then(() => {
        btn.innerText = "copied";
        setTimeout(() => (btn.innerText = "copy"), 2000);
      });
    }
  </script><h3 id="appending-lines-1">
  <a class="anchor inpage" href="#appending-lines-1">###</a>Appending lines</h3>
<p>Append line after line 2</p>
<details open>
    <summary>TEXT</summary><pre
        class="codeblock"
      ><code class="language-" data-lang="">$ sed &#39;2a Text after line 2&#39; file.txt</code><button onclick="copyCode(this)" class="copybtn">copy</button></pre></details>

  <script>
    function copyCode(btn) {
      const code = btn.previousElementSibling.textContent.trim();
      navigator.clipboard.writeText(code).then(() => {
        btn.innerText = "copied";
        setTimeout(() => (btn.innerText = "copy"), 2000);
      });
    }
  </script><p>Append line at the end of the file</p>
<details open>
    <summary>TEXT</summary><pre
        class="codeblock"
      ><code class="language-" data-lang="">$ sed &#39;$a THE END!&#39; file.txt</code><button onclick="copyCode(this)" class="copybtn">copy</button></pre></details>

  <script>
    function copyCode(btn) {
      const code = btn.previousElementSibling.textContent.trim();
      navigator.clipboard.writeText(code).then(() => {
        btn.innerText = "copied";
        setTimeout(() => (btn.innerText = "copy"), 2000);
      });
    }
  </script><p>Append line after every 3rd line starting from line 3</p>
<details open>
    <summary>TEXT</summary><pre
        class="codeblock"
      ><code class="language-" data-lang="">$ sed &#39;3~3a Some text&#39; file.txt</code><button onclick="copyCode(this)" class="copybtn">copy</button></pre></details>

  <script>
    function copyCode(btn) {
      const code = btn.previousElementSibling.textContent.trim();
      navigator.clipboard.writeText(code).then(() => {
        btn.innerText = "copied";
        setTimeout(() => (btn.innerText = "copy"), 2000);
      });
    }
  </script><h3 id="numbering-1">
  <a class="anchor inpage" href="#numbering-1">###</a>Numbering</h3>
<p>Number line of a file (simple left alignment)</p>
<details open>
    <summary>TEXT</summary><pre
        class="codeblock"
      ><code class="language-" data-lang="">$ sed = file.txt | sed &#39;N;s/\n/\t/&#39;</code><button onclick="copyCode(this)" class="copybtn">copy</button></pre></details>

  <script>
    function copyCode(btn) {
      const code = btn.previousElementSibling.textContent.trim();
      navigator.clipboard.writeText(code).then(() => {
        btn.innerText = "copied";
        setTimeout(() => (btn.innerText = "copy"), 2000);
      });
    }
  </script><p>Number line of a file (number on left, right-aligned)</p>
<details open>
    <summary>TEXT</summary><pre
        class="codeblock"
      ><code class="language-" data-lang="">$ sed = file.txt | sed &#39;N; s/^/   /; s/ *\(.\{6,\}\)\n/\1  /&#39;</code><button onclick="copyCode(this)" class="copybtn">copy</button></pre></details>

  <script>
    function copyCode(btn) {
      const code = btn.previousElementSibling.textContent.trim();
      navigator.clipboard.writeText(code).then(() => {
        btn.innerText = "copied";
        setTimeout(() => (btn.innerText = "copy"), 2000);
      });
    }
  </script><p>Number line of file, but only print numbers if line is not blank</p>
<details open>
    <summary>TEXT</summary><pre
        class="codeblock"
      ><code class="language-" data-lang="">$ sed &#39;/./=&#39; file.txt | sed &#39;/./N; s/\n/ /&#39;</code><button onclick="copyCode(this)" class="copybtn">copy</button></pre></details>

  <script>
    function copyCode(btn) {
      const code = btn.previousElementSibling.textContent.trim();
      navigator.clipboard.writeText(code).then(() => {
        btn.innerText = "copied";
        setTimeout(() => (btn.innerText = "copy"), 2000);
      });
    }
  </script><p>Count lines (emulates &ldquo;wc -l&rdquo;)</p>
<details open>
    <summary>TEXT</summary><pre
        class="codeblock"
      ><code class="language-" data-lang="">$ sed -n &#39;$=&#39;</code><button onclick="copyCode(this)" class="copybtn">copy</button></pre></details>

  <script>
    function copyCode(btn) {
      const code = btn.previousElementSibling.textContent.trim();
      navigator.clipboard.writeText(code).then(() => {
        btn.innerText = "copied";
        setTimeout(() => (btn.innerText = "copy"), 2000);
      });
    }
  </script><h3 id="prepending-lines-1">
  <a class="anchor inpage" href="#prepending-lines-1">###</a>Prepending lines</h3>
<p>Insert text before line 5</p>
<details open>
    <summary>TEXT</summary><pre
        class="codeblock"
      ><code class="language-" data-lang="">$ sed &#39;5i line number five&#39; file.txt</code><button onclick="copyCode(this)" class="copybtn">copy</button></pre></details>

  <script>
    function copyCode(btn) {
      const code = btn.previousElementSibling.textContent.trim();
      navigator.clipboard.writeText(code).then(() => {
        btn.innerText = "copied";
        setTimeout(() => (btn.innerText = "copy"), 2000);
      });
    }
  </script><p>Insert &ldquo;Example:&rdquo; before each line that contains &ldquo;hello&rdquo;</p>
<details open>
    <summary>TEXT</summary><pre
        class="codeblock"
      ><code class="language-" data-lang="">$ sed &#39;/hello/i Example: &#39; file.txt</code><button onclick="copyCode(this)" class="copybtn">copy</button></pre></details>

  <script>
    function copyCode(btn) {
      const code = btn.previousElementSibling.textContent.trim();
      navigator.clipboard.writeText(code).then(() => {
        btn.innerText = "copied";
        setTimeout(() => (btn.innerText = "copy"), 2000);
      });
    }
  </script><h3 id="deleting-lines-1">
  <a class="anchor inpage" href="#deleting-lines-1">###</a>Deleting lines</h3>
<p>Delete line 5-7 in file</p>
<details open>
    <summary>TEXT</summary><pre
        class="codeblock"
      ><code class="language-" data-lang="">$ sed &#39;5,7d&#39; file.txt</code><button onclick="copyCode(this)" class="copybtn">copy</button></pre></details>

  <script>
    function copyCode(btn) {
      const code = btn.previousElementSibling.textContent.trim();
      navigator.clipboard.writeText(code).then(() => {
        btn.innerText = "copied";
        setTimeout(() => (btn.innerText = "copy"), 2000);
      });
    }
  </script><p>Delete every 2nd line starting with line 3</p>
<details open>
    <summary>TEXT</summary><pre
        class="codeblock"
      ><code class="language-" data-lang="">$ sed &#39;3~2d&#39; file.txt</code><button onclick="copyCode(this)" class="copybtn">copy</button></pre></details>

  <script>
    function copyCode(btn) {
      const code = btn.previousElementSibling.textContent.trim();
      navigator.clipboard.writeText(code).then(() => {
        btn.innerText = "copied";
        setTimeout(() => (btn.innerText = "copy"), 2000);
      });
    }
  </script><p>Delete the last line in file</p>
<details open>
    <summary>TEXT</summary><pre
        class="codeblock"
      ><code class="language-" data-lang="">$ sed &#39;$d&#39; file.txt</code><button onclick="copyCode(this)" class="copybtn">copy</button></pre></details>

  <script>
    function copyCode(btn) {
      const code = btn.previousElementSibling.textContent.trim();
      navigator.clipboard.writeText(code).then(() => {
        btn.innerText = "copied";
        setTimeout(() => (btn.innerText = "copy"), 2000);
      });
    }
  </script><p>Delete lines starting with &ldquo;Hello&rdquo;</p>
<details open>
    <summary>TEXT</summary><pre
        class="codeblock"
      ><code class="language-" data-lang="">$ sed &#39;/^Hello/d&#39; file.txt</code><button onclick="copyCode(this)" class="copybtn">copy</button></pre></details>

  <script>
    function copyCode(btn) {
      const code = btn.previousElementSibling.textContent.trim();
      navigator.clipboard.writeText(code).then(() => {
        btn.innerText = "copied";
        setTimeout(() => (btn.innerText = "copy"), 2000);
      });
    }
  </script><p>Delete all empty lines</p>
<details open>
    <summary>TEXT</summary><pre
        class="codeblock"
      ><code class="language-" data-lang="">$ sed &#39;/^$/d&#39; file.txt</code><button onclick="copyCode(this)" class="copybtn">copy</button></pre></details>

  <script>
    function copyCode(btn) {
      const code = btn.previousElementSibling.textContent.trim();
      navigator.clipboard.writeText(code).then(() => {
        btn.innerText = "copied";
        setTimeout(() => (btn.innerText = "copy"), 2000);
      });
    }
  </script><p>Delete lines starting with &ldquo;#&rdquo;</p>
<details open>
    <summary>TEXT</summary><pre
        class="codeblock"
      ><code class="language-" data-lang="">$ sed &#39;/^#/d&#39; file.txt</code><button onclick="copyCode(this)" class="copybtn">copy</button></pre></details>

  <script>
    function copyCode(btn) {
      const code = btn.previousElementSibling.textContent.trim();
      navigator.clipboard.writeText(code).then(() => {
        btn.innerText = "copied";
        setTimeout(() => (btn.innerText = "copy"), 2000);
      });
    }
  </script><h3 id="file-spacing-1">
  <a class="anchor inpage" href="#file-spacing-1">###</a>File spacing</h3>
<p>Double space</p>
<details open>
    <summary>TEXT</summary><pre
        class="codeblock"
      ><code class="language-" data-lang="">$ sed G</code><button onclick="copyCode(this)" class="copybtn">copy</button></pre></details>

  <script>
    function copyCode(btn) {
      const code = btn.previousElementSibling.textContent.trim();
      navigator.clipboard.writeText(code).then(() => {
        btn.innerText = "copied";
        setTimeout(() => (btn.innerText = "copy"), 2000);
      });
    }
  </script><p>Delete all blank lines and double space</p>
<details open>
    <summary>TEXT</summary><pre
        class="codeblock"
      ><code class="language-" data-lang="">$ sed &#39;/^$/d;G&#39;</code><button onclick="copyCode(this)" class="copybtn">copy</button></pre></details>

  <script>
    function copyCode(btn) {
      const code = btn.previousElementSibling.textContent.trim();
      navigator.clipboard.writeText(code).then(() => {
        btn.innerText = "copied";
        setTimeout(() => (btn.innerText = "copy"), 2000);
      });
    }
  </script><p>Triple space a file</p>
<details open>
    <summary>TEXT</summary><pre
        class="codeblock"
      ><code class="language-" data-lang="">$ sed &#39;G;G&#39;</code><button onclick="copyCode(this)" class="copybtn">copy</button></pre></details>

  <script>
    function copyCode(btn) {
      const code = btn.previousElementSibling.textContent.trim();
      navigator.clipboard.writeText(code).then(() => {
        btn.innerText = "copied";
        setTimeout(() => (btn.innerText = "copy"), 2000);
      });
    }
  </script><p>Undo double-spacing</p>
<details open>
    <summary>TEXT</summary><pre
        class="codeblock"
      ><code class="language-" data-lang="">$ sed &#39;n;d&#39;</code><button onclick="copyCode(this)" class="copybtn">copy</button></pre></details>

  <script>
    function copyCode(btn) {
      const code = btn.previousElementSibling.textContent.trim();
      navigator.clipboard.writeText(code).then(() => {
        btn.innerText = "copied";
        setTimeout(() => (btn.innerText = "copy"), 2000);
      });
    }
  </script><p>Insert a blank line above line which matches &ldquo;regex&rdquo;</p>
<details open>
    <summary>TEXT</summary><pre
        class="codeblock"
      ><code class="language-" data-lang="">$ sed &#39;/regex/{x;p;x;}&#39;</code><button onclick="copyCode(this)" class="copybtn">copy</button></pre></details>

  <script>
    function copyCode(btn) {
      const code = btn.previousElementSibling.textContent.trim();
      navigator.clipboard.writeText(code).then(() => {
        btn.innerText = "copied";
        setTimeout(() => (btn.innerText = "copy"), 2000);
      });
    }
  </script><p>Insert a blank line below line which matches &ldquo;regex&rdquo;</p>
<details open>
    <summary>TEXT</summary><pre
        class="codeblock"
      ><code class="language-" data-lang="">$ sed &#39;/regex/G&#39;</code><button onclick="copyCode(this)" class="copybtn">copy</button></pre></details>

  <script>
    function copyCode(btn) {
      const code = btn.previousElementSibling.textContent.trim();
      navigator.clipboard.writeText(code).then(() => {
        btn.innerText = "copied";
        setTimeout(() => (btn.innerText = "copy"), 2000);
      });
    }
  </script><p>Insert a blank line around line which matches &ldquo;regex&rdquo;</p>
<details open>
    <summary>TEXT</summary><pre
        class="codeblock"
      ><code class="language-" data-lang="">$ sed &#39;/regex/{x;p;x;G;}&#39;</code><button onclick="copyCode(this)" class="copybtn">copy</button></pre></details>

  <script>
    function copyCode(btn) {
      const code = btn.previousElementSibling.textContent.trim();
      navigator.clipboard.writeText(code).then(() => {
        btn.innerText = "copied";
        setTimeout(() => (btn.innerText = "copy"), 2000);
      });
    }
  </script>]]></content:encoded></item><item><title>网页端下载网易云音乐的音乐</title><link>https://hiraethecho.github.io/docs/dev/netease/</link><pubDate>Tue, 29 Apr 2025 00:00:00 +0000</pubDate><author>wyz2016zxc@outlook.com(Hiraeth)</author><guid>https://hiraethecho.github.io/docs/dev/netease/</guid><description>通过浏览器的审查元素功能下载网易云音乐的音乐</description><content:encoded><![CDATA[<h1 id="从网页端下载音乐">
  <a class="anchor inpage" href="#%e4%bb%8e%e7%bd%91%e9%a1%b5%e7%ab%af%e4%b8%8b%e8%bd%bd%e9%9f%b3%e4%b9%90">#</a>从网页端下载音乐</h1>
<p>打开网易云音乐，然后打开<code>页面审查元素</code></p>
<ul>
<li>firefox系一般在<code>setting</code>-<code>more tools</code>-<code>webdeveloper tools</code>， 快捷键是<kbd>ctrl</kbd>+<kbd>shift</kbd>+<kbd>I</kbd></li>
<li>chrome系忘记了， 快捷键似乎是<kbd>F11</kbd>或<kbd>F12</kbd></li>
</ul>
<p>在新页面里选择<code>Network</code>，可以在<code>Filter</code>里写m4a。然后点击播放，会有新的请求。右键网址后用<code>open in new tab</code>，就可以在新页面打开音频。再右键保存音频即可。</p>
<blockquote class="alert alert-note">
      <p class="alert-heading">NOTE</p><p><del>或者直接<code>Save reponse as</code>来下载。</del> 这样只下载<code>1024k</code>的文件，不是整个。</p></blockquote><p>理论上是网页能播放就能下载。</p>
]]></content:encoded></item><item><title>ssh的使用</title><link>https://hiraethecho.github.io/docs/dev/ssh/</link><pubDate>Sun, 13 Apr 2025 00:00:00 +0000</pubDate><author>wyz2016zxc@outlook.com(Hiraeth)</author><guid>https://hiraethecho.github.io/docs/dev/ssh/</guid><description>ssh的简单使用</description><content:encoded><![CDATA[<h1 id="ssh">
  <a class="anchor inpage" href="#ssh">#</a>ssh</h1>
<h2 id="内网ssh连接">
  <a class="anchor inpage" href="#%e5%86%85%e7%bd%91ssh%e8%bf%9e%e6%8e%a5">##</a>内网ssh连接</h2>
<p>一个ipv6地址的电脑，作为中间机，一个内网的电脑，记作服务机，期望其他的客户机（比如iphone）连接到内网的服务机。</p>
<h3 id="思路">
  <a class="anchor inpage" href="#%e6%80%9d%e8%b7%af">###</a>思路</h3>
<p>将服务机的ssh端口转发到中间机的端口，即数据从中间机的端口传送到服务机；客户机连接中间机的端口即可。中间机有ipv6地址，就可以ssh直连。</p>
<h3 id="操作">
  <a class="anchor inpage" href="#%e6%93%8d%e4%bd%9c">###</a>操作</h3>
<p>在服务机上</p>
<details open>
    <summary>shell</summary><pre
        class="chroma codeblock"
      ><code class="language-shell" data-lang="shell"
          ><span style="display:flex;"><span>ssh -R 1234:localhost:22 midle_username@ipv6</span></span></code
        ><button onclick="copyCode(this)" class="copybtn">copy</button></pre></details>

  <script>
    function copyCode(btn) {
      const code = btn.previousElementSibling.textContent.trim();
      navigator.clipboard.writeText(code).then(() => {
        btn.innerText = "copied";
        setTimeout(() => (btn.innerText = "copy"), 2000);
      });
    }
  </script><p>将服务机的22端口和中间机的1234端口连接。</p>
<p>在客户机上用</p>
<details open>
    <summary>shell</summary><pre
        class="chroma codeblock"
      ><code class="language-shell" data-lang="shell"
          ><span style="display:flex;"><span>ssh -p <span style="color:#ae81ff">1234</span> server_user@ipv6</span></span></code
        ><button onclick="copyCode(this)" class="copybtn">copy</button></pre></details>

  <script>
    function copyCode(btn) {
      const code = btn.previousElementSibling.textContent.trim();
      navigator.clipboard.writeText(code).then(() => {
        btn.innerText = "copied";
        setTimeout(() => (btn.innerText = "copy"), 2000);
      });
    }
  </script><p>连接，那么数据就从客户机到中间机的1234端口，再转发到服务机的22端口</p>
<p>ssh 有一些选项：</p>
<ul>
<li>-f: Fork into background 让 SSH 在认证成功后进入后台运行，不占用当前终端。</li>
<li>-N: No remote command 不执行远程命令，仅用于端口转发。</li>
<li>-T: Disable pseudo-terminal allocation 不分配伪终端（PTY），适用于纯端口转发。</li>
<li>-R: Remote port forwarding 建立反向隧道（远程端口转发）。</li>
</ul>
<h3 id="注意">
  <a class="anchor inpage" href="#%e6%b3%a8%e6%84%8f">###</a>注意</h3>
<p>中间机上在<code>/etc/ssh/sshd_config</code>（作为服务端的配置）设置</p>
<details open>
    <summary>conf</summary><pre
        class="codeblock"
      ><code class="language-conf" data-lang="conf">AllowTcpForwarding yes
GatewayPorts yes</code><button onclick="copyCode(this)" class="copybtn">copy</button></pre></details>

  <script>
    function copyCode(btn) {
      const code = btn.previousElementSibling.textContent.trim();
      navigator.clipboard.writeText(code).then(() => {
        btn.innerText = "copied";
        setTimeout(() => (btn.innerText = "copy"), 2000);
      });
    }
  </script><p>在服务机 <code>/etc/ssh/sshd_config</code>（作为服务端的配置）设置监听端口，默认为22</p>
<p>根据系统设置防火墙</p>
<h2 id="x-through-ssh">
  <a class="anchor inpage" href="#x-through-ssh">##</a>X through ssh</h2>
<p>to share X11 through ssh, need <code>Xorg</code> on server and client.<br>
on client using</p>
<details open>
    <summary>shell</summary><pre
        class="chroma codeblock"
      ><code class="language-shell" data-lang="shell"
          ><span style="display:flex;"><span>ssh -X -C remote_user@remote_host</span></span></code
        ><button onclick="copyCode(this)" class="copybtn">copy</button></pre></details>

  <script>
    function copyCode(btn) {
      const code = btn.previousElementSibling.textContent.trim();
      navigator.clipboard.writeText(code).then(() => {
        btn.innerText = "copied";
        setTimeout(() => (btn.innerText = "copy"), 2000);
      });
    }
  </script><p>where <code>X</code> for X forwarding, and <code>-C</code> for compression. In this ssh session, GUI
like <code>gvim</code> should show on client.</p>
<h3 id="systemd-自动启动">
  <a class="anchor inpage" href="#systemd-%e8%87%aa%e5%8a%a8%e5%90%af%e5%8a%a8">###</a>systemd 自动启动</h3>
<p>create <code>/etc/systemd/system/ssh-tunnel.service</code></p>
<details open>
    <summary>TEXT</summary><pre
        class="codeblock"
      ><code class="language-" data-lang="">[Unit]
Description=Autossh Persistent Reverse SSH Tunnel
After=network.target

[Service]
User=username
ExecStart=/usr/bin/autossh -M 20000 -NR 1234:localhost:22 midle_username@ipv6
Restart=always
RestartSec=10
KillMode=process
Environment=&#34;AUTOSSH_GATETIME=0&#34;
Environment=&#34;AUTOSSH_POLL=30&#34;

[Install]
WantedBy=multi-user.target</code><button onclick="copyCode(this)" class="copybtn">copy</button></pre></details>

  <script>
    function copyCode(btn) {
      const code = btn.previousElementSibling.textContent.trim();
      navigator.clipboard.writeText(code).then(() => {
        btn.innerText = "copied";
        setTimeout(() => (btn.innerText = "copy"), 2000);
      });
    }
  </script><details open>
    <summary>sh</summary><pre
        class="chroma codeblock"
      ><code class="language-sh" data-lang="sh"
          ><span style="display:flex;"><span>sudo systemctl daemon-reload
</span></span><span style="display:flex;"><span>sudo systemctl enable --now ssh-tunnel</span></span></code
        ><button onclick="copyCode(this)" class="copybtn">copy</button></pre></details>

  <script>
    function copyCode(btn) {
      const code = btn.previousElementSibling.textContent.trim();
      navigator.clipboard.writeText(code).then(() => {
        btn.innerText = "copied";
        setTimeout(() => (btn.innerText = "copy"), 2000);
      });
    }
  </script><h2 id="debug">
  <a class="anchor inpage" href="#debug">##</a>debug</h2>
<p>在debian上，防火墙</p>
<details open>
    <summary>sh</summary><pre
        class="chroma codeblock"
      ><code class="language-sh" data-lang="sh"
          ><span style="display:flex;"><span>sudo ufw allow 22/tcp 1234/tcp
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span>sudo ufw status
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span>1234/tcp                   ALLOW       Anywhere
</span></span><span style="display:flex;"><span>22/tcp                     ALLOW       Anywhere
</span></span><span style="display:flex;"><span>1234/tcp <span style="color:#f92672">(</span>v6<span style="color:#f92672">)</span>              ALLOW       Anywhere <span style="color:#f92672">(</span>v6<span style="color:#f92672">)</span>
</span></span><span style="display:flex;"><span>22/tcp <span style="color:#f92672">(</span>v6<span style="color:#f92672">)</span>                ALLOW       Anywhere <span style="color:#f92672">(</span>v6<span style="color:#f92672">)</span></span></span></code
        ><button onclick="copyCode(this)" class="copybtn">copy</button></pre></details>

  <script>
    function copyCode(btn) {
      const code = btn.previousElementSibling.textContent.trim();
      navigator.clipboard.writeText(code).then(() => {
        btn.innerText = "copied";
        setTimeout(() => (btn.innerText = "copy"), 2000);
      });
    }
  </script><p>在<code>/etc/ssh/sshd_config</code>中</p>
<details open>
    <summary>config</summary><pre
        class="codeblock"
      ><code class="language-config" data-lang="config">Port 22
# Port 2222 # custom port
AddressFamily any
#ListenAddress 0.0.0.0
#ListenAddress ::
PubkeyAuthentication yes
AuthorizedKeysFile  .ssh/authorized_keys

# To disable tunneled clear text passwords, change to no here!
PasswordAuthentication no
#AllowAgentForwarding yes
AllowTcpForwarding yes
GatewayPorts yes
X11Forwarding yes
X11DisplayOffset 10
X11UseLocalhost no</code><button onclick="copyCode(this)" class="copybtn">copy</button></pre></details>

  <script>
    function copyCode(btn) {
      const code = btn.previousElementSibling.textContent.trim();
      navigator.clipboard.writeText(code).then(() => {
        btn.innerText = "copied";
        setTimeout(() => (btn.innerText = "copy"), 2000);
      });
    }
  </script><p>检查网络，包含这样的</p>
<details open>
    <summary>sh</summary><pre
        class="chroma codeblock"
      ><code class="language-sh" data-lang="sh"
          ><span style="display:flex;"><span>ss -tnlp
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span>State  Recv-Q Send-Q Local Address:Port  Peer Address:PortProcess
</span></span><span style="display:flex;"><span>LISTEN <span style="color:#ae81ff">0</span>      <span style="color:#ae81ff">128</span>          0.0.0.0:22         0.0.0.0:*
</span></span><span style="display:flex;"><span>LISTEN <span style="color:#ae81ff">0</span>      <span style="color:#ae81ff">1</span>          127.0.0.1:20001      0.0.0.0:*    users:<span style="color:#f92672">((</span><span style="color:#e6db74">&#34;autossh&#34;</span>,pid<span style="color:#f92672">=</span>15104,fd<span style="color:#f92672">=</span>3<span style="color:#f92672">))</span>
</span></span><span style="display:flex;"><span>LISTEN <span style="color:#ae81ff">0</span>      <span style="color:#ae81ff">128</span>        127.0.0.1:20000      0.0.0.0:*    users:<span style="color:#f92672">((</span><span style="color:#e6db74">&#34;ssh&#34;</span>,pid<span style="color:#f92672">=</span>21175,fd<span style="color:#f92672">=</span>5<span style="color:#f92672">))</span>
</span></span><span style="display:flex;"><span>LISTEN <span style="color:#ae81ff">0</span>      <span style="color:#ae81ff">128</span>             <span style="color:#f92672">[</span>::<span style="color:#f92672">]</span>:22            <span style="color:#f92672">[</span>::<span style="color:#f92672">]</span>:*
</span></span><span style="display:flex;"><span>LISTEN <span style="color:#ae81ff">0</span>      <span style="color:#ae81ff">128</span>            <span style="color:#f92672">[</span>::1<span style="color:#f92672">]</span>:20000         <span style="color:#f92672">[</span>::<span style="color:#f92672">]</span>:*    users:<span style="color:#f92672">((</span><span style="color:#e6db74">&#34;ssh&#34;</span>,pid<span style="color:#f92672">=</span>21175,fd<span style="color:#f92672">=</span>4<span style="color:#f92672">))</span></span></span></code
        ><button onclick="copyCode(this)" class="copybtn">copy</button></pre></details>

  <script>
    function copyCode(btn) {
      const code = btn.previousElementSibling.textContent.trim();
      navigator.clipboard.writeText(code).then(() => {
        btn.innerText = "copied";
        setTimeout(() => (btn.innerText = "copy"), 2000);
      });
    }
  </script><p>检查端口占用：</p>
<details open>
    <summary>TEXT</summary><pre
        class="codeblock"
      ><code class="language-" data-lang="">lsof -i :22
lsof -i :1234</code><button onclick="copyCode(this)" class="copybtn">copy</button></pre></details>

  <script>
    function copyCode(btn) {
      const code = btn.previousElementSibling.textContent.trim();
      navigator.clipboard.writeText(code).then(() => {
        btn.innerText = "copied";
        setTimeout(() => (btn.innerText = "copy"), 2000);
      });
    }
  </script><p>修改配置后记得重启各种服务，例如</p>
<details open>
    <summary>sh</summary><pre
        class="chroma codeblock"
      ><code class="language-sh" data-lang="sh"
          ><span style="display:flex;"><span>sudo systemctl restart sshd
</span></span><span style="display:flex;"><span>sudo systemctl daemon-reload
</span></span><span style="display:flex;"><span>sudo systemctl enable --now ssh-tunnel
</span></span><span style="display:flex;"><span>sudo systemctl restart ssh-tunnel
</span></span><span style="display:flex;"><span>sudo ufw reload</span></span></code
        ><button onclick="copyCode(this)" class="copybtn">copy</button></pre></details>

  <script>
    function copyCode(btn) {
      const code = btn.previousElementSibling.textContent.trim();
      navigator.clipboard.writeText(code).then(() => {
        btn.innerText = "copied";
        setTimeout(() => (btn.innerText = "copy"), 2000);
      });
    }
  </script>]]></content:encoded></item><item><title>用obsidian管理多个博客</title><link>https://hiraethecho.github.io/docs/dev/blogs/</link><pubDate>Sat, 05 Apr 2025 00:00:00 +0000</pubDate><author>wyz2016zxc@outlook.com(Hiraeth)</author><guid>https://hiraethecho.github.io/docs/dev/blogs/</guid><description>之前在一个obsidian仓库管理hexo hugo mkdocs三个网站的方法</description><content:encoded><![CDATA[<h1 id="用obsidian管理多个博客">
  <a class="anchor inpage" href="#%e7%94%a8obsidian%e7%ae%a1%e7%90%86%e5%a4%9a%e4%b8%aa%e5%8d%9a%e5%ae%a2">#</a>用obsidian管理多个博客</h1>
<p>一些花里胡哨的技巧。</p>
<h2 id="目标">
  <a class="anchor inpage" href="#%e7%9b%ae%e6%a0%87">##</a>目标</h2>
<p>多个博客网站，都用github pages功能发布。多个博客的post文件放在一个obsidian仓库中管理，并且本身作为一个github repository。push 这个obsidian/github仓库后将博客内容同步到其他博客repo。各个repo自己发布。</p>
<h2 id="思路">
  <a class="anchor inpage" href="#%e6%80%9d%e8%b7%af">##</a>思路</h2>
<p>用github action，push之后检测变化的文件，clone对应仓库，同步文件，再分别push。</p>
<p>需要注意的是，GitHub action对各个repo的读写权限，需要配置各种keys。<br>
先生成ssh keys，将pub放入博客repo的deploy key，记得打开写权限；private key放入obsidian repo的secrets中。<br>
每个博客仓库都需要一个密钥对。</p>
<h2 id="示例">
  <a class="anchor inpage" href="#%e7%a4%ba%e4%be%8b">##</a>示例</h2>
<p>例如将<code>obsidian/hexo</code>的内容同步到<code>hexo</code>框架下对应的<code>hexo/source/_posts</code>文件夹下，<code>/.github/workflows/sync_hexo</code>中</p>
<details open>
    <summary>yml</summary><pre
        class="chroma codeblock"
      ><code class="language-yml" data-lang="yml"
          ><span style="display:flex;"><span><span style="color:#f92672">name</span>: <span style="color:#ae81ff">Sync ob/hexo to hexo/source_posts</span>
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span><span style="color:#f92672">on</span>:
</span></span><span style="display:flex;"><span>    <span style="color:#f92672">push</span>:
</span></span><span style="display:flex;"><span>        <span style="color:#f92672">paths</span>:
</span></span><span style="display:flex;"><span>            - <span style="color:#e6db74">&#34;hexo/**&#34;</span> <span style="color:#75715e"># 监听文件夹内的文件变化，没有变化不会触发action</span>
</span></span><span style="display:flex;"><span><span style="color:#f92672">jobs</span>:
</span></span><span style="display:flex;"><span>    <span style="color:#f92672">sync</span>:
</span></span><span style="display:flex;"><span>        <span style="color:#f92672">runs-on</span>: <span style="color:#ae81ff">ubuntu-latest</span>
</span></span><span style="display:flex;"><span>        <span style="color:#f92672">steps</span>:
</span></span><span style="display:flex;"><span>            <span style="color:#75715e"># 检出 obsidian 仓库的代码</span>
</span></span><span style="display:flex;"><span>            - <span style="color:#f92672">name</span>: <span style="color:#ae81ff">Checkout blogs repository</span>
</span></span><span style="display:flex;"><span>              <span style="color:#f92672">uses</span>: <span style="color:#ae81ff">actions/checkout@v3</span>
</span></span><span style="display:flex;"><span>              <span style="color:#f92672">with</span>:
</span></span><span style="display:flex;"><span>                  <span style="color:#f92672">repository</span>: <span style="color:#ae81ff">username/obsidian_repo</span>
</span></span><span style="display:flex;"><span>                  <span style="color:#f92672">path</span>: <span style="color:#ae81ff">obsidian</span>
</span></span><span style="display:flex;"><span>            - <span style="color:#f92672">name</span>: <span style="color:#ae81ff">commit</span>
</span></span><span style="display:flex;"><span>              <span style="color:#f92672">run</span>: |<span style="color:#e6db74">
</span></span></span><span style="display:flex;"><span><span style="color:#e6db74">                  cd obsidian
</span></span></span><span style="display:flex;"><span><span style="color:#e6db74">                  git log -1 --pretty=%B &gt; ~/commit</span>
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span>            <span style="color:#75715e"># 设置 Git 配置（用户名和ssh私钥）</span>
</span></span><span style="display:flex;"><span>            - <span style="color:#f92672">name</span>: <span style="color:#ae81ff">Set up Git</span>
</span></span><span style="display:flex;"><span>              <span style="color:#f92672">env</span>:
</span></span><span style="display:flex;"><span>                  <span style="color:#f92672">ACTIONS_KEY</span>: <span style="color:#ae81ff">${{ secrets.OB_PRI }}</span>
</span></span><span style="display:flex;"><span>              <span style="color:#f92672">run</span>: |<span style="color:#e6db74">
</span></span></span><span style="display:flex;"><span><span style="color:#e6db74">                  mkdir -p ~/.ssh/
</span></span></span><span style="display:flex;"><span><span style="color:#e6db74">                  echo &#34;$ACTIONS_KEY&#34; &gt; ~/.ssh/id_rsa
</span></span></span><span style="display:flex;"><span><span style="color:#e6db74">                  chmod 700 ~/.ssh
</span></span></span><span style="display:flex;"><span><span style="color:#e6db74">                  chmod 600 ~/.ssh/id_rsa
</span></span></span><span style="display:flex;"><span><span style="color:#e6db74">                  ssh-keyscan github.com &gt;&gt; ~/.ssh/known_hosts
</span></span></span><span style="display:flex;"><span><span style="color:#e6db74">                  git config --global user.name &#34;action&#34;
</span></span></span><span style="display:flex;"><span><span style="color:#e6db74">                  git config --global user.email &#34;email&#34;
</span></span></span><span style="display:flex;"><span><span style="color:#e6db74">                  git config --global core.quotepath false
</span></span></span><span style="display:flex;"><span><span style="color:#e6db74">                  git config --global i18n.commitEncoding utf-8
</span></span></span><span style="display:flex;"><span><span style="color:#e6db74">                  git config --global i18n.logOutputEncoding utf-8</span>
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span>            - <span style="color:#f92672">name</span>: <span style="color:#ae81ff">clone</span>
</span></span><span style="display:flex;"><span>              <span style="color:#f92672">run</span>: |<span style="color:#e6db74">
</span></span></span><span style="display:flex;"><span><span style="color:#e6db74">                  git clone git@github.com:username/hexo_repo ~/hexo</span>
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span>            - <span style="color:#f92672">name</span>: <span style="color:#ae81ff">Sync files from obsidian/hexo to hexo/source/_posts</span>
</span></span><span style="display:flex;"><span>              <span style="color:#f92672">run</span>: |<span style="color:#e6db74">
</span></span></span><span style="display:flex;"><span><span style="color:#e6db74">                  rsync -av obsidian/hexo/ ~/hexo/source/_posts/</span>
</span></span><span style="display:flex;"><span>            - <span style="color:#f92672">name</span>: <span style="color:#ae81ff">Commit and push changes to HexoBlog repository</span>
</span></span><span style="display:flex;"><span>              <span style="color:#f92672">run</span>: |<span style="color:#e6db74">
</span></span></span><span style="display:flex;"><span><span style="color:#e6db74">                  cd ~/hexo
</span></span></span><span style="display:flex;"><span><span style="color:#e6db74">                  git add .
</span></span></span><span style="display:flex;"><span><span style="color:#e6db74">                  git commit -m &#34;Sync obsidian to hexo $(cat ~/commit)&#34;
</span></span></span><span style="display:flex;"><span><span style="color:#e6db74">                  git push origin main</span></span></span></code
        ><button onclick="copyCode(this)" class="copybtn">copy</button></pre></details>

  <script>
    function copyCode(btn) {
      const code = btn.previousElementSibling.textContent.trim();
      navigator.clipboard.writeText(code).then(() => {
        btn.innerText = "copied";
        setTimeout(() => (btn.innerText = "copy"), 2000);
      });
    }
  </script><p>注意其中 <code>username</code> <code>hexo_repo</code> <code>obsidian_repo</code> <code>secrets.OB_PRI</code>等根据情况改写。</p>
]]></content:encoded></item><item><title>Windows重装指南</title><link>https://hiraethecho.github.io/docs/dev/rewindows/</link><pubDate>Sat, 18 Jan 2025 00:00:00 +0000</pubDate><author>wyz2016zxc@outlook.com(Hiraeth)</author><guid>https://hiraethecho.github.io/docs/dev/rewindows/</guid><description>重装和初始化windows</description><content:encoded><![CDATA[<h1 id="windows重装指南">
  <a class="anchor inpage" href="#windows%e9%87%8d%e8%a3%85%e6%8c%87%e5%8d%97">#</a>Windows重装指南</h1>
<p>记录一下重装或者第一次安装windows的一些注意事项。</p>
<h2 id="重装">
  <a class="anchor inpage" href="#%e9%87%8d%e8%a3%85">##</a>重装</h2>
<p>按<kbd>windows</kbd>然后按住<kbd>shift</kbd>点击重启，这样重启后会进入恢复模式（之类的），这里可以选择重装系统。或者在设置中的系统恢复部分。<br>
重装系统只重装C盘，其他盘是不动的。但是应用安装在其他盘的时候会有问题。</p>
<h2 id="安装">
  <a class="anchor inpage" href="#%e5%ae%89%e8%a3%85">##</a>安装</h2>
<p>window11有个莫名其妙的设定，不能在没有网络的时候安装，必须登陆微软账户，很神经，但是可以绕开。<br>
在安装界面按<kbd>Shift+F10</kbd>调出命令行，然后输入</p>
<details open>
    <summary>TEXT</summary><pre
        class="codeblock"
      ><code class="language-" data-lang="">oobe\bypassnro</code><button onclick="copyCode(this)" class="copybtn">copy</button></pre></details>

  <script>
    function copyCode(btn) {
      const code = btn.previousElementSibling.textContent.trim();
      navigator.clipboard.writeText(code).then(() => {
        btn.innerText = "copied";
        setTimeout(() => (btn.innerText = "copy"), 2000);
      });
    }
  </script><p>之后会重新启动安装程序，可以选择无网络连接。</p>
<h2 id="设置">
  <a class="anchor inpage" href="#%e8%ae%be%e7%bd%ae">##</a>设置</h2>
<h3 id="用户文件夹">
  <a class="anchor inpage" href="#%e7%94%a8%e6%88%b7%e6%96%87%e4%bb%b6%e5%a4%b9">###</a>用户文件夹</h3>
<p>在用户目录<code>C:\Users\_username_</code>下有一些用户目录，移动这些目录需要通过右键菜单的<code>属性</code></p>
<h3 id="设置-1">
  <a class="anchor inpage" href="#%e8%ae%be%e7%bd%ae-1">###</a>设置</h3>
<h3 id="其他">
  <a class="anchor inpage" href="#%e5%85%b6%e4%bb%96">###</a>其他</h3>
<p>电源管理</p>
<p>pagefiles</p>
<h2 id="软件源">
  <a class="anchor inpage" href="#%e8%bd%af%e4%bb%b6%e6%ba%90">##</a>软件源</h2>
<p>首先从microsoft store安装，其次用scoop，最后用msi安装。</p>
<h3 id="应用商店">
  <a class="anchor inpage" href="#%e5%ba%94%e7%94%a8%e5%95%86%e5%ba%97">###</a>应用商店</h3>
<h3 id="scoop">
  <a class="anchor inpage" href="#scoop">###</a>scoop</h3>
<p>权限：</p>
<details open>
    <summary>TEXT</summary><pre
        class="codeblock"
      ><code class="language-" data-lang="">Set-ExecutionPolicy -ExecutionPolicy RemoteSigned -Scope CurrentUser</code><button onclick="copyCode(this)" class="copybtn">copy</button></pre></details>

  <script>
    function copyCode(btn) {
      const code = btn.previousElementSibling.textContent.trim();
      navigator.clipboard.writeText(code).then(() => {
        btn.innerText = "copied";
        setTimeout(() => (btn.innerText = "copy"), 2000);
      });
    }
  </script><p>更改环境变量以修改<code>scoop</code>安装位置</p>
<details open>
    <summary>TEXT</summary><pre
        class="codeblock"
      ><code class="language-" data-lang="">$env:SCOOP=&#39;D:\Applications\Scoop&#39;
[Environment]::SetEnvironmentVariable(&#39;SCOOP&#39;, $env:SCOOP, &#39;User&#39;)</code><button onclick="copyCode(this)" class="copybtn">copy</button></pre></details>

  <script>
    function copyCode(btn) {
      const code = btn.previousElementSibling.textContent.trim();
      navigator.clipboard.writeText(code).then(() => {
        btn.innerText = "copied";
        setTimeout(() => (btn.innerText = "copy"), 2000);
      });
    }
  </script><p>安装<code>scoop </code></p>
<details open>
    <summary>TEXT</summary><pre
        class="codeblock"
      ><code class="language-" data-lang="">Invoke-Expression (New-Object System.Net.WebClient).DownloadString(&#39;https://get.scoop.sh&#39;)</code><button onclick="copyCode(this)" class="copybtn">copy</button></pre></details>

  <script>
    function copyCode(btn) {
      const code = btn.previousElementSibling.textContent.trim();
      navigator.clipboard.writeText(code).then(() => {
        btn.innerText = "copied";
        setTimeout(() => (btn.innerText = "copy"), 2000);
      });
    }
  </script><p>或者</p>
<details open>
    <summary>TEXT</summary><pre
        class="codeblock"
      ><code class="language-" data-lang="">iwr -useb get.scoop.sh | iex</code><button onclick="copyCode(this)" class="copybtn">copy</button></pre></details>

  <script>
    function copyCode(btn) {
      const code = btn.previousElementSibling.textContent.trim();
      navigator.clipboard.writeText(code).then(() => {
        btn.innerText = "copied";
        setTimeout(() => (btn.innerText = "copy"), 2000);
      });
    }
  </script><h2 id="软件">
  <a class="anchor inpage" href="#%e8%bd%af%e4%bb%b6">##</a>软件</h2>
<h2 id="清理">
  <a class="anchor inpage" href="#%e6%b8%85%e7%90%86">##</a>清理</h2>
<h3 id="win-sxs">
  <a class="anchor inpage" href="#win-sxs">###</a>win SxS</h3>
<h3 id="应用">
  <a class="anchor inpage" href="#%e5%ba%94%e7%94%a8">###</a>应用</h3>
<p>清理应用商店，卸载预装软件</p>
<details open>
    <summary>TEXT</summary><pre
        class="codeblock"
      ><code class="language-" data-lang="">Get-AppxPackage -All 　　　　　　　　　　　　　　　　　　　/* 获取Win10以上系统所有预装软件 */
Get-AppxPackage -All {预装软件全名} | Remove-AppxPackage　　/* 管道方式卸载Win10以上系统预装软件 */
Remove-AppxPackage {预装软件全名} 　　　　　　　　　　　　/* 常规卸载Win10以上系统预装软件 */
Get-AppxPackage -All | Select-Object Name, PackageFullName　　　/*（推荐）获取Win10以上系统所有预装软件 */
Remove-AppxPackage -Package &#34;PackageFullName&#34;　　　　　　/*（推荐）常规卸载Win10以上系统预装软件 */
Get-AppxPackage *BingWeather* | Remove-AppxPackage　　　　/*卸载单个软件
Get-AppXPackage | Remove-AppxPackage　　　　　　　　　　/*卸载所有软件命令</code><button onclick="copyCode(this)" class="copybtn">copy</button></pre></details>

  <script>
    function copyCode(btn) {
      const code = btn.previousElementSibling.textContent.trim();
      navigator.clipboard.writeText(code).then(() => {
        btn.innerText = "copied";
        setTimeout(() => (btn.innerText = "copy"), 2000);
      });
    }
  </script><p>图形化选择</p>
<details open>
    <summary>TEXT</summary><pre
        class="codeblock"
      ><code class="language-" data-lang="">Get-AppxPackage | Out-GridView -Passthru | Remove-AppXPackage -AllUsers</code><button onclick="copyCode(this)" class="copybtn">copy</button></pre></details>

  <script>
    function copyCode(btn) {
      const code = btn.previousElementSibling.textContent.trim();
      navigator.clipboard.writeText(code).then(() => {
        btn.innerText = "copied";
        setTimeout(() => (btn.innerText = "copy"), 2000);
      });
    }
  </script><p>删除某些</p>
<details open>
    <summary>TEXT</summary><pre
        class="codeblock"
      ><code class="language-" data-lang="">Get-AppxProvisionedPackage -Online | where-object {$_.packagename -like &#34;xbox&#34;} | Remove-AppxProvisionedPackage -Online</code><button onclick="copyCode(this)" class="copybtn">copy</button></pre></details>

  <script>
    function copyCode(btn) {
      const code = btn.previousElementSibling.textContent.trim();
      navigator.clipboard.writeText(code).then(() => {
        btn.innerText = "copied";
        setTimeout(() => (btn.innerText = "copy"), 2000);
      });
    }
  </script><p>去除某个分区的<code>WindowsApps</code>文件夹</p>
<details open>
    <summary>TEXT</summary><pre
        class="codeblock"
      ><code class="language-" data-lang="">Remove-AppxVolume -Volume X:\</code><button onclick="copyCode(this)" class="copybtn">copy</button></pre></details>

  <script>
    function copyCode(btn) {
      const code = btn.previousElementSibling.textContent.trim();
      navigator.clipboard.writeText(code).then(() => {
        btn.innerText = "copied";
        setTimeout(() => (btn.innerText = "copy"), 2000);
      });
    }
  </script>]]></content:encoded></item><item><title>用mkdocs、obsidian、zotero搭建在线文献学习笔记</title><link>https://hiraethecho.github.io/docs/dev/3in1wiki/</link><pubDate>Tue, 15 Oct 2024 00:00:00 +0000</pubDate><author>wyz2016zxc@outlook.com(Hiraeth)</author><guid>https://hiraethecho.github.io/docs/dev/3in1wiki/</guid><description>&lt;h1 id="使用mkdocsobsidianzotero搭建在线文献学习笔记"&gt;
&lt;a class="anchor inpage" href="#%e4%bd%bf%e7%94%a8mkdocsobsidianzotero%e6%90%ad%e5%bb%ba%e5%9c%a8%e7%ba%bf%e6%96%87%e7%8c%ae%e5%ad%a6%e4%b9%a0%e7%ac%94%e8%ae%b0"&gt;#&lt;/a&gt;使用mkdocs、obsidian、zotero搭建在线文献学习笔记&lt;/h1&gt;
&lt;p&gt;工作流是，在zotero中阅读和标记。用zotero-better-notes插件把标记变成文本格式，并且导出到obsidian的库文件中，进一步编辑（或者用nvim编辑）。在obsidian中更方便笔记链接跳转，zotero只是文献管理和阅读。然后把笔记同步到mkdocs的git仓库（实际上是把mkdocs的文件夹软链接到obsidian库），用github pages搭建在线wiki。&lt;/p&gt;</description><content:encoded><![CDATA[<h1 id="使用mkdocsobsidianzotero搭建在线文献学习笔记">
  <a class="anchor inpage" href="#%e4%bd%bf%e7%94%a8mkdocsobsidianzotero%e6%90%ad%e5%bb%ba%e5%9c%a8%e7%ba%bf%e6%96%87%e7%8c%ae%e5%ad%a6%e4%b9%a0%e7%ac%94%e8%ae%b0">#</a>使用mkdocs、obsidian、zotero搭建在线文献学习笔记</h1>
<p>工作流是，在zotero中阅读和标记。用zotero-better-notes插件把标记变成文本格式，并且导出到obsidian的库文件中，进一步编辑（或者用nvim编辑）。在obsidian中更方便笔记链接跳转，zotero只是文献管理和阅读。然后把笔记同步到mkdocs的git仓库（实际上是把mkdocs的文件夹软链接到obsidian库），用github pages搭建在线wiki。</p>
<h2 id="设置">
  <a class="anchor inpage" href="#%e8%ae%be%e7%bd%ae">##</a>设置</h2>
<h3 id="zotero">
  <a class="anchor inpage" href="#zotero">###</a>Zotero</h3>
<p>关键是<code>zotero-better-note</code>插件的
：从注释创建笔记；将笔记插入到其他笔记；将笔记导出为markdown。</p>
<blockquote class="alert alert-important">
      <p class="alert-heading">IMPORTANT</p><p>导出路径和模板中链接路径有硬编码部分，需要根据具体情况手动修改。</p></blockquote><h3 id="obsidian">
  <a class="anchor inpage" href="#obsidian">###</a>obsidian</h3>
<p>需要在设置中选择使用<code>markdown</code>风格链接而不是<code>wiki</code>风格。根目录<code>/</code>是obsidian的库文件夹。</p>
<h3 id="mkdocs">
  <a class="anchor inpage" href="#mkdocs">###</a>mkdocs</h3>
<p>基本上就是直接使用模板。</p>
<h2 id="路径匹配">
  <a class="anchor inpage" href="#%e8%b7%af%e5%be%84%e5%8c%b9%e9%85%8d">##</a>路径匹配</h2>
<p>主要需要注意的，是文件名和链接格式，即<code>[markdown格式的链接](这里应该写什么路径)</code>，使得zotero、obsidian、在线网页的跳转都正常。实际上有两个跳转，一个是到md文件的跳转，另一个是到pdf的跳转。前者是obsidian或网页内的跳转，相对简单；后者是跳转到zotero中的pdf，这个实际上只有我能用，因为涉及到zotero的数据库。有多种选择：</p>
<h3 id="docs文件夹作为obsidian仓库">
  <a class="anchor inpage" href="#docs%e6%96%87%e4%bb%b6%e5%a4%b9%e4%bd%9c%e4%b8%baobsidian%e4%bb%93%e5%ba%93">###</a><code>docs</code>文件夹作为obsidian仓库</h3>
<p>创建仓库<code>username.github.io</code>（必须是这个格式），在线网页会是<code>https://&lt;username&gt;.github.io</code>，那么链接应该写成<code>[title](/filename)</code>，在网页端是<code>https://&lt;username&gt;.github.io/filename</code>。把<code>docs/</code>文件夹作为obsidian repo，用<code>.gitignore</code>忽略掉<code>docs/.obsidian</code>。</p>
<p>优点是简单，缺点文件直接在obsidian的根目录，不好管理其他内容了。</p>
<h3 id="docs文件夹作为obsidian仓库子文件夹">
  <a class="anchor inpage" href="#docs%e6%96%87%e4%bb%b6%e5%a4%b9%e4%bd%9c%e4%b8%baobsidian%e4%bb%93%e5%ba%93%e5%ad%90%e6%96%87%e4%bb%b6%e5%a4%b9">###</a><code>docs</code>文件夹作为obsidian仓库子文件夹</h3>
<p>使用二级域名的github pages，即创建仓库（例如<code>wiki</code>），在线网页会是<code>https://&lt;username&gt;.github.io/wiki</code>，那么链接应该写成<code>[title](/wiki/filename)</code>，在网页端是<code>https://&lt;username&gt;.github.io/wiki/filename</code></p>
<p>把<code>docs</code>变成obsidian的子文件夹，可以用软链接：</p>
<details open>
    <summary>sh</summary><pre
        class="chroma codeblock"
      ><code class="language-sh" data-lang="sh"
          ><span style="display:flex;"><span>ln -s /path/to/git/repo/docs /path/to/obsidian/repo/wiki</span></span></code
        ><button onclick="copyCode(this)" class="copybtn">copy</button></pre></details>

  <script>
    function copyCode(btn) {
      const code = btn.previousElementSibling.textContent.trim();
      navigator.clipboard.writeText(code).then(() => {
        btn.innerText = "copied";
        setTimeout(() => (btn.innerText = "copy"), 2000);
      });
    }
  </script><p>或者用
</p>
<h2 id="总结">
  <a class="anchor inpage" href="#%e6%80%bb%e7%bb%93">##</a>总结</h2>
<blockquote class="alert alert-note">
      <p class="alert-heading">NOTE</p><p>似乎需要一个markdown和latex转换的脚本。其中markdown应该混写html比较好。似乎lua就可以，那么就可以做nvim插件。<br>
2025-05-21: 似乎latex转markdown+html比较好，用<code>&lt;ul&gt;</code> <code>&lt;ol&gt;</code> <code>&lt;detail&gt;</code>标签来处理latex环境<code>itemize</code> <code>enumerate</code> <code>Theorem</code></p></blockquote>]]></content:encoded></item><item><title>git备忘</title><link>https://hiraethecho.github.io/docs/dev/git-tips/</link><pubDate>Fri, 10 Nov 2023 00:00:00 +0000</pubDate><author>wyz2016zxc@outlook.com(Hiraeth)</author><guid>https://hiraethecho.github.io/docs/dev/git-tips/</guid><description>git 常用命令</description><content:encoded><![CDATA[<h2 id="config">
  <a class="anchor inpage" href="#config">##</a>config</h2>
<details open>
    <summary>TEXT</summary><pre
        class="codeblock"
      ><code class="language-" data-lang="">git config --list</code><button onclick="copyCode(this)" class="copybtn">copy</button></pre></details>

  <script>
    function copyCode(btn) {
      const code = btn.previousElementSibling.textContent.trim();
      navigator.clipboard.writeText(code).then(() => {
        btn.innerText = "copied";
        setTimeout(() => (btn.innerText = "copy"), 2000);
      });
    }
  </script><details open>
    <summary>TEXT</summary><pre
        class="codeblock"
      ><code class="language-" data-lang="">git config --global --list</code><button onclick="copyCode(this)" class="copybtn">copy</button></pre></details>

  <script>
    function copyCode(btn) {
      const code = btn.previousElementSibling.textContent.trim();
      navigator.clipboard.writeText(code).then(() => {
        btn.innerText = "copied";
        setTimeout(() => (btn.innerText = "copy"), 2000);
      });
    }
  </script><details open>
    <summary>TEXT</summary><pre
        class="codeblock"
      ><code class="language-" data-lang="">git config --system --list</code><button onclick="copyCode(this)" class="copybtn">copy</button></pre></details>

  <script>
    function copyCode(btn) {
      const code = btn.previousElementSibling.textContent.trim();
      navigator.clipboard.writeText(code).then(() => {
        btn.innerText = "copied";
        setTimeout(() => (btn.innerText = "copy"), 2000);
      });
    }
  </script><details open>
    <summary>TEXT</summary><pre
        class="codeblock"
      ><code class="language-" data-lang="">git config --global user.name “[firstname lastname]”</code><button onclick="copyCode(this)" class="copybtn">copy</button></pre></details>

  <script>
    function copyCode(btn) {
      const code = btn.previousElementSibling.textContent.trim();
      navigator.clipboard.writeText(code).then(() => {
        btn.innerText = "copied";
        setTimeout(() => (btn.innerText = "copy"), 2000);
      });
    }
  </script><details open>
    <summary>TEXT</summary><pre
        class="codeblock"
      ><code class="language-" data-lang="">git config --global user.email “[valid-email]”</code><button onclick="copyCode(this)" class="copybtn">copy</button></pre></details>

  <script>
    function copyCode(btn) {
      const code = btn.previousElementSibling.textContent.trim();
      navigator.clipboard.writeText(code).then(() => {
        btn.innerText = "copied";
        setTimeout(() => (btn.innerText = "copy"), 2000);
      });
    }
  </script><details open>
    <summary>sh</summary><pre
        class="chroma codeblock"
      ><code class="language-sh" data-lang="sh"
          ><span style="display:flex;"><span>git config --global credential.helper <span style="color:#e6db74">&#39;store&#39;</span></span></span></code
        ><button onclick="copyCode(this)" class="copybtn">copy</button></pre></details>

  <script>
    function copyCode(btn) {
      const code = btn.previousElementSibling.textContent.trim();
      navigator.clipboard.writeText(code).then(() => {
        btn.innerText = "copied";
        setTimeout(() => (btn.innerText = "copy"), 2000);
      });
    }
  </script><h2 id="basic-usage">
  <a class="anchor inpage" href="#basic-usage">##</a>basic usage</h2>
<h3 id="init-status-diff-add-commit-stash-ignore">
  <a class="anchor inpage" href="#init-status-diff-add-commit-stash-ignore">###</a>init, status, diff, add, commit, stash, ignore</h3>
<details open>
    <summary>TEXT</summary><pre
        class="codeblock"
      ><code class="language-" data-lang="">$ git init</code><button onclick="copyCode(this)" class="copybtn">copy</button></pre></details>

  <script>
    function copyCode(btn) {
      const code = btn.previousElementSibling.textContent.trim();
      navigator.clipboard.writeText(code).then(() => {
        btn.innerText = "copied";
        setTimeout(() => (btn.innerText = "copy"), 2000);
      });
    }
  </script><details open>
    <summary>TEXT</summary><pre
        class="codeblock"
      ><code class="language-" data-lang="">$ git status</code><button onclick="copyCode(this)" class="copybtn">copy</button></pre></details>

  <script>
    function copyCode(btn) {
      const code = btn.previousElementSibling.textContent.trim();
      navigator.clipboard.writeText(code).then(() => {
        btn.innerText = "copied";
        setTimeout(() => (btn.innerText = "copy"), 2000);
      });
    }
  </script><details open>
    <summary>TEXT</summary><pre
        class="codeblock"
      ><code class="language-" data-lang="">$ git diff</code><button onclick="copyCode(this)" class="copybtn">copy</button></pre></details>

  <script>
    function copyCode(btn) {
      const code = btn.previousElementSibling.textContent.trim();
      navigator.clipboard.writeText(code).then(() => {
        btn.innerText = "copied";
        setTimeout(() => (btn.innerText = "copy"), 2000);
      });
    }
  </script><details open>
    <summary>TEXT</summary><pre
        class="codeblock"
      ><code class="language-" data-lang="">$ git add .</code><button onclick="copyCode(this)" class="copybtn">copy</button></pre></details>

  <script>
    function copyCode(btn) {
      const code = btn.previousElementSibling.textContent.trim();
      navigator.clipboard.writeText(code).then(() => {
        btn.innerText = "copied";
        setTimeout(() => (btn.innerText = "copy"), 2000);
      });
    }
  </script><details open>
    <summary>TEXT</summary><pre
        class="codeblock"
      ><code class="language-" data-lang="">$ git commit -m &#39;message here&#39;</code><button onclick="copyCode(this)" class="copybtn">copy</button></pre></details>

  <script>
    function copyCode(btn) {
      const code = btn.previousElementSibling.textContent.trim();
      navigator.clipboard.writeText(code).then(() => {
        btn.innerText = "copied";
        setTimeout(() => (btn.innerText = "copy"), 2000);
      });
    }
  </script><details open>
    <summary>TEXT</summary><pre
        class="codeblock"
      ><code class="language-" data-lang="">$ git commit --amend</code><button onclick="copyCode(this)" class="copybtn">copy</button></pre></details>

  <script>
    function copyCode(btn) {
      const code = btn.previousElementSibling.textContent.trim();
      navigator.clipboard.writeText(code).then(() => {
        btn.innerText = "copied";
        setTimeout(() => (btn.innerText = "copy"), 2000);
      });
    }
  </script><details open>
    <summary>TEXT</summary><pre
        class="codeblock"
      ><code class="language-" data-lang="">git stash
git checkout branch2
git stash pop</code><button onclick="copyCode(this)" class="copybtn">copy</button></pre></details>

  <script>
    function copyCode(btn) {
      const code = btn.previousElementSibling.textContent.trim();
      navigator.clipboard.writeText(code).then(() => {
        btn.innerText = "copied";
        setTimeout(() => (btn.innerText = "copy"), 2000);
      });
    }
  </script><p>新增ignore文件，并不再跟踪</p>
<details open>
    <summary>TEXT</summary><pre
        class="codeblock"
      ><code class="language-" data-lang=""># edit .gitignore
git rm -r --cached .
git add .
git commit -m &#34;remove xyz file&#34;</code><button onclick="copyCode(this)" class="copybtn">copy</button></pre></details>

  <script>
    function copyCode(btn) {
      const code = btn.previousElementSibling.textContent.trim();
      navigator.clipboard.writeText(code).then(() => {
        btn.innerText = "copied";
        setTimeout(() => (btn.innerText = "copy"), 2000);
      });
    }
  </script><h3 id="branch">
  <a class="anchor inpage" href="#branch">###</a>branch</h3>
<p>列出分支</p>
<details open>
    <summary>TEXT</summary><pre
        class="codeblock"
      ><code class="language-" data-lang="">$ git branch</code><button onclick="copyCode(this)" class="copybtn">copy</button></pre></details>

  <script>
    function copyCode(btn) {
      const code = btn.previousElementSibling.textContent.trim();
      navigator.clipboard.writeText(code).then(() => {
        btn.innerText = "copied";
        setTimeout(() => (btn.innerText = "copy"), 2000);
      });
    }
  </script><p>切换分支</p>
<details open>
    <summary>TEXT</summary><pre
        class="codeblock"
      ><code class="language-" data-lang="">$ git checkout &lt;branch&gt;</code><button onclick="copyCode(this)" class="copybtn">copy</button></pre></details>

  <script>
    function copyCode(btn) {
      const code = btn.previousElementSibling.textContent.trim();
      navigator.clipboard.writeText(code).then(() => {
        btn.innerText = "copied";
        setTimeout(() => (btn.innerText = "copy"), 2000);
      });
    }
  </script><p>创建并切换到新分支:</p>
<details open>
    <summary>TEXT</summary><pre
        class="codeblock"
      ><code class="language-" data-lang="">$ git checkout -b &lt;branch&gt;</code><button onclick="copyCode(this)" class="copybtn">copy</button></pre></details>

  <script>
    function copyCode(btn) {
      const code = btn.previousElementSibling.textContent.trim();
      navigator.clipboard.writeText(code).then(() => {
        btn.innerText = "copied";
        setTimeout(() => (btn.innerText = "copy"), 2000);
      });
    }
  </script><p>基于当前分支创建新分支：</p>
<details open>
    <summary>TEXT</summary><pre
        class="codeblock"
      ><code class="language-" data-lang="">$ git branch &lt;new-branch&gt;</code><button onclick="copyCode(this)" class="copybtn">copy</button></pre></details>

  <script>
    function copyCode(btn) {
      const code = btn.previousElementSibling.textContent.trim();
      navigator.clipboard.writeText(code).then(() => {
        btn.innerText = "copied";
        setTimeout(() => (btn.innerText = "copy"), 2000);
      });
    }
  </script><p>基于远程分支创建新的可追溯的分支：</p>
<details open>
    <summary>TEXT</summary><pre
        class="codeblock"
      ><code class="language-" data-lang="">$ git branch --track &lt;new-branch&gt; &lt;remote-branch&gt;</code><button onclick="copyCode(this)" class="copybtn">copy</button></pre></details>

  <script>
    function copyCode(btn) {
      const code = btn.previousElementSibling.textContent.trim();
      navigator.clipboard.writeText(code).then(() => {
        btn.innerText = "copied";
        setTimeout(() => (btn.innerText = "copy"), 2000);
      });
    }
  </script><p>删除</p>
<details open>
    <summary>TEXT</summary><pre
        class="codeblock"
      ><code class="language-" data-lang="">$ git branch -d &lt;branch&gt;</code><button onclick="copyCode(this)" class="copybtn">copy</button></pre></details>

  <script>
    function copyCode(btn) {
      const code = btn.previousElementSibling.textContent.trim();
      navigator.clipboard.writeText(code).then(() => {
        btn.innerText = "copied";
        setTimeout(() => (btn.innerText = "copy"), 2000);
      });
    }
  </script><details open>
    <summary>TEXT</summary><pre
        class="codeblock"
      ><code class="language-" data-lang="">$ git tag &lt;tag-name&gt;</code><button onclick="copyCode(this)" class="copybtn">copy</button></pre></details>

  <script>
    function copyCode(btn) {
      const code = btn.previousElementSibling.textContent.trim();
      navigator.clipboard.writeText(code).then(() => {
        btn.innerText = "copied";
        setTimeout(() => (btn.innerText = "copy"), 2000);
      });
    }
  </script><h3 id="log">
  <a class="anchor inpage" href="#log">###</a>log</h3>
<details open>
    <summary>TEXT</summary><pre
        class="codeblock"
      ><code class="language-" data-lang="">$ git log --oneline</code><button onclick="copyCode(this)" class="copybtn">copy</button></pre></details>

  <script>
    function copyCode(btn) {
      const code = btn.previousElementSibling.textContent.trim();
      navigator.clipboard.writeText(code).then(() => {
        btn.innerText = "copied";
        setTimeout(() => (btn.innerText = "copy"), 2000);
      });
    }
  </script><details open>
    <summary>TEXT</summary><pre
        class="codeblock"
      ><code class="language-" data-lang="">$ git log --author=&#34;username&#34;</code><button onclick="copyCode(this)" class="copybtn">copy</button></pre></details>

  <script>
    function copyCode(btn) {
      const code = btn.previousElementSibling.textContent.trim();
      navigator.clipboard.writeText(code).then(() => {
        btn.innerText = "copied";
        setTimeout(() => (btn.innerText = "copy"), 2000);
      });
    }
  </script><p>仅显示远端&lt;remote/master&gt;分支与远端&lt;origin/master&gt;分支提交记录的差集：</p>
<details open>
    <summary>TEXT</summary><pre
        class="codeblock"
      ><code class="language-" data-lang="">$ git log --oneline &lt;origin/master&gt;..&lt;remote/master&gt; --left-right</code><button onclick="copyCode(this)" class="copybtn">copy</button></pre></details>

  <script>
    function copyCode(btn) {
      const code = btn.previousElementSibling.textContent.trim();
      navigator.clipboard.writeText(code).then(() => {
        btn.innerText = "copied";
        setTimeout(() => (btn.innerText = "copy"), 2000);
      });
    }
  </script><p>谁，在什么时间，修改了文件的什么内容：</p>
<details open>
    <summary>TEXT</summary><pre
        class="codeblock"
      ><code class="language-" data-lang="">$ git blame &lt;file&gt;</code><button onclick="copyCode(this)" class="copybtn">copy</button></pre></details>

  <script>
    function copyCode(btn) {
      const code = btn.previousElementSibling.textContent.trim();
      navigator.clipboard.writeText(code).then(() => {
        btn.innerText = "copied";
        setTimeout(() => (btn.innerText = "copy"), 2000);
      });
    }
  </script><h3 id="remote">
  <a class="anchor inpage" href="#remote">###</a>remote</h3>
<details open>
    <summary>TEXT</summary><pre
        class="codeblock"
      ><code class="language-" data-lang="">$ git remote -v</code><button onclick="copyCode(this)" class="copybtn">copy</button></pre></details>

  <script>
    function copyCode(btn) {
      const code = btn.previousElementSibling.textContent.trim();
      navigator.clipboard.writeText(code).then(() => {
        btn.innerText = "copied";
        setTimeout(() => (btn.innerText = "copy"), 2000);
      });
    }
  </script><details open>
    <summary>TEXT</summary><pre
        class="codeblock"
      ><code class="language-" data-lang="">$ git remote show &lt;remote&gt;</code><button onclick="copyCode(this)" class="copybtn">copy</button></pre></details>

  <script>
    function copyCode(btn) {
      const code = btn.previousElementSibling.textContent.trim();
      navigator.clipboard.writeText(code).then(() => {
        btn.innerText = "copied";
        setTimeout(() => (btn.innerText = "copy"), 2000);
      });
    }
  </script><details open>
    <summary>TEXT</summary><pre
        class="codeblock"
      ><code class="language-" data-lang="">$ git remote add &lt;remote&gt; &lt;url&gt;</code><button onclick="copyCode(this)" class="copybtn">copy</button></pre></details>

  <script>
    function copyCode(btn) {
      const code = btn.previousElementSibling.textContent.trim();
      navigator.clipboard.writeText(code).then(() => {
        btn.innerText = "copied";
        setTimeout(() => (btn.innerText = "copy"), 2000);
      });
    }
  </script><details open>
    <summary>TEXT</summary><pre
        class="codeblock"
      ><code class="language-" data-lang="">$ git fetch &lt;remote&gt;</code><button onclick="copyCode(this)" class="copybtn">copy</button></pre></details>

  <script>
    function copyCode(btn) {
      const code = btn.previousElementSibling.textContent.trim();
      navigator.clipboard.writeText(code).then(() => {
        btn.innerText = "copied";
        setTimeout(() => (btn.innerText = "copy"), 2000);
      });
    }
  </script><details open>
    <summary>TEXT</summary><pre
        class="codeblock"
      ><code class="language-" data-lang="">git pull --rebase &lt;remote&gt; &lt;branch&gt;</code><button onclick="copyCode(this)" class="copybtn">copy</button></pre></details>

  <script>
    function copyCode(btn) {
      const code = btn.previousElementSibling.textContent.trim();
      navigator.clipboard.writeText(code).then(() => {
        btn.innerText = "copied";
        setTimeout(() => (btn.innerText = "copy"), 2000);
      });
    }
  </script><details open>
    <summary>TEXT</summary><pre
        class="codeblock"
      ><code class="language-" data-lang="">$ git push remote &lt;remote&gt; &lt;branch&gt;</code><button onclick="copyCode(this)" class="copybtn">copy</button></pre></details>

  <script>
    function copyCode(btn) {
      const code = btn.previousElementSibling.textContent.trim();
      navigator.clipboard.writeText(code).then(() => {
        btn.innerText = "copied";
        setTimeout(() => (btn.innerText = "copy"), 2000);
      });
    }
  </script><details open>
    <summary>TEXT</summary><pre
        class="codeblock"
      ><code class="language-" data-lang="">git push &lt;remote&gt; --delete &lt;branch&gt; (since Git v1.7.0)</code><button onclick="copyCode(this)" class="copybtn">copy</button></pre></details>

  <script>
    function copyCode(btn) {
      const code = btn.previousElementSibling.textContent.trim();
      navigator.clipboard.writeText(code).then(() => {
        btn.innerText = "copied";
        setTimeout(() => (btn.innerText = "copy"), 2000);
      });
    }
  </script><details open>
    <summary>TEXT</summary><pre
        class="codeblock"
      ><code class="language-" data-lang="">git remote add &lt;remote name&gt; &lt;url&gt;
git push &lt;remote name&gt; &lt;local branch&gt;:&lt;remote branch&gt;</code><button onclick="copyCode(this)" class="copybtn">copy</button></pre></details>

  <script>
    function copyCode(btn) {
      const code = btn.previousElementSibling.textContent.trim();
      navigator.clipboard.writeText(code).then(() => {
        btn.innerText = "copied";
        setTimeout(() => (btn.innerText = "copy"), 2000);
      });
    }
  </script><details open>
    <summary>TEXT</summary><pre
        class="codeblock"
      ><code class="language-" data-lang="">$ git push --tags</code><button onclick="copyCode(this)" class="copybtn">copy</button></pre></details>

  <script>
    function copyCode(btn) {
      const code = btn.previousElementSibling.textContent.trim();
      navigator.clipboard.writeText(code).then(() => {
        btn.innerText = "copied";
        setTimeout(() => (btn.innerText = "copy"), 2000);
      });
    }
  </script><h3 id="reset">
  <a class="anchor inpage" href="#reset">###</a>reset</h3>
<details open>
    <summary>TEXT</summary><pre
        class="codeblock"
      ><code class="language-" data-lang="">$ git reset --hard HEAD</code><button onclick="copyCode(this)" class="copybtn">copy</button></pre></details>

  <script>
    function copyCode(btn) {
      const code = btn.previousElementSibling.textContent.trim();
      navigator.clipboard.writeText(code).then(() => {
        btn.innerText = "copied";
        setTimeout(() => (btn.innerText = "copy"), 2000);
      });
    }
  </script><p>移除缓存区的所有文件（i.e. 撤销上次<code>git add</code>）:</p>
<details open>
    <summary>TEXT</summary><pre
        class="codeblock"
      ><code class="language-" data-lang="">$ git reset HEAD</code><button onclick="copyCode(this)" class="copybtn">copy</button></pre></details>

  <script>
    function copyCode(btn) {
      const code = btn.previousElementSibling.textContent.trim();
      navigator.clipboard.writeText(code).then(() => {
        btn.innerText = "copied";
        setTimeout(() => (btn.innerText = "copy"), 2000);
      });
    }
  </script><p>放弃某个文件的所有本地修改：</p>
<details open>
    <summary>TEXT</summary><pre
        class="codeblock"
      ><code class="language-" data-lang="">$ git checkout HEAD &lt;file&gt;</code><button onclick="copyCode(this)" class="copybtn">copy</button></pre></details>

  <script>
    function copyCode(btn) {
      const code = btn.previousElementSibling.textContent.trim();
      navigator.clipboard.writeText(code).then(() => {
        btn.innerText = "copied";
        setTimeout(() => (btn.innerText = "copy"), 2000);
      });
    }
  </script><p>重置一个提交（通过创建一个截然不同的新提交）</p>
<details open>
    <summary>TEXT</summary><pre
        class="codeblock"
      ><code class="language-" data-lang="">$ git revert &lt;commit&gt;</code><button onclick="copyCode(this)" class="copybtn">copy</button></pre></details>

  <script>
    function copyCode(btn) {
      const code = btn.previousElementSibling.textContent.trim();
      navigator.clipboard.writeText(code).then(() => {
        btn.innerText = "copied";
        setTimeout(() => (btn.innerText = "copy"), 2000);
      });
    }
  </script><p>将HEAD重置到指定的版本，并抛弃该版本之后的所有修改：</p>
<details open>
    <summary>TEXT</summary><pre
        class="codeblock"
      ><code class="language-" data-lang="">$ git reset --hard &lt;commit&gt;</code><button onclick="copyCode(this)" class="copybtn">copy</button></pre></details>

  <script>
    function copyCode(btn) {
      const code = btn.previousElementSibling.textContent.trim();
      navigator.clipboard.writeText(code).then(() => {
        btn.innerText = "copied";
        setTimeout(() => (btn.innerText = "copy"), 2000);
      });
    }
  </script><h2 id="submodule">
  <a class="anchor inpage" href="#submodule">##</a>submodule</h2>
<p>使用 <code>git submodule add &lt;submodule_url&gt;</code> 命令可以在项目中创建一个子模块。<br>
此时项目仓库中会多出两个文件：<code>.gitmodules</code> 和 <code>project-sub-1</code> 。<br>
通常此时可以使用 <code>git commit -m &quot;add submodule xxx&quot;</code> 提交一次，表示引入了某个子模块。提交后，在主项目仓库中，会显示出子模块文件夹，并带上其所在仓库的版本号。</p>
<p>上述步骤在创建子模块的过程中，会自动将相关代码克隆到对应路径，但对于后续使用者而言，对于主项目使用普通的 <code>clone</code> 操作并不会拉取到子模块中的实际代码。<br>
如果希望子模块代码也获取到，一种方式是在克隆主项目的时候带上参数 <code>--recurse-submodules</code>，这样会递归地将项目中所有子模块的代码拉取。<br>
手动更新</p>
<details open>
    <summary>sh</summary><pre
        class="chroma codeblock"
      ><code class="language-sh" data-lang="sh"
          ><span style="display:flex;"><span>git submodule init
</span></span><span style="display:flex;"><span>git submodule update</span></span></code
        ><button onclick="copyCode(this)" class="copybtn">copy</button></pre></details>

  <script>
    function copyCode(btn) {
      const code = btn.previousElementSibling.textContent.trim();
      navigator.clipboard.writeText(code).then(() => {
        btn.innerText = "copied";
        setTimeout(() => (btn.innerText = "copy"), 2000);
      });
    }
  </script><ol>
<li>当前项目下子模块文件夹内的内容发生了未跟踪的内容变动；</li>
<li>当前项目下子模块文件夹内的内容发生了版本变化；</li>
<li>当前项目下子模块文件夹内的内容没变，远程有更新；</li>
</ol>
<p>对于第1种情况，通常是在开发环境中，直接修改子模块文件夹中的代码导致的。<br>
此时在主项目中使用 <code>git status</code> 能够看到关于子模块尚
在此情景下，通常需要进入子模块文件夹，按照子模块内部的版本控制体系提交代码。</p>
<p>当提交完成后，主项目的状态则进入了情况2，即当前项目下子模块文件夹内的内容发生了版本变化。<br>
当子模块版本变化时，在主项目中使用 <code>git status</code> 查看仓库状态时，会显示子模块有新的提交。<br>
在这种情况下，可以使用 <code>git add/commit</code> 将其添加到主项目的代码提交中，实际的改动就是那个子模块 <code>文件</code> 所表示的版本信息。<br>
通常当子项目更新后，主项目修改其所依赖的版本时，会产生类似这种情景的 commit 提交信息。</p>
<p>情况3：子模块远程有更新。需要让主项目主动进入子模块拉取新版代码，进行升级操作。</p>
<details open>
    <summary>sh</summary><pre
        class="chroma codeblock"
      ><code class="language-sh" data-lang="sh"
          ><span style="display:flex;"><span>cd project-sub-1
</span></span><span style="display:flex;"><span>git pull origin master</span></span></code
        ><button onclick="copyCode(this)" class="copybtn">copy</button></pre></details>

  <script>
    function copyCode(btn) {
      const code = btn.previousElementSibling.textContent.trim();
      navigator.clipboard.writeText(code).then(() => {
        btn.innerText = "copied";
        setTimeout(() => (btn.innerText = "copy"), 2000);
      });
    }
  </script><p>子模块目录下的代码版本会发生变化，转到情况2的流程进行主项目的提交。<br>
当主项目的子项目特别多时，可能会不太方便，此时可以使用 <code>git submodule</code> 的一个命令 <code>foreach</code> 执行：</p>
<details open>
    <summary>TEXT</summary><pre
        class="codeblock"
      ><code class="language-" data-lang="">git submodule foreach &#39;git pull origin master&#39;</code><button onclick="copyCode(this)" class="copybtn">copy</button></pre></details>

  <script>
    function copyCode(btn) {
      const code = btn.previousElementSibling.textContent.trim();
      navigator.clipboard.writeText(code).then(() => {
        btn.innerText = "copied";
        setTimeout(() => (btn.innerText = "copy"), 2000);
      });
    }
  </script><p>使用 <code>git submodule deinit</code> 命令卸载一个子模块。这个命令如果添加上参数 <code>--force</code>，则子模块工作区内即使有本地的修改，也会被移除。</p>
<details open>
    <summary>TEXT</summary><pre
        class="codeblock"
      ><code class="language-" data-lang="">git submodule deinit project-sub-1
git rm project-sub-1</code><button onclick="copyCode(this)" class="copybtn">copy</button></pre></details>

  <script>
    function copyCode(btn) {
      const code = btn.previousElementSibling.textContent.trim();
      navigator.clipboard.writeText(code).then(() => {
        btn.innerText = "copied";
        setTimeout(() => (btn.innerText = "copy"), 2000);
      });
    }
  </script><p>此时，主项目中关于子模块的信息基本已经删除，可以提交代码：</p>
<details open>
    <summary>TEXT</summary><pre
        class="codeblock"
      ><code class="language-" data-lang="">git commit -m &#34;delete submodule project-sub-1&#34;</code><button onclick="copyCode(this)" class="copybtn">copy</button></pre></details>

  <script>
    function copyCode(btn) {
      const code = btn.previousElementSibling.textContent.trim();
      navigator.clipboard.writeText(code).then(() => {
        btn.innerText = "copied";
        setTimeout(() => (btn.innerText = "copy"), 2000);
      });
    }
  </script><h2 id="worktree">
  <a class="anchor inpage" href="#worktree">##</a>worktree</h2>
<p>一般在主目录外建立另一个worktree，这样可以同时处理两个分支</p>
<details open>
    <summary>TEXT</summary><pre
        class="codeblock"
      ><code class="language-" data-lang="">usage: git worktree add [-f] [--detach] [--checkout] [--lock [--reason &lt;string&gt;]]
                        [--orphan] [(-b | -B) &lt;new-branch&gt;] &lt;path&gt; [&lt;commit-ish&gt;]
   or: git worktree list [-v | --porcelain [-z]]
   or: git worktree lock [--reason &lt;string&gt;] &lt;worktree&gt;
   or: git worktree move &lt;worktree&gt; &lt;new-path&gt;
   or: git worktree prune [-n] [-v] [--expire &lt;expire&gt;]
   or: git worktree remove [-f] &lt;worktree&gt;
   or: git worktree repair [&lt;path&gt;...]
   or: git worktree unlock &lt;worktree&gt;</code><button onclick="copyCode(this)" class="copybtn">copy</button></pre></details>

  <script>
    function copyCode(btn) {
      const code = btn.previousElementSibling.textContent.trim();
      navigator.clipboard.writeText(code).then(() => {
        btn.innerText = "copied";
        setTimeout(() => (btn.innerText = "copy"), 2000);
      });
    }
  </script><p>For example: <code>git worktree add ../tree</code></p>
<h2 id="清理">
  <a class="anchor inpage" href="#%e6%b8%85%e7%90%86">##</a>清理</h2>
<p>清理</p>
<details open>
    <summary>TEXT</summary><pre
        class="codeblock"
      ><code class="language-" data-lang="">git clean -xdf</code><button onclick="copyCode(this)" class="copybtn">copy</button></pre></details>

  <script>
    function copyCode(btn) {
      const code = btn.previousElementSibling.textContent.trim();
      navigator.clipboard.writeText(code).then(() => {
        btn.innerText = "copied";
        setTimeout(() => (btn.innerText = "copy"), 2000);
      });
    }
  </script><p>其中<code>-x</code> remove ignored files，<code>d</code> remove untracked directories, <code>-f</code> remove untracked nested repositories</p>
<h2 id="reference">
  <a class="anchor inpage" href="#reference">##</a>reference</h2>
<ol>
<li>
</li>
<li>
</li>
<li>
</li>
<li>
</li>
<li>
</li>
</ol>
]]></content:encoded></item><item><title>regex</title><link>https://hiraethecho.github.io/docs/dev/regex/</link><pubDate>Mon, 01 Jan 0001 00:00:00 +0000</pubDate><author>wyz2016zxc@outlook.com(Hiraeth)</author><guid>https://hiraethecho.github.io/docs/dev/regex/</guid><description>&lt;h1 id="regex"&gt;
&lt;a class="anchor inpage" href="#regex"&gt;#&lt;/a&gt;regex&lt;/h1&gt;
&lt;h2 id="vim"&gt;
&lt;a class="anchor inpage" href="#vim"&gt;##&lt;/a&gt;vim&lt;/h2&gt;
&lt;details open&gt;
&lt;summary&gt;vim&lt;/summary&gt;&lt;pre
class="chroma codeblock"
&gt;&lt;code class="language-vim" data-lang="vim"
&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;/^&lt;span style="color:#a6e22e"&gt;hello&lt;/span&gt;\&amp;gt; &lt;span style="color:#75715e"&gt;&amp;#34; 匹配行首的单词 hello&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;:%&lt;span style="color:#a6e22e"&gt;s&lt;/span&gt;&lt;span style="color:#e6db74"&gt;/foo/&lt;/span&gt;&lt;span style="color:#a6e22e"&gt;bar&lt;/span&gt;/&lt;span style="color:#a6e22e"&gt;g&lt;/span&gt; &lt;span style="color:#75715e"&gt;&amp;#34; 全局替换 foo 为 bar&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;:%&lt;span style="color:#a6e22e"&gt;s&lt;/span&gt;&lt;span style="color:#e6db74"&gt;/\(\d\+\)/&lt;/span&gt;[\&lt;span style="color:#ae81ff"&gt;1&lt;/span&gt;]/&lt;span style="color:#a6e22e"&gt;g&lt;/span&gt; &lt;span style="color:#75715e"&gt;&amp;#34; 将所有数字用 [] 包裹（捕获组）&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/code
&gt;&lt;button onclick="copyCode(this)" class="copybtn"&gt;copy&lt;/button&gt;&lt;/pre&gt;&lt;/details&gt;
&lt;script&gt;
function copyCode(btn) {
const code = btn.previousElementSibling.textContent.trim();
navigator.clipboard.writeText(code).then(() =&gt; {
btn.innerText = "copied";
setTimeout(() =&gt; (btn.innerText = "copy"), 2000);
});
}
&lt;/script&gt;&lt;p&gt;捕获组：&lt;code&gt;:%s/\(\d\+\)/[\1]/g&lt;/code&gt; 将所有数字用 &lt;code&gt;[]&lt;/code&gt; 包裹（捕获组）&lt;/p&gt;</description></item></channel></rss>