<?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>HomeonDocs</title><link>https://hiraethecho.github.io/docs/</link><description>Recent contentinHomeonDocs</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/index.xml" rel="self" type="application/rss+xml"/><item><title>grub rescue</title><link>https://hiraethecho.github.io/docs/linux/grub-rescue/</link><pubDate>Tue, 06 Jan 2026 00:00:00 +0000</pubDate><author>wyz2016zxc@outlook.com(Hiraeth)</author><guid>https://hiraethecho.github.io/docs/linux/grub-rescue/</guid><description>在windows下搞坏grub又没有live系统，使用神秘的grub rescue启动linux</description><content:encoded><![CDATA[<h1 id="grub-rescure">
  <a class="anchor inpage" href="#grub-rescure">#</a>grub rescure</h1>
<p>全完蛋的时候还是要live iso进去搞</p>
<h2 id="启动">
  <a class="anchor inpage" href="#%e5%90%af%e5%8a%a8">##</a>启动</h2>
<p><code>ls</code> 查看分区</p>
<p>我用的是btrfs系统。查找 Btrfs 分区 <code>ls (hd0,gpt2)/</code></p>
<p>设置prefix <code>set prefix=(hd0,gpt2)/@/boot/grub</code><br>
或者，如果 @boot 是独立子卷 <code>set prefix=(hd0,gpt2)/@boot/grub</code><br>
或者，如果没有子卷结构（早期安装） <code>set prefix=(hd0,gpt2)/boot/grub</code></p>
<p>加载 Btrfs 模块 <code>insmod btrfs</code></p>
<p>继续正常流程</p>
<details open>
    <summary>TEXT</summary><pre
        class="codeblock"
      ><code class="language-" data-lang="">set root=(hd0,gpt2)
insmod normal
normal</code><button onclick="copyCode(this)" class="copybtn">copy</button></pre></details>

  <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="修复grub">
  <a class="anchor inpage" href="#%e4%bf%ae%e5%a4%8dgrub">##</a>修复grub</h2>
<p>安装</p>
<details open>
    <summary>TEXT</summary><pre
        class="codeblock"
      ><code class="language-" data-lang="">grub-install --target=x86_64-efi --efi-directory=/efi  --bootloader-id=ARCH</code><button onclick="copyCode(this)" class="copybtn">copy</button></pre></details>

  <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="">grub-mkconfig -o /boot/grub/grub.cfg</code><button onclick="copyCode(this)" class="copybtn">copy</button></pre></details>

  <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="#%e5%85%b6%e4%bb%96">##</a>其他</h2>
<h3 id="核心命令">
  <a class="anchor inpage" href="#%e6%a0%b8%e5%bf%83%e5%91%bd%e4%bb%a4">###</a><strong>核心命令</strong></h3>
<details open>
    <summary>bash</summary><pre
        class="chroma codeblock"
      ><code class="language-bash" data-lang="bash"
          ><span style="display:flex;"><span><span style="color:#75715e"># 1. ls - 列出设备和分区</span>
</span></span><span style="display:flex;"><span>ls                    <span style="color:#75715e"># 列出所有设备</span>
</span></span><span style="display:flex;"><span>ls <span style="color:#f92672">(</span>hd0<span style="color:#f92672">)</span>             <span style="color:#75715e"># 查看第一块磁盘</span>
</span></span><span style="display:flex;"><span>ls <span style="color:#f92672">(</span>hd0,1<span style="color:#f92672">)</span>           <span style="color:#75715e"># 查看第一块磁盘的第一个分区</span>
</span></span><span style="display:flex;"><span>ls <span style="color:#f92672">(</span>hd0,gpt1<span style="color:#f92672">)</span>/       <span style="color:#75715e"># 查看分区内容</span>
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span><span style="color:#75715e"># 2. set - 查看/设置环境变量</span>
</span></span><span style="display:flex;"><span>set                   <span style="color:#75715e"># 查看所有变量</span>
</span></span><span style="display:flex;"><span>set root<span style="color:#f92672">=(</span>hd0,1<span style="color:#f92672">)</span>     <span style="color:#75715e"># 设置根设备</span>
</span></span><span style="display:flex;"><span>set prefix<span style="color:#f92672">=(</span>hd0,1<span style="color:#f92672">)</span>/boot/grub</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="模块相关命令">
  <a class="anchor inpage" href="#%e6%a8%a1%e5%9d%97%e7%9b%b8%e5%85%b3%e5%91%bd%e4%bb%a4">###</a><strong>模块相关命令</strong></h3>
<details open>
    <summary>bash</summary><pre
        class="chroma codeblock"
      ><code class="language-bash" data-lang="bash"
          ><span style="display:flex;"><span><span style="color:#75715e"># 3. insmod - 加载模块</span>
</span></span><span style="display:flex;"><span>insmod normal        <span style="color:#75715e"># 加载 normal 模块</span>
</span></span><span style="display:flex;"><span>insmod linux         <span style="color:#75715e"># 加载 Linux 引导模块</span>
</span></span><span style="display:flex;"><span>insmod chain         <span style="color:#75715e"># 加载链式引导模块</span>
</span></span><span style="display:flex;"><span>insmod part_msdos    <span style="color:#75715e"># MBR 分区支持</span>
</span></span><span style="display:flex;"><span>insmod part_gpt      <span style="color:#75715e"># GPT 分区支持</span>
</span></span><span style="display:flex;"><span>insmod ext2          <span style="color:#75715e"># ext2/3/4 支持</span>
</span></span><span style="display:flex;"><span>insmod btrfs         <span style="color:#75715e"># Btrfs 支持</span>
</span></span><span style="display:flex;"><span>insmod ntfs          <span style="color:#75715e"># NTFS 支持</span>
</span></span><span style="display:flex;"><span>insmod fat           <span style="color:#75715e"># FAT/FAT32 支持</span>
</span></span><span style="display:flex;"><span>insmod xfs           <span style="color:#75715e"># XFS 支持</span>
</span></span><span style="display:flex;"><span>insmod configfile    <span style="color:#75715e"># 配置文件支持</span>
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span><span style="color:#75715e"># 4. lsmod - 列出已加载模块</span>
</span></span><span style="display:flex;"><span>lsmod</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="引导相关命令">
  <a class="anchor inpage" href="#%e5%bc%95%e5%af%bc%e7%9b%b8%e5%85%b3%e5%91%bd%e4%bb%a4">###</a><strong>引导相关命令</strong></h3>
<details open>
    <summary>bash</summary><pre
        class="chroma codeblock"
      ><code class="language-bash" data-lang="bash"
          ><span style="display:flex;"><span><span style="color:#75715e"># 5. normal - 进入正常模式</span>
</span></span><span style="display:flex;"><span>normal              <span style="color:#75715e"># 如果加载了 normal 模块</span>
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span><span style="color:#75715e"># 6. boot - 启动系统</span>
</span></span><span style="display:flex;"><span>boot               <span style="color:#75715e"># 启动已加载的系统</span>
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span><span style="color:#75715e"># 7. linux/initrd - 手动引导 Linux</span>
</span></span><span style="display:flex;"><span>linux <span style="color:#f92672">(</span>hd0,2<span style="color:#f92672">)</span>/vmlinuz-linux root<span style="color:#f92672">=</span>/dev/sda3
</span></span><span style="display:flex;"><span>initrd <span style="color:#f92672">(</span>hd0,2<span style="color:#f92672">)</span>/initramfs-linux.img
</span></span><span style="display:flex;"><span>boot</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="磁盘和分区侦察">
  <a class="anchor inpage" href="#%e7%a3%81%e7%9b%98%e5%92%8c%e5%88%86%e5%8c%ba%e4%be%a6%e5%af%9f">###</a><strong>磁盘和分区侦察</strong></h3>
<details open>
    <summary>bash</summary><pre
        class="chroma codeblock"
      ><code class="language-bash" data-lang="bash"
          ><span style="display:flex;"><span><span style="color:#75715e"># 查看所有存储设备</span>
</span></span><span style="display:flex;"><span>ls
</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"># (hd0) (hd0,msdos1) (hd0,msdos2) (hd0,msdos3)</span>
</span></span><span style="display:flex;"><span><span style="color:#75715e"># 或者 UEFI/GPT：</span>
</span></span><span style="display:flex;"><span><span style="color:#75715e"># (hd0) (hd0,gpt1) (hd0,gpt2) (hd0,gpt3)</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>ls <span style="color:#f92672">(</span>hd0,1<span style="color:#f92672">)</span>/
</span></span><span style="display:flex;"><span>ls <span style="color:#f92672">(</span>hd0,2<span style="color:#f92672">)</span>/
</span></span><span style="display:flex;"><span>ls <span style="color:#f92672">(</span>hd0,3<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><h3 id="识别关键分区特征">
  <a class="anchor inpage" href="#%e8%af%86%e5%88%ab%e5%85%b3%e9%94%ae%e5%88%86%e5%8c%ba%e7%89%b9%e5%be%81">###</a><strong>识别关键分区特征</strong></h3>
<details open>
    <summary>bash</summary><pre
        class="chroma codeblock"
      ><code class="language-bash" data-lang="bash"
          ><span style="display:flex;"><span><span style="color:#75715e"># 查找 Linux 分区特征</span>
</span></span><span style="display:flex;"><span>ls <span style="color:#f92672">(</span>hdX,gptY<span style="color:#f92672">)</span>/boot/          <span style="color:#75715e"># 查找 /boot 目录</span>
</span></span><span style="display:flex;"><span>ls <span style="color:#f92672">(</span>hdX,gptY<span style="color:#f92672">)</span>/etc/           <span style="color:#75715e"># 查找 /etc 目录</span>
</span></span><span style="display:flex;"><span>ls <span style="color:#f92672">(</span>hdX,gptY<span style="color:#f92672">)</span>/usr/           <span style="color:#75715e"># 查找 /usr 目录</span>
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span><span style="color:#75715e"># 查找 GRUB 文件</span>
</span></span><span style="display:flex;"><span>ls <span style="color:#f92672">(</span>hdX,gptY<span style="color:#f92672">)</span>/boot/grub/     <span style="color:#75715e"># GRUB 目录</span>
</span></span><span style="display:flex;"><span>ls <span style="color:#f92672">(</span>hdX,gptY<span style="color:#f92672">)</span>/grub/          <span style="color:#75715e"># 独立 /boot 分区</span>
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span><span style="color:#75715e"># 查找 Windows 分区特征</span>
</span></span><span style="display:flex;"><span>ls <span style="color:#f92672">(</span>hdX,msdos1<span style="color:#f92672">)</span>/Windows/     <span style="color:#75715e"># Windows 系统目录</span>
</span></span><span style="display:flex;"><span>ls <span style="color:#f92672">(</span>hdX,msdos1<span style="color:#f92672">)</span>/Users/       <span style="color:#75715e"># Windows 用户目录</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="文件系统特定探查">
  <a class="anchor inpage" href="#%e6%96%87%e4%bb%b6%e7%b3%bb%e7%bb%9f%e7%89%b9%e5%ae%9a%e6%8e%a2%e6%9f%a5">###</a><strong>文件系统特定探查</strong></h3>
<details open>
    <summary>bash</summary><pre
        class="chroma codeblock"
      ><code class="language-bash" data-lang="bash"
          ><span style="display:flex;"><span><span style="color:#75715e"># 先加载文件系统模块再查看</span>
</span></span><span style="display:flex;"><span>insmod ext2
</span></span><span style="display:flex;"><span>ls <span style="color:#f92672">(</span>hd0,1<span style="color:#f92672">)</span>/
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span>insmod btrfs
</span></span><span style="display:flex;"><span>ls <span style="color:#f92672">(</span>hd0,2<span style="color:#f92672">)</span>/           <span style="color:#75715e"># 可能看到 @, @home 等子卷</span>
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span>insmod ntfs
</span></span><span style="display:flex;"><span>ls <span style="color:#f92672">(</span>hd0,3<span style="color:#f92672">)</span>/           <span style="color:#75715e"># Windows 分区</span>
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span>insmod fat
</span></span><span style="display:flex;"><span>ls <span style="color:#f92672">(</span>hd0,gpt1<span style="color:#f92672">)</span>/        <span style="color:#75715e"># EFI 系统分区</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="简单的-grub-文件丢失">
  <a class="anchor inpage" href="#%e7%ae%80%e5%8d%95%e7%9a%84-grub-%e6%96%87%e4%bb%b6%e4%b8%a2%e5%a4%b1">###</a><strong>简单的 GRUB 文件丢失</strong></h3>
<details open>
    <summary>bash</summary><pre
        class="chroma codeblock"
      ><code class="language-bash" data-lang="bash"
          ><span style="display:flex;"><span>set prefix<span style="color:#f92672">=(</span>hd0,gpt2<span style="color:#f92672">)</span>/boot/grub
</span></span><span style="display:flex;"><span>set root<span style="color:#f92672">=(</span>hd0,gpt2<span style="color:#f92672">)</span>
</span></span><span style="display:flex;"><span>insmod normal
</span></span><span style="display:flex;"><span>normal</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>进入系统后运行：grub-install /dev/sda</p>
<h3 id="分区编号改变">
  <a class="anchor inpage" href="#%e5%88%86%e5%8c%ba%e7%bc%96%e5%8f%b7%e6%94%b9%e5%8f%98">###</a><strong>分区编号改变</strong></h3>
<p>原来的 (hd0,2) 现在变成了 (hd0,3)</p>
<details open>
    <summary>bash</summary><pre
        class="chroma codeblock"
      ><code class="language-bash" data-lang="bash"
          ><span style="display:flex;"><span>set prefix<span style="color:#f92672">=(</span>hd0,gpt3<span style="color:#f92672">)</span>/boot/grub
</span></span><span style="display:flex;"><span>set root<span style="color:#f92672">=(</span>hd0,gpt3<span style="color:#f92672">)</span>
</span></span><span style="display:flex;"><span>insmod normal
</span></span><span style="display:flex;"><span>normal</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>进入系统后更新 /etc/fstab 和 GRUB</p>
<h3 id="手动引导进入系统">
  <a class="anchor inpage" href="#%e6%89%8b%e5%8a%a8%e5%bc%95%e5%af%bc%e8%bf%9b%e5%85%a5%e7%b3%bb%e7%bb%9f">###</a><strong>手动引导进入系统</strong></h3>
<details open>
    <summary>bash</summary><pre
        class="chroma codeblock"
      ><code class="language-bash" data-lang="bash"
          ><span style="display:flex;"><span><span style="color:#75715e"># 1. 找到内核和 initramfs</span>
</span></span><span style="display:flex;"><span>ls <span style="color:#f92672">(</span>hd0,gpt2<span style="color:#f92672">)</span>/boot/
</span></span><span style="display:flex;"><span><span style="color:#75715e"># 应该看到 vmlinuz-linux 和 initramfs-linux.img</span>
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span><span style="color:#75715e"># 2. 加载必要模块</span>
</span></span><span style="display:flex;"><span>insmod part_gpt
</span></span><span style="display:flex;"><span>insmod ext2
</span></span><span style="display:flex;"><span>insmod gzio
</span></span><span style="display:flex;"><span>insmod xzio
</span></span><span style="display:flex;"><span>insmod lzopio
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span><span style="color:#75715e"># 3. 设置根设备</span>
</span></span><span style="display:flex;"><span>set root<span style="color:#f92672">=(</span>hd0,gpt2<span style="color:#f92672">)</span>
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span><span style="color:#75715e"># 4. 加载内核和 initramfs</span>
</span></span><span style="display:flex;"><span>linux /boot/vmlinuz-linux root<span style="color:#f92672">=</span>/dev/sda2 rw
</span></span><span style="display:flex;"><span><span style="color:#75715e"># 或者使用 UUID</span>
</span></span><span style="display:flex;"><span>linux /boot/vmlinuz-linux root<span style="color:#f92672">=</span>UUID<span style="color:#f92672">=</span>xxxx-xxxx rw
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span>initrd /boot/initramfs-linux.img
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span><span style="color:#75715e"># 5. 启动</span>
</span></span><span style="display:flex;"><span>boot</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="引导-windows-系统">
  <a class="anchor inpage" href="#%e5%bc%95%e5%af%bc-windows-%e7%b3%bb%e7%bb%9f">###</a><strong>引导 Windows 系统</strong></h3>
<p>找到 Windows 分区
对于 UEFI</p>
<details open>
    <summary>bash</summary><pre
        class="chroma codeblock"
      ><code class="language-bash" data-lang="bash"
          ><span style="display:flex;"><span>insmod part_gpt
</span></span><span style="display:flex;"><span>insmod fat
</span></span><span style="display:flex;"><span>ls <span style="color:#f92672">(</span>hd0,gpt1<span style="color:#f92672">)</span>/EFI/Microsoft/Boot/bootmgfw.efi
</span></span><span style="display:flex;"><span>chainloader /EFI/Microsoft/Boot/bootmgfw.efi
</span></span><span style="display:flex;"><span>boot</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="调试模式">
  <a class="anchor inpage" href="#%e8%b0%83%e8%af%95%e6%a8%a1%e5%bc%8f">###</a><strong>调试模式</strong></h3>
<details open>
    <summary>bash</summary><pre
        class="chroma codeblock"
      ><code class="language-bash" data-lang="bash"
          ><span style="display:flex;"><span><span style="color:#75715e"># 进入 GRUB 时按 ESC 或 C</span>
</span></span><span style="display:flex;"><span><span style="color:#75715e"># 或者从 rescue 模式</span>
</span></span><span style="display:flex;"><span>set debug<span style="color:#f92672">=</span>all
</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><h3 id="查看环境变量">
  <a class="anchor inpage" href="#%e6%9f%a5%e7%9c%8b%e7%8e%af%e5%a2%83%e5%8f%98%e9%87%8f">###</a><strong>查看环境变量</strong></h3>
<details open>
    <summary>bash</summary><pre
        class="chroma codeblock"
      ><code class="language-bash" data-lang="bash"
          ><span style="display:flex;"><span>set
</span></span><span style="display:flex;"><span><span style="color:#75715e"># 重要变量：</span>
</span></span><span style="display:flex;"><span><span style="color:#75715e"># prefix - GRUB 文件路径</span>
</span></span><span style="display:flex;"><span><span style="color:#75715e"># root - 根设备</span>
</span></span><span style="display:flex;"><span><span style="color:#75715e"># cmdpath - GRUB 镜像路径</span>
</span></span><span style="display:flex;"><span><span style="color:#75715e"># debug - 调试级别</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="修复常见错误">
  <a class="anchor inpage" href="#%e4%bf%ae%e5%a4%8d%e5%b8%b8%e8%a7%81%e9%94%99%e8%af%af">###</a><strong>修复常见错误</strong></h3>
<h4 id="unknown-filesystem">
  <a class="anchor inpage" href="#unknown-filesystem">####</a><strong>unknown filesystem</strong></h4>
<details open>
    <summary>bash</summary><pre
        class="chroma codeblock"
      ><code class="language-bash" data-lang="bash"
          ><span style="display:flex;"><span><span style="color:#75715e"># 加载对应的文件系统模块</span>
</span></span><span style="display:flex;"><span>insmod ext2    <span style="color:#75715e"># 对于 ext2/3/4</span>
</span></span><span style="display:flex;"><span>insmod btrfs   <span style="color:#75715e"># 对于 Btrfs</span>
</span></span><span style="display:flex;"><span>insmod xfs     <span style="color:#75715e"># 对于 XFS</span>
</span></span><span style="display:flex;"><span>insmod fat     <span style="color:#75715e"># 对于 FAT/EFI 分区</span>
</span></span><span style="display:flex;"><span>insmod ntfs    <span style="color:#75715e"># 对于 NTFS</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><h4 id="out-of-memory">
  <a class="anchor inpage" href="#out-of-memory">####</a><strong>out of memory</strong></h4>
<details open>
    <summary>bash</summary><pre
        class="chroma codeblock"
      ><code class="language-bash" data-lang="bash"
          ><span style="display:flex;"><span><span style="color:#75715e"># 清除已加载的模块</span>
</span></span><span style="display:flex;"><span>rmmod 模块名
</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>insmod part_gpt
</span></span><span style="display:flex;"><span>insmod ext2
</span></span><span style="display:flex;"><span>insmod linux</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="创建-grub-修复盘">
  <a class="anchor inpage" href="#%e5%88%9b%e5%bb%ba-grub-%e4%bf%ae%e5%a4%8d%e7%9b%98">###</a><strong>创建 GRUB 修复盘</strong></h3>
<details open>
    <summary>bash</summary><pre
        class="chroma codeblock"
      ><code class="language-bash" data-lang="bash"
          ><span style="display:flex;"><span><span style="color:#75715e"># 创建一个 GRUB 救援 USB</span>
</span></span><span style="display:flex;"><span>dd <span style="color:#66d9ef">if</span><span style="color:#f92672">=</span>/usr/lib/grub/i386-pc/boot.img of<span style="color:#f92672">=</span>/dev/sdX bs<span style="color:#f92672">=</span><span style="color:#ae81ff">446</span> count<span style="color:#f92672">=</span><span style="color:#ae81ff">1</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>grub-install --target<span style="color:#f92672">=</span>i386-pc --boot-directory<span style="color:#f92672">=</span>/mnt/usb/boot /dev/sdX</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="配置-grub-更健壮">
  <a class="anchor inpage" href="#%e9%85%8d%e7%bd%ae-grub-%e6%9b%b4%e5%81%a5%e5%a3%ae">###</a><strong>配置 GRUB 更健壮</strong></h3>
<p>编辑 <code>/etc/default/grub</code>：</p>
<details open>
    <summary>bash</summary><pre
        class="chroma codeblock"
      ><code class="language-bash" data-lang="bash"
          ><span style="display:flex;"><span><span style="color:#75715e"># 使用 UUID 而不是设备名（更稳定）</span>
</span></span><span style="display:flex;"><span>GRUB_DISABLE_LINUX_UUID<span style="color:#f92672">=</span>false
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span><span style="color:#75715e"># 启用 OS 探测</span>
</span></span><span style="display:flex;"><span>GRUB_DISABLE_OS_PROBER<span style="color:#f92672">=</span>false
</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>GRUB_BACKUP_PATHS<span style="color:#f92672">=</span><span style="color:#e6db74">&#34;/boot/grub /grub&#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>GRUB_PRELOAD_MODULES<span style="color:#f92672">=</span><span style="color:#e6db74">&#34;part_gpt part_msdos ext2 btrfs xfs fat ntfs&#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="八特殊文件系统注意事项">
  <a class="anchor inpage" href="#%e5%85%ab%e7%89%b9%e6%ae%8a%e6%96%87%e4%bb%b6%e7%b3%bb%e7%bb%9f%e6%b3%a8%e6%84%8f%e4%ba%8b%e9%a1%b9">###</a><strong>八、特殊文件系统注意事项</strong></h3>
<h4 id="zfs">
  <a class="anchor inpage" href="#zfs">####</a><strong>ZFS</strong></h4>
<details open>
    <summary>bash</summary><pre
        class="chroma codeblock"
      ><code class="language-bash" data-lang="bash"
          ><span style="display:flex;"><span><span style="color:#75715e"># 需要额外模块</span>
</span></span><span style="display:flex;"><span>insmod zfs
</span></span><span style="display:flex;"><span>set root<span style="color:#f92672">=</span>ZFS<span style="color:#f92672">=</span>poolname/dataset</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><h4 id="lvm">
  <a class="anchor inpage" href="#lvm">####</a><strong>LVM</strong></h4>
<details open>
    <summary>bash</summary><pre
        class="chroma codeblock"
      ><code class="language-bash" data-lang="bash"
          ><span style="display:flex;"><span>insmod lvm
</span></span><span style="display:flex;"><span>ls <span style="color:#f92672">(</span>lvm/volume_group-logical_volume<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><h4 id="加密分区luks">
  <a class="anchor inpage" href="#%e5%8a%a0%e5%af%86%e5%88%86%e5%8c%baluks">####</a><strong>加密分区（LUKS）</strong></h4>
<details open>
    <summary>bash</summary><pre
        class="chroma codeblock"
      ><code class="language-bash" data-lang="bash"
          ><span style="display:flex;"><span><span style="color:#75715e"># 需要先解密</span>
</span></span><span style="display:flex;"><span>cryptomount <span style="color:#f92672">(</span>hd0,gpt2<span style="color:#f92672">)</span>
</span></span><span style="display:flex;"><span>set root<span style="color:#f92672">=(</span>crypto0<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="常用命令速查表">
  <a class="anchor inpage" href="#%e5%b8%b8%e7%94%a8%e5%91%bd%e4%bb%a4%e9%80%9f%e6%9f%a5%e8%a1%a8">##</a><strong>常用命令速查表</strong></h2>
<table>
  <thead>
      <tr>
          <th>命令</th>
          <th>用途</th>
          <th>示例</th>
      </tr>
  </thead>
  <tbody>
      <tr>
          <td><code>ls</code></td>
          <td>列出设备/分区</td>
          <td><code>ls (hd0,1)/</code></td>
      </tr>
      <tr>
          <td><code>set</code></td>
          <td>设置变量</td>
          <td><code>set root=(hd0,1)</code></td>
      </tr>
      <tr>
          <td><code>insmod</code></td>
          <td>加载模块</td>
          <td><code>insmod ext2</code></td>
      </tr>
      <tr>
          <td><code>normal</code></td>
          <td>进入正常模式</td>
          <td><code>normal</code></td>
      </tr>
      <tr>
          <td><code>linux</code></td>
          <td>加载内核</td>
          <td><code>linux /vmlinuz</code></td>
      </tr>
      <tr>
          <td><code>initrd</code></td>
          <td>加载initrd</td>
          <td><code>initrd /initramfs</code></td>
      </tr>
      <tr>
          <td><code>boot</code></td>
          <td>启动系统</td>
          <td><code>boot</code></td>
      </tr>
      <tr>
          <td><code>configfile</code></td>
          <td>加载配置</td>
          <td><code>configfile /grub.cfg</code></td>
      </tr>
      <tr>
          <td><code>chainloader</code></td>
          <td>链式引导</td>
          <td><code>chainloader +1</code></td>
      </tr>
  </tbody>
</table>
]]></content:encoded></item><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 theme记录</title><link>https://hiraethecho.github.io/docs/project/hugo-theme-log/</link><pubDate>Sat, 06 Dec 2025 00:00:00 +0000</pubDate><author>wyz2016zxc@outlook.com(Hiraeth)</author><guid>https://hiraethecho.github.io/docs/project/hugo-theme-log/</guid><description>写hugo主题时候的一些记录</description><content:encoded><![CDATA[<h1 id="开发记录">
  <a class="anchor inpage" href="#%e5%bc%80%e5%8f%91%e8%ae%b0%e5%bd%95">#</a>开发记录</h1>
<h2 id="一阶段">
  <a class="anchor inpage" href="#%e4%b8%80%e9%98%b6%e6%ae%b5">##</a>一阶段</h2>
<p>用 hugo new theme生成的样子，复制了一些文章做测试。这里加了文件树的功能，用AI写的，完全不懂go template
<figure>
  <a
    href="https://asset.877675.xyz/1.webp"
    class="img-link"
    data-sub-html=""
    target="_blank"
  >
    <img
      src="https://asset.877675.xyz/1.webp"
      alt=""loading="lazy"
    />
  </a></figure>
</p>
<p>然后开始做css，先分了区，为了前期方便，随便加了background color，太刺激了
<figure>
  <a
    href="https://asset.877675.xyz/2.webp"
    class="img-link"
    data-sub-html=""
    target="_blank"
  >
    <img
      src="https://asset.877675.xyz/2.webp"
      alt=""loading="lazy"
    />
  </a></figure>
</p>
<p>用details而不是ul，加了点button
<figure>
  <a
    href="https://asset.877675.xyz/3.webp"
    class="img-link"
    data-sub-html=""
    target="_blank"
  >
    <img
      src="https://asset.877675.xyz/3.webp"
      alt=""loading="lazy"
    />
  </a></figure>
</p>
<p>太刺眼了，换颜色了。稍微搞了点响应式，微调一点css，加了代码复制按钮之类的功能。
<figure>
  <a
    href="https://asset.877675.xyz/4.webp"
    class="img-link"
    data-sub-html=""
    target="_blank"
  >
    <img
      src="https://asset.877675.xyz/4.webp"
      alt=""loading="lazy"
    />
  </a></figure>
</p>
<p>一边加各种layout里的功能，一边调css，打算确定颜色风格
<figure>
  <a
    href="https://asset.877675.xyz/5.webp"
    class="img-link"
    data-sub-html=""
    target="_blank"
  >
    <img
      src="https://asset.877675.xyz/5.webp"
      alt=""loading="lazy"
    />
  </a></figure>
</p>
<p>加了callouts等，打算用柔和一点的阴影类的装饰，用更少颜色
<figure>
  <a
    href="https://asset.877675.xyz/6.webp"
    class="img-link"
    data-sub-html=""
    target="_blank"
  >
    <img
      src="https://asset.877675.xyz/6.webp"
      alt=""loading="lazy"
    />
  </a></figure>
</p>
<p>开始无休止的微调。
<figure>
  <a
    href="https://asset.877675.xyz/7.webp"
    class="img-link"
    data-sub-html=""
    target="_blank"
  >
    <img
      src="https://asset.877675.xyz/7.webp"
      alt=""loading="lazy"
    />
  </a></figure>
</p>
<h2 id="实装">
  <a class="anchor inpage" href="#%e5%ae%9e%e8%a3%85">##</a>实装</h2>
<p>基本上开始使用，加了评论、搜索，偶尔调一调样式和bug。<br>
以及名称换成了lichtung而不是glade。</p>
<h2 id="稳定">
  <a class="anchor inpage" href="#%e7%a8%b3%e5%ae%9a">##</a>稳定</h2>
<p>2026-03-16 又翻出这个log，发现已经很久没有动主题了，算是稳定了。<br>
有闲情逸致的时候写个文档吧。<br>
没有文档的
，也不是不能用。</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>niri</title><link>https://hiraethecho.github.io/docs/linux/niri/</link><pubDate>Tue, 02 Dec 2025 00:00:00 +0000</pubDate><author>wyz2016zxc@outlook.com(Hiraeth)</author><guid>https://hiraethecho.github.io/docs/linux/niri/</guid><description>wayland下paper scroll 的 wm</description><content:encoded><![CDATA[<h1 id="滚动式窗口管理器niri">
  <a class="anchor inpage" href="#%e6%bb%9a%e5%8a%a8%e5%bc%8f%e7%aa%97%e5%8f%a3%e7%ae%a1%e7%90%86%e5%99%a8niri">#</a>滚动式窗口管理器niri</h1>
<p>长期使用dwm作为X11下的窗口管理器，一直想找一个舒服wayland下窗口管理器试试。hyprland太重了，dwl没力气再写了，river太像了，sway不习惯。<br>
最后发现了niri，水平滚动式WM，非常有趣好用。</p>
<h2 id="特点">
  <a class="anchor inpage" href="#%e7%89%b9%e7%82%b9">##</a>特点</h2>
<p>某种意义上niri是<em>反</em>窗口管理器：不管理窗口，就一排铺开。</p>
<ul>
<li>最大的优点应该是窗口不会变化大小和位置。</li>
<li>我用dwm时主要用monocle布局，并且尽量放在不同tag下（dwm的tag类似于工作区），通过切换tag来切换窗口。少数需要同时查看多个窗口时才会用grid或tile布局。<br>
在niri下用named workspace可以实现相同效果，并且更符合直觉，就像在一个大桌子上摊开文件一样。</li>
<li>另一个优势是niri的逻辑很适合触控板，在外出无鼠标使用笔记本的场景非常舒服。</li>
</ul>
<h2 id="set-up">
  <a class="anchor inpage" href="#set-up">##</a>set-up</h2>
<p>各种配置文档和实例已经很多了，所以只列出我选择的搭配的组合：</p>
<ul>
<li>niri</li>
<li>dms/noctalia</li>
<li>rofi</li>
<li>foot</li>
</ul>
<p>然后是我倾向的设定：</p>
<ul>
<li>虽然niri推荐动态工作区，但我还是习惯named space，所以用dms和noctalia这种quick-shell系的组件作为bar（waybar用不习惯）</li>
<li>我习惯少一点快捷键，不介意稍微多按几下，所以只使用
<details open>
    <summary>TEXT</summary><pre
        class="codeblock"
      ><code class="language-" data-lang="">    Super&#43;H {
        consume-or-expel-window-left
    }
    Super&#43;L {
        consume-or-expel-window-right
    }
    Super&#43;J {
        move-window-down-or-to-workspace-down
    }
    Super&#43;K {
        move-window-up-or-to-workspace-up
    }</code><button onclick="copyCode(this)" class="copybtn">copy</button></pre></details>

  <script>
    function copyCode(btn) {
      const code = btn.previousElementSibling.textContent.trim();
      navigator.clipboard.writeText(code).then(() => {
        btn.innerText = "copied";
        setTimeout(() => (btn.innerText = "copy"), 2000);
      });
    }
  </script>而且基本不用移动workspace或column的操作</li>
<li>使用rofi是因为X11下也可以用，保持一点一致性。</li>
</ul>
<h2 id="dot">
  <a class="anchor inpage" href="#dot">##</a>dot</h2>
<p>我的具体配置可以参考我的
，使用stow管理。<br>
niri相关的文件在<code>wm/.config/niri</code>，rofi相关的配置（没有整理）在<code>tools/.config/rofi</code>和<code>bin/.local/bin/</code></p>
]]></content:encoded></item><item><title>我的工具</title><link>https://hiraethecho.github.io/docs/tools/</link><pubDate>Tue, 02 Dec 2025 00:00:00 +0000</pubDate><author>wyz2016zxc@outlook.com(Hiraeth)</author><guid>https://hiraethecho.github.io/docs/tools/</guid><description>我使用的工具</description><content:encoded><![CDATA[<h1 id="我的工具">
  <a class="anchor inpage" href="#%e6%88%91%e7%9a%84%e5%b7%a5%e5%85%b7">#</a>我的工具</h1>
<h2 id="on-my-archlinux">
  <a class="anchor inpage" href="#on-my-archlinux">##</a>On My Archlinux</h2>
<p>我使用archlinux发行版，在X11下使用dwm，在wayland下使用niri。常用st, kitty, foot 作为terminal。编辑器是neovim，偶尔使用zed。<br>
或者可以这样展示 <code>:r! pacman -Qqe</code></p>
<details
      class="alert alert-note"
      >
      <summary class="alert-heading">pacman -Qqe</summary><p>7zip
accountsservice
aconfmgr-git
acpi
acpilight
aerc
alsa-utils
amd-ucode
archlinuxcn-keyring
atuin
autossh
awesome-terminal-fonts
base
base-devel
bash-language-server
bat
bc
bluetui
bluez-tools
bluez-utils
brightnessctl
btop
btrfs-assistant
btrfs-progs
buku
bun
cava
clang
cliphist
cloudflared
cups
ddcutil
deepseek-pake
dhcpcd
dmenu
dms-shell-bin
dua-cli
dunst
efibootmgr
emmylua-ls-bin
eza
fastfetch
fbterm
fcitx5
fcitx5-chinese-addons
fcitx5-configtool
fcitx5-gtk
fcitx5-pinyin-zhwiki
fcitx5-qt
fd
feh
ffmpeg4.4
flameshot
flomo-pake
foot
fzf
fzf-tab-git
git
github-cli
github-copilot
gnome-keyring
gparted
grub
grub-btrfs
gvfs
gvfs-dnssd
harper
hugo
imagemagick
impala
iw
iwd
kdlfmt
keifu-bin
keyd
khal
kitty
koofr-desktop-bin
lazygit
less
lib32-mesa
lib32-vulkan-radeon
libnotify
librepods
libxml2-legacy
libzip
linux
linux-firmware-amdgpu
linux-firmware-atheros
linux-firmware-other
linux-headers
linux-wifi-hotspot
lua-language-server
maim
marksman
mate-polkit
mcat-bin
mpc
mpd
mpv
mupdf
ncmpcpp
neovim
net-tools
newsboat
niri
noctalia-shell
nodejs
noto-fonts-emoji
npm
ntfs-3g
obsidian
openssh
os-prober
otf-codenewroman-nerd
otf-maplemono
pacman-contrib
pamixer
paru
pavucontrol-gtk3
pcmanfm
picgo
pipewire
pipewire-alsa
pipewire-audio
pipewire-pulse
power-profiles-daemon
python-pynvim
qbittorrent
rar
rclone
rime-emoji
ripgrep
rmpc
rocm-smi-lib
rofi
shellcheck-bin
shfmt
sioyek
snapper
stacer
starship
stow
stylua
sudo
sx
taplo-cli
task
tealdeer
tex-fmt
texlab
texlive-bibtexextra
texlive-binextra
texlive-langchinese
texlive-latexextra
texlive-mathscience
texlive-pstricks
texlive-xetex
timeshift
tinymist
todoman
tree-sitter
ttf-daddytime-mono-nerd
ttf-ibm-plex
ttf-lxgw-wenkai-mono
ttf-monaco-nerd-font-git
ttf-nerd-fonts-symbols-mono
typst
ufrii-print
unzip
uv
vdirsyncer
vscode-css-languageserver
vulkan-radeon
waterfox-bin
watt-toolkit-bin
websocat
wechat-bin
wemeet-bin
weread-pake
wget
wiremix
wireplumber
wl-clipboard
wlsunset
xbindkeys
xclip
xdg-desktop-portal
xdg-ninja-git
xdg-user-dirs-gtk
xdotool
xf86-video-amdgpu
xhidecursor
xorg-server
xorg-server-xephyr
xorg-xhost
xorg-xinit
xorg-xinput
xorg-xsetroot
xorg-xwayland
xwayland-satellite
yay
yazi
yutto
zathura
zathura-djvu
zathura-pdf-mupdf
zip
zotero
zoxide
zram-generator
zsh
zsh-autosuggestions
zsh-fast-syntax-highlighting</p></details><h2 id="dev">
  <a class="anchor inpage" href="#dev">##</a>Dev</h2>
]]></content:encoded></item><item><title>Now</title><link>https://hiraethecho.github.io/docs/now/</link><pubDate>Tue, 25 Nov 2025 00:00:00 +0000</pubDate><author>wyz2016zxc@outlook.com(Hiraeth)</author><guid>https://hiraethecho.github.io/docs/now/</guid><description>我正在做什么</description><content:encoded><![CDATA[<h1 id="now">
  <a class="anchor inpage" href="#now">#</a>Now</h1>
<p>现在在做的事</p>
<h2 id="docs">
  <a class="anchor inpage" href="#docs">##</a>docs</h2>
<p>要在本站写的</p>
<h3 id="dev">
  <a class="anchor inpage" href="#dev">###</a>dev</h3>
<ul>
<li><input disabled="" type="checkbox"> html css js</li>
<li><input disabled="" type="checkbox"> json yaml toml</li>
<li><input disabled="" type="checkbox"> lua</li>
<li><input checked="" disabled="" type="checkbox"> latex</li>
</ul>
<h3 id="software">
  <a class="anchor inpage" href="#software">###</a>software</h3>
<p>汇总一下在用的软件</p>
<h2 id="计划做的项目">
  <a class="anchor inpage" href="#%e8%ae%a1%e5%88%92%e5%81%9a%e7%9a%84%e9%a1%b9%e7%9b%ae">##</a>计划做的项目</h2>
<p>math site</p>
<p>hugo theme</p>
<h2 id="ref">
  <a class="anchor inpage" href="#ref">##</a>ref</h2>
<!--
https://wogong.net/blog/now/
https://rexarski.com/now/
-->
]]></content:encoded></item><item><title>linux手册</title><link>https://hiraethecho.github.io/docs/linux/linux-handbook/</link><pubDate>Sat, 25 Oct 2025 00:00:00 +0000</pubDate><author>wyz2016zxc@outlook.com(Hiraeth)</author><guid>https://hiraethecho.github.io/docs/linux/linux-handbook/</guid><description>&lt;h1 id="linux-handbook"&gt;
&lt;a class="anchor inpage" href="#linux-handbook"&gt;#&lt;/a&gt;Linux Handbook&lt;/h1&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;bash &amp;lt;(curl -sSL https://linuxmirrors.cn/main.sh)&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;bash &amp;lt;(curl -sSL https://linuxmirrors.cn/docker.sh)&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;bash &amp;lt;(curl -sSL https://linuxmirrors.cn/docker.sh) --only-registry&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="file"&gt;
&lt;a class="anchor inpage" href="#file"&gt;##&lt;/a&gt;file&lt;/h2&gt;
&lt;p&gt;&lt;code&gt;filedialog&lt;/code&gt; 是其他应用需要选择文件时的弹窗&lt;/p&gt;</description><content:encoded><![CDATA[<h1 id="linux-handbook">
  <a class="anchor inpage" href="#linux-handbook">#</a>Linux Handbook</h1>
<p>
</p>
<details open>
    <summary>TEXT</summary><pre
        class="codeblock"
      ><code class="language-" data-lang="">bash &lt;(curl -sSL https://linuxmirrors.cn/main.sh)</code><button onclick="copyCode(this)" class="copybtn">copy</button></pre></details>

  <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="">bash &lt;(curl -sSL https://linuxmirrors.cn/docker.sh)</code><button onclick="copyCode(this)" class="copybtn">copy</button></pre></details>

  <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="">bash &lt;(curl -sSL https://linuxmirrors.cn/docker.sh) --only-registry</code><button onclick="copyCode(this)" class="copybtn">copy</button></pre></details>

  <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="file">
  <a class="anchor inpage" href="#file">##</a>file</h2>
<p><code>filedialog</code> 是其他应用需要选择文件时的弹窗</p>
<h2 id="boot">
  <a class="anchor inpage" href="#boot">##</a>boot</h2>
<h2 id="display-manager">
  <a class="anchor inpage" href="#display-manager">##</a>display manager</h2>
<p>lightdm 有一堆莫名其妙的问题</p>
<p>gtk display还不知道怎么搞</p>
<h2 id="keyring">
  <a class="anchor inpage" href="#keyring">##</a>keyring</h2>
<p>
</p>
<p>use <code>gnome-keyring</code> and <code>thunar</code> to auto connect a webdav.

</p>
<h2 id="reference">
  <a class="anchor inpage" href="#reference">##</a>Reference</h2>
<p>
</p>
<h2 id="commands">
  <a class="anchor inpage" href="#commands">##</a>commands</h2>
<details open>
    <summary>sh</summary><pre
        class="chroma codeblock"
      ><code class="language-sh" data-lang="sh"
          ><span style="display:flex;"><span>type something</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>example</p>
<details open>
    <summary>sh</summary><pre
        class="chroma codeblock"
      ><code class="language-sh" data-lang="sh"
          ><span style="display:flex;"><span>type cd
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span>cd is a shell builtin</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="技巧">
  <a class="anchor inpage" href="#%e6%8a%80%e5%b7%a7">##</a>技巧</h2>
<details open>
    <summary>tldr</summary><pre
        class="codeblock"
      ><code class="language-tldr" data-lang="tldr">  Change attributes of files or directories.
  More information: &lt;https://manned.org/chattr&gt;.

  Make a file or directory [i]mmutable to changes and deletion, even by superuser:

      chattr &#43;i path/to/file_or_directory

  Make a file or directory mutable:

      chattr -i path/to/file_or_directory

  [R]ecursively make an entire directory and contents immutable:

      chattr -R &#43;i path/to/directory

  Mark a directory and its files to be interpreted in a case-insensitive manner (case-[F]olding):

      chattr &#43;F path/to/directory

  Set a file to only allow [a]ppending:

      chattr &#43;a 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>]]></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>关于</title><link>https://hiraethecho.github.io/docs/about/</link><pubDate>Wed, 22 Oct 2025 00:00:00 +0000</pubDate><author>wyz2016zxc@outlook.com(Hiraeth)</author><guid>https://hiraethecho.github.io/docs/about/</guid><description>本站和其他网站</description><content:encoded><![CDATA[<h1 id="介绍">
  <a class="anchor inpage" href="#%e4%bb%8b%e7%bb%8d">#</a>介绍</h1>
<p>一个非程序员的计算机技术文档网站。</p>
<p>本站使用hugo自制主题
。文档还没写。</p>
<p>我的博客在
，数学笔记在
。</p>
<p>其他旧网站：</p>
<ul>
<li>
</li>
<li>
</li>
<li>
</li>
</ul>
]]></content:encoded></item><item><title>hugo主题lichtung</title><link>https://hiraethecho.github.io/docs/project/example/</link><pubDate>Sun, 05 Oct 2025 00:00:00 +0000</pubDate><author>wyz2016zxc@outlook.com(Hiraeth)</author><guid>https://hiraethecho.github.io/docs/project/example/</guid><description>&lt;h1 id="my-hugo-theme"&gt;
&lt;a class="anchor inpage" href="#my-hugo-theme"&gt;#&lt;/a&gt;My hugo theme&lt;/h1&gt;
&lt;p&gt;&lt;figure&gt;
&lt;a
href="https://asset.877675.xyz/202510101905530.webp"
class="img-link"
data-sub-html=""
target="_blank"
&gt;
&lt;img
src="https://asset.877675.xyz/202510101905530.webp"
alt=""loading="lazy"
/&gt;
&lt;/a&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p&gt;some thing.&lt;br&gt;
another line
a
&lt;/p&gt;
&lt;h2 id="titles"&gt;
&lt;a class="anchor inpage" href="#titles"&gt;##&lt;/a&gt;titles&lt;/h2&gt;
&lt;h3 id="h3"&gt;
&lt;a class="anchor inpage" href="#h3"&gt;###&lt;/a&gt;h3&lt;/h3&gt;
&lt;h4 id="h4"&gt;
&lt;a class="anchor inpage" href="#h4"&gt;####&lt;/a&gt;h4&lt;/h4&gt;
&lt;h5 id="h5"&gt;
&lt;a class="anchor inpage" href="#h5"&gt;#####&lt;/a&gt;h5&lt;/h5&gt;
&lt;h6 id="h6"&gt;
&lt;a class="anchor inpage" href="#h6"&gt;######&lt;/a&gt;h6&lt;/h6&gt;
&lt;h2 id="fonts"&gt;
&lt;a class="anchor inpage" href="#fonts"&gt;##&lt;/a&gt;fonts&lt;/h2&gt;
&lt;p&gt;&lt;strong&gt;bold text&lt;/strong&gt; and &lt;em&gt;italic text&lt;/em&gt;. and both &lt;strong&gt;&lt;em&gt;bold and italic&lt;/em&gt;&lt;/strong&gt; and &lt;em&gt;&lt;strong&gt;jlkfas&lt;/strong&gt;&lt;/em&gt;&lt;/p&gt;
&lt;p&gt;try some thing new: &lt;del&gt;delete&lt;/del&gt;, &lt;ins&gt;insert&lt;/ins&gt;, &lt;mark&gt;mark&lt;/mark&gt;, superscript&lt;sup&gt;2&lt;/sup&gt; and subscript&lt;sub&gt;2&lt;/sub&gt;&lt;/p&gt;
&lt;p&gt;some Typographer&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;... &amp;amp;hellip; horizontal ellipsis
' &amp;amp;rsquo; apostrophe
-- &amp;amp;ndash; en dash
--- &amp;amp;mdash; em dash
« &amp;amp;laquo; left angle quote
“ &amp;amp;ldquo; left double quote
‘ &amp;amp;lsquo; left single quote
» &amp;amp;raquo; right angle quote
” &amp;amp;rdquo; right double quote
’ &amp;amp;rsquo; right single quote
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;as&lt;/p&gt;</description><content:encoded><![CDATA[<h1 id="my-hugo-theme">
  <a class="anchor inpage" href="#my-hugo-theme">#</a>My hugo theme</h1>
<p><figure>
  <a
    href="https://asset.877675.xyz/202510101905530.webp"
    class="img-link"
    data-sub-html=""
    target="_blank"
  >
    <img
      src="https://asset.877675.xyz/202510101905530.webp"
      alt=""loading="lazy"
    />
  </a></figure>
</p>
<p>some thing.<br>
another line
a 
</p>
<h2 id="titles">
  <a class="anchor inpage" href="#titles">##</a>titles</h2>
<h3 id="h3">
  <a class="anchor inpage" href="#h3">###</a>h3</h3>
<h4 id="h4">
  <a class="anchor inpage" href="#h4">####</a>h4</h4>
<h5 id="h5">
  <a class="anchor inpage" href="#h5">#####</a>h5</h5>
<h6 id="h6">
  <a class="anchor inpage" href="#h6">######</a>h6</h6>
<h2 id="fonts">
  <a class="anchor inpage" href="#fonts">##</a>fonts</h2>
<p><strong>bold text</strong> and <em>italic text</em>. and both <strong><em>bold and italic</em></strong> and <em><strong>jlkfas</strong></em></p>
<p>try some thing new: <del>delete</del>, <ins>insert</ins>, <mark>mark</mark>, superscript<sup>2</sup> and subscript<sub>2</sub></p>
<p>some Typographer</p>
<pre><code>... &amp;hellip;    horizontal ellipsis
'   &amp;rsquo; apostrophe
--  &amp;ndash; en dash
--- &amp;mdash; em dash
«   &amp;laquo; left angle quote
“   &amp;ldquo; left double quote
‘   &amp;lsquo; left single quote
»   &amp;raquo; right angle quote
”   &amp;rdquo; right double quote
’   &amp;rsquo; right single quote
</code></pre>
<p>as</p>
<p>&hellip; … horizontal ellipsis
&rsquo; ’ apostrophe
&ndash; – en dash
&mdash; — em dash
« « left angle quote
“ “ left double quote
‘ ‘ left single quote
» » right angle quote
” ” right double quote
’ ’ right single quote</p>
<h2 id="callouts">
  <a class="anchor inpage" href="#callouts">##</a>callouts</h2>
<p>some text</p>
<blockquote class="alert alert-note">
      <p class="alert-heading">a</p></blockquote><p>and other</p>
<blockquote class="alert alert-tip">
      <p class="alert-heading">b</p></blockquote><blockquote class="alert alert-important">
      <p class="alert-heading">重要</p></blockquote><blockquote class="alert alert-warning">
      <p class="alert-heading">WARNING</p><p>hell</p></blockquote><blockquote class="alert alert-caution">
      <p class="alert-heading">CAUTION</p><p>waow</p>
<blockquote class="alert alert-warning">
      <p class="alert-heading">WARNING</p><p>nested</p></blockquote><p>blocks</p></blockquote><h3 id="blockquotes">
  <a class="anchor inpage" href="#blockquotes">###</a>blockquotes</h3>
<blockquote class="alert"><p>just<br>
a quote</p>
</blockquote><p>nest</p>
<blockquote class="alert"><p>nest</p>
<blockquote class="alert"><p>anoth</p>
</blockquote></blockquote><p>and</p>
<blockquote class="alert"><p>nest</p>
<blockquote class="alert"><p>anoth</p>
</blockquote><p>a</p>
</blockquote><h2 id="latex">
  <a class="anchor inpage" href="#latex">##</a>latex</h2>
<p>行间</p>
<pre><code>\[
\mathrm{e}^{\theta \mathrm{i}} = \cos \theta + \mathrm{i}\sin \theta
\]
</code></pre>
<p>和</p>
<pre><code>\[
\mathcal{E}=\mathcal{O}^{\oplus n} \rightarrow \mathcal{F}
\]
</code></pre>
<p>为
</p>
\[
\mathrm{e}^{\theta \mathrm{i}} = \cos \theta + \mathrm{i}\sin \theta
\]<p>
和
</p>
\[
\mathcal{E}=\mathcal{O}^{\oplus n} \rightarrow \mathcal{F}
\]<p>
行中 <code>$E=mc^2$</code> 和 <code>\(E=mc^2\)</code> 为 $E=mc^2$ 和 \(E=mc^2\)</p>
<h2 id="footnotes">
  <a class="anchor inpage" href="#footnotes">##</a>footnotes</h2>
<p>some text.<sup id="fnref:1"><a href="#fn:1" class="footnote-ref" role="doc-noteref">1</a></sup> And named footnote<sup id="fnref:2"><a href="#fn:2" class="footnote-ref" role="doc-noteref">2</a></sup> another footnote<sup id="fnref:3"><a href="#fn:3" class="footnote-ref" role="doc-noteref">3</a></sup> what if <sup id="fnref1:1"><a href="#fn:1" class="footnote-ref" role="doc-noteref">1</a></sup> same one.</p>
<h2 id="forms">
  <a class="anchor inpage" href="#forms">##</a>forms</h2>
<p>select 跳转</p>
<pre><code>&lt;select onchange=&quot;location = this.value;&quot;&gt;
&lt;option value=&quot;&quot;&gt;导航菜单&lt;/option&gt;
&lt;option value=&quot;/&quot;&gt;首页&lt;/option&gt;
&lt;option value=&quot;/glade&quot;&gt;关于&lt;/option&gt;
&lt;/select&gt;
</code></pre>
<select onchange="location = this.value;">
  <option value="">导航菜单</option>
  <option value="/">首页</option>
  <option value="/about">关于</option>
</select>
<details><summary>details</summary>
<ul>
  <li>nested</li>
  <li> ul </li>
</ul>
</details>
<h2 id="lists">
  <a class="anchor inpage" href="#lists">##</a>lists</h2>
<p>some texts</p>
<ul>
<li>askjdfk</li>
<li>jklasdf
<ul>
<li>nested
<ol>
<li>mixed type</li>
<li>ok</li>
</ol>
</li>
<li>sdajfl</li>
</ul>
</li>
<li>laksdfjlk</li>
</ul>
<p>ok, then another list</p>
<ol>
<li>i do</li>
<li>not</li>
</ol>
<h2 id="codes">
  <a class="anchor inpage" href="#codes">##</a>codes</h2>
<h3 id="inline-codes">
  <a class="anchor inpage" href="#inline-codes">###</a>inline codes</h3>
<p>asdfjlk <code>ajsdfj</code> sdjfakl</p>
<h3 id="code-fences">
  <a class="anchor inpage" href="#code-fences">###</a>code fences</h3>
<p>iolkjlkasdf</p>
<details open>
    <summary>bash</summary><pre
        class="chroma codeblock"
      ><code class="language-bash" data-lang="bash"
          ><span style="display:flex;"><span><span style="color:#75715e">#!/bin/bash --noprofile --norc
</span></span></span><span style="display:flex;"><span><span style="color:#75715e"></span>export MY_VARIABLE<span style="color:#f92672">=</span><span style="color:#e6db74">&#34;value&#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><details open>
    <summary>TEXT</summary><pre
        class="codeblock"
      ><code class="language-" data-lang="">#!/bin/bash --noprofile --norc
export MY_VARIABLE=&#34;value&#34;
echo &#34;Current PATH: $PATH&#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>this is confusing</p>
<pre><code>#!/bin/bash --noprofile --norc
export MY_VARIABLE=&quot;value&quot;
echo &quot;Current PATH: $PATH&quot;
</code></pre>
<h3 id="pre">
  <a class="anchor inpage" href="#pre">###</a>pre</h3>
<pre><code>       一剪梅·舟过吴江 蒋捷
一片春愁待酒浇。江上舟摇，楼上帘招。
秋娘渡与泰娘桥，风又飘飘，雨又萧萧。
何日归家洗客袍？银字笙调，心字香烧。
流光容易把人抛，红了樱桃，绿了芭蕉。
</code></pre>
<hr>
<h2 id="table">
  <a class="anchor inpage" href="#table">##</a>table</h2>
<table>
  <thead>
      <tr>
          <th>ajksldf</th>
          <th>dsf</th>
          <th>dfs</th>
      </tr>
  </thead>
  <tbody>
      <tr>
          <td>dfs</td>
          <td>dfs</td>
          <td>dfsx</td>
      </tr>
      <tr>
          <td>ss</td>
          <td>eet</td>
          <td>zzz</td>
      </tr>
      <tr>
          <td>dsfwe</td>
          <td>dsfb</td>
          <td>we</td>
      </tr>
  </tbody>
</table>
<h2 id="plain-text">
  <a class="anchor inpage" href="#plain-text">##</a>plain text</h2>
<p>ok Let me see.</p>
<div class="footnotes" role="doc-endnotes">
<hr>
<ol>
<li id="fn:1">
<p>what is this&#160;<a href="#fnref:1" class="footnote-backref" role="doc-backlink">&#x21a9;&#xfe0e;</a>&#160;<a href="#fnref1:1" class="footnote-backref" role="doc-backlink">&#x21a9;&#xfe0e;</a></p>
</li>
<li id="fn:2">
<p>a footnote with name.&#160;<a href="#fnref:2" class="footnote-backref" role="doc-backlink">&#x21a9;&#xfe0e;</a></p>
</li>
<li id="fn:3">
<p>another footnote&#160;<a href="#fnref:3" class="footnote-backref" role="doc-backlink">&#x21a9;&#xfe0e;</a></p>
</li>
</ol>
</div>
]]></content:encoded></item><item><title>latex基本概念</title><link>https://hiraethecho.github.io/docs/software/latex/</link><pubDate>Mon, 25 Aug 2025 00:00:00 +0000</pubDate><author>wyz2016zxc@outlook.com(Hiraeth)</author><guid>https://hiraethecho.github.io/docs/software/latex/</guid><description>&lt;h1 id="latex概览"&gt;
&lt;a class="anchor inpage" href="#latex%e6%a6%82%e8%a7%88"&gt;#&lt;/a&gt;latex概览&lt;/h1&gt;
&lt;h2 id="tex-和-latex"&gt;
&lt;a class="anchor inpage" href="#tex-%e5%92%8c-latex"&gt;##&lt;/a&gt;tex 和 latex&lt;/h2&gt;
&lt;h3 id="1-tex底层排版引擎"&gt;
&lt;a class="anchor inpage" href="#1-tex%e5%ba%95%e5%b1%82%e6%8e%92%e7%89%88%e5%bc%95%e6%93%8e"&gt;###&lt;/a&gt;&lt;strong&gt;1. TeX：底层排版引擎&lt;/strong&gt;&lt;/h3&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;作者&lt;/strong&gt;：Donald Knuth（高德纳）开发，1978 年发布。&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;定位&lt;/strong&gt;：
&lt;ul&gt;
&lt;li&gt;是一个&lt;strong&gt;底层的排版编程语言&lt;/strong&gt;，提供精确的排版控制（如盒模型、断行算法、数学公式布局等）。&lt;/li&gt;
&lt;li&gt;语法类似编程（需手动处理格式细节），适合专业人士或极客。&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;特点&lt;/strong&gt;：
&lt;ul&gt;
&lt;li&gt;直接操作命令（如 &lt;code&gt;\hbox&lt;/code&gt;, &lt;code&gt;\vskip&lt;/code&gt;）。&lt;/li&gt;
&lt;li&gt;默认生成 &lt;code&gt;.dvi&lt;/code&gt; 文件（需转换为 PDF/PS）。&lt;/li&gt;
&lt;li&gt;无预定义的高层结构（如章节、目录需手动实现）。&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;&lt;strong&gt;示例（纯 TeX 代码）&lt;/strong&gt;：&lt;/p&gt;</description><content:encoded><![CDATA[<h1 id="latex概览">
  <a class="anchor inpage" href="#latex%e6%a6%82%e8%a7%88">#</a>latex概览</h1>
<h2 id="tex-和-latex">
  <a class="anchor inpage" href="#tex-%e5%92%8c-latex">##</a>tex 和 latex</h2>
<h3 id="1-tex底层排版引擎">
  <a class="anchor inpage" href="#1-tex%e5%ba%95%e5%b1%82%e6%8e%92%e7%89%88%e5%bc%95%e6%93%8e">###</a><strong>1. TeX：底层排版引擎</strong></h3>
<ul>
<li><strong>作者</strong>：Donald Knuth（高德纳）开发，1978 年发布。</li>
<li><strong>定位</strong>：
<ul>
<li>是一个<strong>底层的排版编程语言</strong>，提供精确的排版控制（如盒模型、断行算法、数学公式布局等）。</li>
<li>语法类似编程（需手动处理格式细节），适合专业人士或极客。</li>
</ul>
</li>
<li><strong>特点</strong>：
<ul>
<li>直接操作命令（如 <code>\hbox</code>, <code>\vskip</code>）。</li>
<li>默认生成 <code>.dvi</code> 文件（需转换为 PDF/PS）。</li>
<li>无预定义的高层结构（如章节、目录需手动实现）。</li>
</ul>
</li>
</ul>
<p><strong>示例（纯 TeX 代码）</strong>：</p>
<details open>
    <summary>tex</summary><pre
        class="chroma codeblock"
      ><code class="language-tex" data-lang="tex"
          ><span style="display:flex;"><span><span style="color:#66d9ef">\font\myfont</span>=cmr12 at 14pt
</span></span><span style="display:flex;"><span><span style="color:#66d9ef">\myfont</span> Hello, <span style="color:#66d9ef">\TeX</span>!
</span></span><span style="display:flex;"><span><span style="color:#66d9ef">\bye</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="2-latex基于-tex-的高级封装">
  <a class="anchor inpage" href="#2-latex%e5%9f%ba%e4%ba%8e-tex-%e7%9a%84%e9%ab%98%e7%ba%a7%e5%b0%81%e8%a3%85">###</a><strong>2. LaTeX：基于 TeX 的高级封装</strong></h3>
<ul>
<li><strong>作者</strong>：Leslie Lamport（莱斯利·兰波特）开发，1984 年发布。</li>
<li><strong>定位</strong>：
<ul>
<li>是 <strong>TeX 的宏包集合</strong>（一组预定义的命令和模板），提供<strong>文档逻辑结构</strong>（如章节、参考文献、交叉引用）。</li>
<li>隐藏了 TeX 的底层复杂性，用户只需关注内容。</li>
</ul>
</li>
<li><strong>特点</strong>：
<ul>
<li>提供标准文档类（如 <code>article</code>, <code>book</code>）。</li>
<li>内置自动化功能（目录、编号、参考文献管理）。</li>
<li>依赖宏包扩展功能（如 <code>graphicx</code> 插入图片、<code>amsmath</code> 增强数学公式）。</li>
</ul>
</li>
</ul>
<p><strong>示例（LaTeX 代码）</strong>：</p>
<details open>
    <summary>tex</summary><pre
        class="chroma codeblock"
      ><code class="language-tex" data-lang="tex"
          ><span style="display:flex;"><span><span style="color:#66d9ef">\documentclass</span>{article}
</span></span><span style="display:flex;"><span><span style="color:#66d9ef">\begin</span>{document}
</span></span><span style="display:flex;"><span><span style="color:#66d9ef">\section</span>{Introduction}
</span></span><span style="display:flex;"><span>Hello, <span style="color:#66d9ef">\LaTeX</span>!
</span></span><span style="display:flex;"><span><span style="color:#66d9ef">\end</span>{document}</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="核心区别">
  <a class="anchor inpage" href="#%e6%a0%b8%e5%bf%83%e5%8c%ba%e5%88%ab">###</a><strong>核心区别</strong></h3>
<table>
  <thead>
      <tr>
          <th>特性</th>
          <th>TeX</th>
          <th>LaTeX</th>
      </tr>
  </thead>
  <tbody>
      <tr>
          <td><strong>设计目标</strong></td>
          <td>底层排版控制</td>
          <td>高层文档结构</td>
      </tr>
      <tr>
          <td><strong>语法复杂度</strong></td>
          <td>复杂（类似编程）</td>
          <td>简单（声明式）</td>
      </tr>
      <tr>
          <td><strong>典型用户</strong></td>
          <td>排版系统开发者、极客</td>
          <td>学术作者、普通用户</td>
      </tr>
      <tr>
          <td><strong>扩展性</strong></td>
          <td>需手动实现一切</td>
          <td>通过宏包（如 <code>hyperref</code>）扩展</td>
      </tr>
      <tr>
          <td><strong>默认输出</strong></td>
          <td><code>.dvi</code></td>
          <td><code>.dvi</code> 或 <code>.pdf</code>（现代工具链）</td>
      </tr>
  </tbody>
</table>
<h3 id="类比解释">
  <a class="anchor inpage" href="#%e7%b1%bb%e6%af%94%e8%a7%a3%e9%87%8a">###</a><strong>类比解释</strong></h3>
<ul>
<li><strong>TeX 类似汇编语言</strong>：
<ul>
<li>直接控制硬件（排版细节），但编写复杂。</li>
</ul>
</li>
<li><strong>LaTeX 类似高级语言（如 Python）</strong>：
<ul>
<li>通过抽象（如 <code>\section</code>）隐藏细节，提升效率。</li>
</ul>
</li>
</ul>
<h3 id="技术关系">
  <a class="anchor inpage" href="#%e6%8a%80%e6%9c%af%e5%85%b3%e7%b3%bb">###</a><strong>技术关系</strong></h3>
<ul>
<li>LaTeX 本质是一组 TeX 宏（<code>.sty</code> 文件），最终仍由 TeX 引擎（如 <code>pdftex</code>, <code>xetex</code>, <code>luatex</code>）执行。</li>
<li>编译流程示例：
<details open>
    <summary>sh</summary><pre
        class="chroma codeblock"
      ><code class="language-sh" data-lang="sh"
          ><span style="display:flex;"><span>latex document.tex   <span style="color:#75715e"># 调用 pdftex 引擎处理 LaTeX 宏</span>
</span></span><span style="display:flex;"><span>xelatex document.tex <span style="color:#75715e"># 调用 xetex 引擎处理 LaTeX 宏</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>
<h3 id="总结">
  <a class="anchor inpage" href="#%e6%80%bb%e7%bb%93">###</a><strong>总结</strong></h3>
<ul>
<li><strong>TeX 是引擎，LaTeX 是模板</strong>。</li>
<li>LaTeX 让用户摆脱 TeX 的底层复杂性，专注于内容逻辑。</li>
<li>现代用户通常直接使用 <code>pdflatex</code>/<code>xelatex</code>/<code>lualatex</code>，无需接触原始 TeX 命令。</li>
</ul>
<p>如果需要进一步解释某个具体细节（如宏包机制或引擎差异），可以继续讨论！</p>
<h2 id="引擎和使用">
  <a class="anchor inpage" href="#%e5%bc%95%e6%93%8e%e5%92%8c%e4%bd%bf%e7%94%a8">##</a>引擎和使用</h2>
<h3 id="1-排版引擎engines">
  <a class="anchor inpage" href="#1-%e6%8e%92%e7%89%88%e5%bc%95%e6%93%8eengines">###</a><strong>1. 排版引擎（Engines）</strong></h3>
<p>引擎是实际执行排版工作的底层程序，负责解析代码、计算布局并生成输出文件（如 PDF/DVI）。<br>
<strong>属于引擎的有</strong>：</p>
<ul>
<li><code>tex</code>：Knuth 原始 TeX 引擎（生成 <code>.dvi</code>）。</li>
<li><code>pdftex</code>：扩展的 TeX 引擎，直接生成 PDF（<code>pdflatex</code> 的基础）。</li>
<li><code>xetex</code>（XeTeX）：支持 Unicode 和系统字体的引擎（<code>xelatex</code> 的基础）。</li>
<li><code>luatex</code>（LuaTeX）：内嵌 Lua 脚本的引擎（<code>lualatex</code> 的基础）。</li>
</ul>
<h3 id="2-模板格式formats">
  <a class="anchor inpage" href="#2-%e6%a8%a1%e6%9d%bf%e6%a0%bc%e5%bc%8fformats">###</a><strong>2. 模板/格式（Formats）</strong></h3>
<p>格式是基于引擎的预定义命令集合（宏包），提供高层抽象，简化用户操作。<br>
<strong>属于格式的有</strong>：</p>
<ul>
<li><code>latex</code>：LaTeX 格式（运行在 <code>pdftex</code>/<code>xetex</code>/<code>luatex</code> 等引擎上）。
<ul>
<li>不是独立引擎，而是通过 <code>latex</code> 命令调用引擎（如 <code>pdftex + LaTeX 宏</code> → <code>pdflatex</code>）。</li>
</ul>
</li>
<li><code>plain tex</code>：Knuth 提供的极简格式（比原始 TeX 稍友好，但远不如 LaTeX）。</li>
<li><code>contex</code>：另一种高级格式（基于 LuaTeX，适合复杂排版）。</li>
</ul>
<h3 id="3-前端命令frontends">
  <a class="anchor inpage" href="#3-%e5%89%8d%e7%ab%af%e5%91%bd%e4%bb%a4frontends">###</a><strong>3. 前端命令（Frontends）</strong></h3>
<p>用户直接调用的命令，本质是 <strong>“引擎 + 格式” 的组合</strong>：</p>
<table>
  <thead>
      <tr>
          <th>命令</th>
          <th>实际调用</th>
          <th>说明</th>
      </tr>
  </thead>
  <tbody>
      <tr>
          <td><code>latex</code></td>
          <td><code>pdftex + LaTeX 格式</code></td>
          <td>传统 LaTeX（DVI 输出）。</td>
      </tr>
      <tr>
          <td><code>pdflatex</code></td>
          <td><code>pdftex + LaTeX 格式</code></td>
          <td>直接生成 PDF（无 Unicode 支持）。</td>
      </tr>
      <tr>
          <td><code>xelatex</code></td>
          <td><code>xetex + LaTeX 格式</code></td>
          <td>支持 Unicode 和系统字体。</td>
      </tr>
      <tr>
          <td><code>lualatex</code></td>
          <td><code>luatex + LaTeX 格式</code></td>
          <td>支持 Lua 脚本和现代字体。</td>
      </tr>
  </tbody>
</table>
<h3 id="关键区分">
  <a class="anchor inpage" href="#%e5%85%b3%e9%94%ae%e5%8c%ba%e5%88%86">###</a><strong>关键区分</strong></h3>
<ul>
<li><strong>引擎</strong>：<code>tex</code>, <code>pdftex</code>, <code>xetex</code>, <code>luatex</code>（核心执行者）。</li>
<li><strong>格式</strong>：<code>latex</code>, <code>plain tex</code>, <code>contex</code>（定义高级命令的规则）。</li>
<li><strong>前端命令</strong>：<code>latex</code>, <code>pdflatex</code>, <code>xelatex</code>, <code>lualatex</code>（组合引擎和格式的快捷方式）。</li>
</ul>
<h3 id="常见误解澄清">
  <a class="anchor inpage" href="#%e5%b8%b8%e8%a7%81%e8%af%af%e8%a7%a3%e6%be%84%e6%b8%85">###</a><strong>常见误解澄清</strong></h3>
<ol>
<li><strong><code>latex</code> 不是引擎</strong>：
<ul>
<li>它是 LaTeX 格式通过 <code>pdftex</code> 引擎运行的接口（命令）。</li>
</ul>
</li>
<li><strong><code>pdflatex</code> vs <code>pdftex</code></strong>：
<ul>
<li><code>pdftex</code> 是引擎，<code>pdflatex</code> = <code>pdftex</code> + LaTeX 格式。</li>
</ul>
</li>
</ol>
<hr>
<h2 id="引擎engines">
  <a class="anchor inpage" href="#%e5%bc%95%e6%93%8eengines">##</a>引擎（Engines）</h2>
<h3 id="基础引擎">
  <a class="anchor inpage" href="#%e5%9f%ba%e7%a1%80%e5%bc%95%e6%93%8e">###</a>基础引擎</h3>
<table>
  <thead>
      <tr>
          <th>引擎名称</th>
          <th>特点</th>
          <th>输出格式</th>
          <th>主要用途</th>
      </tr>
  </thead>
  <tbody>
      <tr>
          <td><strong>tex</strong></td>
          <td>Knuth原始引擎，底层控制</td>
          <td>.dvi</td>
          <td>历史兼容、底层排版开发</td>
      </tr>
      <tr>
          <td><strong>pdftex</strong></td>
          <td>TeX的扩展，直接PDF输出</td>
          <td>.pdf</td>
          <td>传统LaTeX文档排版</td>
      </tr>
      <tr>
          <td><strong>xetex</strong> (XeTeX)</td>
          <td>支持Unicode和系统字体</td>
          <td>.xdv/.pdf</td>
          <td>多语言排版、系统字体支持</td>
      </tr>
      <tr>
          <td><strong>luatex</strong> (LuaTeX)</td>
          <td>内嵌Lua解释器，动态脚本</td>
          <td>.pdf</td>
          <td>复杂排版、自动化处理</td>
      </tr>
  </tbody>
</table>
<h3 id="引擎特性对比">
  <a class="anchor inpage" href="#%e5%bc%95%e6%93%8e%e7%89%b9%e6%80%a7%e5%af%b9%e6%af%94">###</a>引擎特性对比</h3>
<table>
  <thead>
      <tr>
          <th>特性</th>
          <th>tex</th>
          <th>pdftex</th>
          <th>xetex</th>
          <th>luatex</th>
      </tr>
  </thead>
  <tbody>
      <tr>
          <td>Unicode支持</td>
          <td>❌</td>
          <td>❌</td>
          <td>✔️</td>
          <td>✔️</td>
      </tr>
      <tr>
          <td>OpenType字体</td>
          <td>❌</td>
          <td>❌</td>
          <td>✔️</td>
          <td>✔️</td>
      </tr>
      <tr>
          <td>Lua脚本</td>
          <td>❌</td>
          <td>❌</td>
          <td>❌</td>
          <td>✔️</td>
      </tr>
      <tr>
          <td>系统字体</td>
          <td>❌</td>
          <td>❌</td>
          <td>✔️</td>
          <td>✔️</td>
      </tr>
      <tr>
          <td>输出格式</td>
          <td>DVI</td>
          <td>PDF</td>
          <td>XDV/PDF</td>
          <td>PDF</td>
      </tr>
  </tbody>
</table>
<h2 id="格式formats">
  <a class="anchor inpage" href="#%e6%a0%bc%e5%bc%8fformats">##</a>格式（Formats）</h2>
<h3 id="主要格式">
  <a class="anchor inpage" href="#%e4%b8%bb%e8%a6%81%e6%a0%bc%e5%bc%8f">###</a>主要格式</h3>
<table>
  <thead>
      <tr>
          <th>格式名称</th>
          <th>基于引擎</th>
          <th>特点</th>
          <th>适用场景</th>
      </tr>
  </thead>
  <tbody>
      <tr>
          <td><strong>plain tex</strong></td>
          <td>tex</td>
          <td>Knuth提供的极简格式</td>
          <td>底层TeX编程</td>
      </tr>
      <tr>
          <td><strong>latex</strong></td>
          <td>多引擎</td>
          <td>高级文档结构，宏包丰富</td>
          <td>学术论文、书籍、报告</td>
      </tr>
      <tr>
          <td><strong>contex</strong></td>
          <td>luatex</td>
          <td>模块化设计，强大功能</td>
          <td>复杂排版、图形密集型文档</td>
      </tr>
  </tbody>
</table>
<h2 id="前端命令frontend-commands">
  <a class="anchor inpage" href="#%e5%89%8d%e7%ab%af%e5%91%bd%e4%bb%a4frontend-commands">##</a>前端命令（Frontend Commands）</h2>
<h3 id="常用命令组合">
  <a class="anchor inpage" href="#%e5%b8%b8%e7%94%a8%e5%91%bd%e4%bb%a4%e7%bb%84%e5%90%88">###</a>常用命令组合</h3>
<table>
  <thead>
      <tr>
          <th>命令</th>
          <th>实际组成</th>
          <th>输出格式</th>
          <th>特点</th>
      </tr>
  </thead>
  <tbody>
      <tr>
          <td><code>tex</code></td>
          <td>tex + plain tex</td>
          <td>.dvi</td>
          <td>原始TeX排版</td>
      </tr>
      <tr>
          <td><code>latex</code></td>
          <td>pdftex + latex格式</td>
          <td>.dvi</td>
          <td>传统LaTeX处理</td>
      </tr>
      <tr>
          <td><code>pdflatex</code></td>
          <td>pdftex + latex格式</td>
          <td>.pdf</td>
          <td>直接PDF输出</td>
      </tr>
      <tr>
          <td><code>xelatex</code></td>
          <td>xetex + latex格式</td>
          <td>.pdf</td>
          <td>Unicode和字体支持</td>
      </tr>
      <tr>
          <td><code>lualatex</code></td>
          <td>luatex + latex格式</td>
          <td>.pdf</td>
          <td>Lua脚本+现代特性</td>
      </tr>
  </tbody>
</table>
<h2 id="文件格式">
  <a class="anchor inpage" href="#%e6%96%87%e4%bb%b6%e6%a0%bc%e5%bc%8f">##</a>文件格式</h2>
<h3 id="输入文件类型">
  <a class="anchor inpage" href="#%e8%be%93%e5%85%a5%e6%96%87%e4%bb%b6%e7%b1%bb%e5%9e%8b">###</a>输入文件类型</h3>
<table>
  <thead>
      <tr>
          <th>扩展名</th>
          <th>类型</th>
          <th>说明</th>
      </tr>
  </thead>
  <tbody>
      <tr>
          <td><code>.tex</code></td>
          <td>源文件</td>
          <td>TeX/LaTeX源代码</td>
      </tr>
      <tr>
          <td><code>.sty</code></td>
          <td>宏包文件</td>
          <td>LaTeX功能扩展包</td>
      </tr>
      <tr>
          <td><code>.cls</code></td>
          <td>文档类</td>
          <td>文档类型定义</td>
      </tr>
      <tr>
          <td><code>.bib</code></td>
          <td>参考文献</td>
          <td>BibTeX数据库文件</td>
      </tr>
  </tbody>
</table>
<h3 id="输出文件类型">
  <a class="anchor inpage" href="#%e8%be%93%e5%87%ba%e6%96%87%e4%bb%b6%e7%b1%bb%e5%9e%8b">###</a>输出文件类型</h3>
<table>
  <thead>
      <tr>
          <th>扩展名</th>
          <th>生成工具</th>
          <th>说明</th>
      </tr>
  </thead>
  <tbody>
      <tr>
          <td><code>.dvi</code></td>
          <td>tex/latex</td>
          <td>设备无关文件</td>
      </tr>
      <tr>
          <td><code>.pdf</code></td>
          <td>pdflatex/xelatex/lualatex</td>
          <td>便携文档格式</td>
      </tr>
      <tr>
          <td><code>.xdv</code></td>
          <td>xetex</td>
          <td>扩展DVI格式</td>
      </tr>
      <tr>
          <td><code>.aux</code></td>
          <td>所有引擎</td>
          <td>辅助信息文件</td>
      </tr>
      <tr>
          <td><code>.log</code></td>
          <td>所有引擎</td>
          <td>编译日志文件</td>
      </tr>
  </tbody>
</table>
<h2 id="工具链组件">
  <a class="anchor inpage" href="#%e5%b7%a5%e5%85%b7%e9%93%be%e7%bb%84%e4%bb%b6">##</a>工具链组件</h2>
<h3 id="核心工具">
  <a class="anchor inpage" href="#%e6%a0%b8%e5%bf%83%e5%b7%a5%e5%85%b7">###</a>核心工具</h3>
<table>
  <thead>
      <tr>
          <th>工具名称</th>
          <th>用途</th>
          <th>示例</th>
      </tr>
  </thead>
  <tbody>
      <tr>
          <td><strong>texlua</strong></td>
          <td>Lua解释器</td>
          <td>运行TeX相关Lua脚本</td>
      </tr>
      <tr>
          <td><strong>kpsewhich</strong></td>
          <td>文件查找</td>
          <td>定位TeX文件位置</td>
      </tr>
      <tr>
          <td><strong>bibtex</strong></td>
          <td>参考文献处理</td>
          <td>生成参考文献列表</td>
      </tr>
      <tr>
          <td><strong>makeindex</strong></td>
          <td>索引生成</td>
          <td>创建文档索引</td>
      </tr>
  </tbody>
</table>
<h3 id="编译工具链">
  <a class="anchor inpage" href="#%e7%bc%96%e8%af%91%e5%b7%a5%e5%85%b7%e9%93%be">###</a>编译工具链</h3>
<pre class="mermaid">graph TD
    A[.tex源文件] --&gt; B{选择引擎}
    B --&gt; C[pdflatex]
    B --&gt; D[xelatex]
    B --&gt; E[lualatex]

    C --&gt; F[生成PDF]
    D --&gt; F
    E --&gt; F

    subgraph &#34;可选处理&#34;
        G[.bib文件] --&gt; H[bibtex]
        I[.idx文件] --&gt; J[makeindex]
        H --&gt; K[.bbl文件]
        J --&gt; L[.ind文件]
    end

    K --&gt; C
    L --&gt; C</pre><h2 id="选择指南">
  <a class="anchor inpage" href="#%e9%80%89%e6%8b%a9%e6%8c%87%e5%8d%97">##</a>选择指南</h2>
<h3 id="引擎选择建议">
  <a class="anchor inpage" href="#%e5%bc%95%e6%93%8e%e9%80%89%e6%8b%a9%e5%bb%ba%e8%ae%ae">###</a>引擎选择建议</h3>
<ol>
<li><strong>中文/多语言文档</strong>：<code>xelatex</code> 或 <code>lualatex</code></li>
<li><strong>传统英文文档</strong>：<code>pdflatex</code></li>
<li><strong>需要动态功能</strong>：<code>lualatex</code>（Lua脚本）</li>
<li><strong>底层开发</strong>：<code>tex</code> 或 <code>luatex</code></li>
</ol>
<h2 id="列举">
  <a class="anchor inpage" href="#%e5%88%97%e4%b8%be">##</a>列举</h2>
<h3 id="1">
  <a class="anchor inpage" href="#1">###</a><strong>1. <code>tex</code>（原始 TeX 引擎）</strong></h3>
<ul>
<li><strong>作用</strong>：Knuth 开发的原始 TeX 排版引擎，处理 <code>.tex</code> 文件并生成 <code>.dvi</code>（DeVice Independent）文件。</li>
<li><strong>特点</strong>：
<ul>
<li>仅支持传统的 TeX 命令，不支持现代字体（如 OpenType）。</li>
<li>主要用于历史兼容性或极简排版。</li>
</ul>
</li>
<li><strong>使用示例</strong>：
<details open>
    <summary>sh</summary><pre
        class="chroma codeblock"
      ><code class="language-sh" data-lang="sh"
          ><span style="display:flex;"><span>tex mydocument.tex  <span style="color:#75715e"># 生成 mydocument.dvi</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>
<h3 id="2">
  <a class="anchor inpage" href="#2">###</a><strong>2. <code>latex</code>（LaTeX 格式 + pdfTeX 引擎）</strong></h3>
<ul>
<li><strong>作用</strong>：使用 <code>pdftex</code> 引擎处理 LaTeX 文档（<code>.tex</code>），默认生成 PDF（也可生成 DVI）。</li>
<li><strong>特点</strong>：
<ul>
<li>基于 <code>pdftex</code>，支持 PDF 输出、微调排版和基本字体扩展。</li>
<li>但不支持 Unicode 和 OpenType 字体（需额外宏包如 <code>fontspec</code>）。</li>
</ul>
</li>
<li><strong>使用示例</strong>：
<details open>
    <summary>sh</summary><pre
        class="chroma codeblock"
      ><code class="language-sh" data-lang="sh"
          ><span style="display:flex;"><span>latex mydocument.tex  <span style="color:#75715e"># 生成 mydocument.dvi</span>
</span></span><span style="display:flex;"><span>pdflatex mydocument.tex  <span style="color:#75715e"># 生成 mydocument.pdf</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>
<h3 id="3">
  <a class="anchor inpage" href="#3">###</a><strong>3. <code>xetex</code>（XeTeX 引擎，支持 Unicode 和系统字体）</strong></h3>
<ul>
<li><strong>作用</strong>：TeX 引擎，原生支持 Unicode 和系统字体（如 <code>.ttf</code>/<code>.otf</code>）。</li>
<li><strong>特点</strong>：
<ul>
<li>直接调用系统字体，无需额外配置。</li>
<li>适用于多语言排版（如中文、阿拉伯语）。</li>
<li>输出格式为 <code>.xdv</code>（扩展 DVI），通常转换为 PDF。</li>
</ul>
</li>
<li><strong>使用示例</strong>：
<details open>
    <summary>sh</summary><pre
        class="chroma codeblock"
      ><code class="language-sh" data-lang="sh"
          ><span style="display:flex;"><span>xetex mydocument.tex  <span style="color:#75715e"># 生成 mydocument.xdv（通常自动转 PDF）</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>
<h3 id="4">
  <a class="anchor inpage" href="#4">###</a><strong>4. <code>xelatex</code>（LaTeX + XeTeX 引擎）</strong></h3>
<ul>
<li><strong>作用</strong>：<code>latex</code> 的增强版，使用 <code>xetex</code> 引擎处理 LaTeX 文档，支持现代字体。</li>
<li><strong>特点</strong>：
<ul>
<li>支持 <code>fontspec</code> 宏包，可轻松使用系统字体。</li>
<li>适合中文排版（如配合 <code>ctex</code> 宏包）。</li>
</ul>
</li>
<li><strong>使用示例</strong>：
<details open>
    <summary>sh</summary><pre
        class="chroma codeblock"
      ><code class="language-sh" data-lang="sh"
          ><span style="display:flex;"><span>xelatex mydocument.tex  <span style="color:#75715e"># 直接生成 PDF</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>
<h3 id="5">
  <a class="anchor inpage" href="#5">###</a><strong>5. <code>luatex</code>（LuaTeX 引擎，支持 Lua 脚本）</strong></h3>
<ul>
<li><strong>作用</strong>：扩展的 TeX 引擎，内置 Lua 解释器，允许动态脚本控制排版。</li>
<li><strong>特点</strong>：
<ul>
<li>支持 Unicode 和 OpenType 字体（类似 XeTeX）。</li>
<li>可通过 <code>\directlua{}</code> 嵌入 Lua 代码，实现高级自动化。</li>
<li>默认生成 PDF。</li>
</ul>
</li>
<li><strong>使用示例</strong>：
<details open>
    <summary>sh</summary><pre
        class="chroma codeblock"
      ><code class="language-sh" data-lang="sh"
          ><span style="display:flex;"><span>luatex mydocument.tex  <span style="color:#75715e"># 生成 PDF</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>
<h3 id="6">
  <a class="anchor inpage" href="#6">###</a><strong>6. <code>lualatex</code>（LaTeX + LuaTeX 引擎）</strong></h3>
<ul>
<li><strong>作用</strong>：<code>latex</code> 的现代替代品，使用 <code>luatex</code> 引擎，结合 LaTeX 和 Lua 扩展。</li>
<li><strong>特点</strong>：
<ul>
<li>支持 <code>fontspec</code> 和 Lua 脚本，灵活性极高。</li>
<li>适合复杂排版（如自动生成内容、动态调整格式）。</li>
</ul>
</li>
<li><strong>使用示例</strong>：
<details open>
    <summary>sh</summary><pre
        class="chroma codeblock"
      ><code class="language-sh" data-lang="sh"
          ><span style="display:flex;"><span>lualatex mydocument.tex  <span style="color:#75715e"># 生成 PDF</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>
<h3 id="总结对比">
  <a class="anchor inpage" href="#%e6%80%bb%e7%bb%93%e5%af%b9%e6%af%94">###</a><strong>总结对比</strong></h3>
<table>
  <thead>
      <tr>
          <th>命令</th>
          <th>引擎</th>
          <th>输出格式</th>
          <th>Unicode 支持</th>
          <th>OpenType 支持</th>
          <th>Lua 支持</th>
          <th>典型用途</th>
      </tr>
  </thead>
  <tbody>
      <tr>
          <td><code>tex</code></td>
          <td>TeX</td>
          <td>DVI</td>
          <td>❌</td>
          <td>❌</td>
          <td>❌</td>
          <td>原始 TeX 排版</td>
      </tr>
      <tr>
          <td><code>latex</code></td>
          <td>pdfTeX</td>
          <td>DVI/PDF</td>
          <td>❌</td>
          <td>❌</td>
          <td>❌</td>
          <td>传统 LaTeX 文档</td>
      </tr>
      <tr>
          <td><code>pdflatex</code></td>
          <td>pdfTeX</td>
          <td>PDF</td>
          <td>❌</td>
          <td>❌</td>
          <td>❌</td>
          <td>直接生成 PDF</td>
      </tr>
      <tr>
          <td><code>xetex</code></td>
          <td>XeTeX</td>
          <td>XDV/PDF</td>
          <td>✔️</td>
          <td>✔️</td>
          <td>❌</td>
          <td>多语言排版（系统字体）</td>
      </tr>
      <tr>
          <td><code>xelatex</code></td>
          <td>XeTeX</td>
          <td>PDF</td>
          <td>✔️</td>
          <td>✔️</td>
          <td>❌</td>
          <td>现代 LaTeX（中文友好）</td>
      </tr>
      <tr>
          <td><code>luatex</code></td>
          <td>LuaTeX</td>
          <td>PDF</td>
          <td>✔️</td>
          <td>✔️</td>
          <td>✔️</td>
          <td>动态脚本控制排版</td>
      </tr>
      <tr>
          <td><code>lualatex</code></td>
          <td>LuaTeX</td>
          <td>PDF</td>
          <td>✔️</td>
          <td>✔️</td>
          <td>✔️</td>
          <td>高级 LaTeX 自动化</td>
      </tr>
  </tbody>
</table>
]]></content:encoded></item><item><title>我的网站计划</title><link>https://hiraethecho.github.io/docs/project/mysites/</link><pubDate>Sun, 17 Aug 2025 00:00:00 +0000</pubDate><author>wyz2016zxc@outlook.com(Hiraeth)</author><guid>https://hiraethecho.github.io/docs/project/mysites/</guid><description>建站资料，技术和服务汇总</description><content:encoded><![CDATA[<h1 id="我的网站们">
  <a class="anchor inpage" href="#%e6%88%91%e7%9a%84%e7%bd%91%e7%ab%99%e4%bb%ac">#</a>我的网站们</h1>
<p>想要建站，各种方式建了很多站，试了很多技术功能。<br>
截至 2025-08-29前 汇总一下。</p>
<h2 id="服务器上的">
  <a class="anchor inpage" href="#%e6%9c%8d%e5%8a%a1%e5%99%a8%e4%b8%8a%e7%9a%84">##</a>服务器上的</h2>
<p>在starship上的服务器跑的服务，用zero trust-network-tunnel的方式绑定到877675.xyz域名下的子域名。</p>
<ul>
<li>
 一个类似flomo的轻量级笔记服务</li>
<li>
 一个结合AI的memo服务</li>
<li><del>
</del> 把github的copilot加上OpenAI的接口。找不到怎么加密，先关掉了。项目的
有本地部署方法。</li>
<li>
 网盘合集</li>
<li>
 用radicale做的日历和联系人服务</li>
</ul>
<h2 id="一些赛博善人">
  <a class="anchor inpage" href="#%e4%b8%80%e4%ba%9b%e8%b5%9b%e5%8d%9a%e5%96%84%e4%ba%ba">##</a>一些赛博善人</h2>
<h3 id="netlify">
  <a class="anchor inpage" href="#netlify">###</a>netlify</h3>
<ul>
<li>twikoo</li>
<li>waline</li>
<li>代替 obsidian publish的 
，要把<code>github-repo/content</code>作为obsidian repo，但是里面还有很多别的东西</li>
<li>digitalgarden 同上，但是可以选择哪些发布，并且不用放在github仓库里，简单但同时自定义差一点。</li>
</ul>
<h3 id="vercel">
  <a class="anchor inpage" href="#vercel">###</a>vercel</h3>
<ul>
<li>memos.top 一个memos的展示
，需要有memos</li>
<li>neno 类似flomo的
，功能很少。</li>
<li>digitalgarden</li>
</ul>
<h3 id="claw-cloud">
  <a class="anchor inpage" href="#claw-cloud">###</a>claw-cloud</h3>
<ul>
<li>企图host一个
，但自定义域名未遂。</li>
</ul>
<h3 id="github-pages">
  <a class="anchor inpage" href="#github-pages">###</a>github pages</h3>
<ul>
<li>
 
 
 这三个博客暂时都是</li>
<li>memos.top 同vercel的上，但是用github pages部署的
</li>
</ul>
<h2 id="cloudflare-属于赛博菩萨了">
  <a class="anchor inpage" href="#cloudflare-%e5%b1%9e%e4%ba%8e%e8%b5%9b%e5%8d%9a%e8%8f%a9%e8%90%a8%e4%ba%86">##</a>cloudflare 属于赛博菩萨了</h2>
<h3 id="pages">
  <a class="anchor inpage" href="#pages">###</a>pages</h3>
<ul>
<li>
 把桶存储变成webdav。目前是把图床和memos的桶放在这。</li>
</ul>
<h3 id="workers">
  <a class="anchor inpage" href="#workers">###</a>workers</h3>
<p>用cloudflare works创建的服务。</p>
<ul>
<li>
 用resend服务发邮件
<ul>
<li>
</li>
<li>
</li>
</ul>
</li>
<li>
 用cloudflare的ai</li>
</ul>
<h3 id="mails">
  <a class="anchor inpage" href="#mails">###</a>mails</h3>
<p>cloudflare自己转发的邮件服务。有点乱，看图吧。</p>
<p><figure>
  <a
    href="https://asset.877675.xyz/202508171454341.webp"
    class="img-link"
    data-sub-html=""
    target="_blank"
  >
    <img
      src="https://asset.877675.xyz/202508171454341.webp"
      alt=""loading="lazy"
    />
  </a></figure>
</p>
<p><figure>
  <a
    href="https://asset.877675.xyz/202508171455969.webp"
    class="img-link"
    data-sub-html=""
    target="_blank"
  >
    <img
      src="https://asset.877675.xyz/202508171455969.webp"
      alt=""loading="lazy"
    />
  </a></figure>
</p>
<h3 id="bucket">
  <a class="anchor inpage" href="#bucket">###</a>bucket</h3>
<ul>
<li>图床</li>
<li>rclone连接，当备份的网盘。</li>
</ul>
<h2 id="为博客添加的功能">
  <a class="anchor inpage" href="#%e4%b8%ba%e5%8d%9a%e5%ae%a2%e6%b7%bb%e5%8a%a0%e7%9a%84%e5%8a%9f%e8%83%bd">##</a>为博客添加的功能</h2>
<h3 id="闲言碎语">
  <a class="anchor inpage" href="#%e9%97%b2%e8%a8%80%e7%a2%8e%e8%af%ad">###</a>闲言碎语</h3>
<ul>
<li>artitalk 一个说说或即刻页面，无后端，leancloud存储。可以用js插入到html里。Github pages上有一个
</li>
<li>nonsense 无后端，leancloud存储。可以单独页面，也可以插入到博客里。这个写入有点费劲。</li>
<li>memos 似乎也可以插入到博客里。
</li>
</ul>
<h3 id="评论">
  <a class="anchor inpage" href="#%e8%af%84%e8%ae%ba">###</a>评论</h3>
<ul>
<li>valine 无后端，leancloud存储</li>
<li>waline 有后端，在netlify。leancloud存储。 
试用。</li>
<li>twikoo 有后端，在netlify。MongDB存储。</li>
</ul>
<h3 id="图床">
  <a class="anchor inpage" href="#%e5%9b%be%e5%ba%8a">###</a>图床</h3>
<p>cloudflare的桶存储，和picgo上传</p>
<p>merge了picgo和memos的桶，把<code>pic</code>和<code>memos</code>的删掉，合并到<code>asset</code>，然后似乎出了点问题，openlist有点bug似乎。删掉重新添加就行，只改bucket不行，好神秘啊。<br>
以及<code>picgo</code>的url全错了，看不到预览，不好找图片了。</p>
]]></content:encoded></item><item><title>买域名上瘾</title><link>https://hiraethecho.github.io/docs/project/my-domain/</link><pubDate>Sun, 10 Aug 2025 00:00:00 +0000</pubDate><author>wyz2016zxc@outlook.com(Hiraeth)</author><guid>https://hiraethecho.github.io/docs/project/my-domain/</guid><description>买域名上瘾</description><content:encoded><![CDATA[<h1 id="买域名上瘾">
  <a class="anchor inpage" href="#%e4%b9%b0%e5%9f%9f%e5%90%8d%e4%b8%8a%e7%98%be">#</a>买域名上瘾</h1>
<p>前一段发现了cloudflare，于是想要买域名。</p>
<h2 id="domain-name">
  <a class="anchor inpage" href="#domain-name">##</a>domain name</h2>
<p>买了三个域名，申请了一个免费的。<br>
第一个是hiraethecho.online，在namecheap，买的第一年便宜，但是买了之后才发现续费好贵，好烦。要用palpay，好麻烦。<br>
然后312220.xyz在namesilo上买的，超级便宜。<br>
但是877675.xyz更便宜，在spaceship上搞的。这里居然可以用支付宝。</p>
<p>然后还想买域名，加了一堆购物车</p>
<table>
  <thead>
      <tr>
          <th>域名</th>
          <th>第一年</th>
          <th>续订</th>
      </tr>
  </thead>
  <tbody>
      <tr>
          <td>hiraeth.meme</td>
          <td>74</td>
          <td>74</td>
      </tr>
      <tr>
          <td>hiraeth.casa</td>
          <td>7.5</td>
          <td>75</td>
      </tr>
      <tr>
          <td>hiraeth.one</td>
          <td>41</td>
          <td>96</td>
      </tr>
      <tr>
          <td>hiraeth.page</td>
          <td>57</td>
          <td>74</td>
      </tr>
      <tr>
          <td>hiraethecho.com</td>
          <td>64</td>
          <td>72</td>
      </tr>
      <tr>
          <td>hiraethecho.top</td>
          <td>7.54</td>
          <td>27.65</td>
      </tr>
      <tr>
          <td>hiraethecho.cc</td>
          <td>22</td>
          <td>60</td>
      </tr>
      <tr>
          <td>hiraethecho.xyz</td>
          <td>13.36</td>
          <td>81.82</td>
      </tr>
      <tr>
          <td>keinmal.com</td>
          <td>64</td>
          <td>72</td>
      </tr>
      <tr>
          <td>keinmal.top</td>
          <td>7.54</td>
          <td>27.65</td>
      </tr>
      <tr>
          <td>keinmal.cc</td>
          <td>22</td>
          <td>60</td>
      </tr>
      <tr>
          <td>keinmal.xyz</td>
          <td>13.36</td>
          <td>81.82</td>
      </tr>
      <tr>
          <td>essmussein.com</td>
          <td>NULL</td>
          <td>NULL</td>
      </tr>
      <tr>
          <td>essmussein.top</td>
          <td>7.54</td>
          <td>27.65</td>
      </tr>
      <tr>
          <td>esmussein.cc</td>
          <td>22</td>
          <td>60</td>
      </tr>
      <tr>
          <td>essmussein.xyz</td>
          <td>13.36</td>
          <td>81.82</td>
      </tr>
  </tbody>
</table>
<p>应该挑一个短的、顶级域名不是特别奇怪的、便宜的。<br>
打算保留877675.xyz，用作我的各种服务或api之类的。然后再买一个当博客的地址。</p>
<h2 id="服务器">
  <a class="anchor inpage" href="#%e6%9c%8d%e5%8a%a1%e5%99%a8">##</a>服务器</h2>
<p>于是又在spaceship上买了个虚拟机，很寒酸，fedora 1 vGPU 2GiB memory, 25G ssd. 但是一个月27，搞点简单的小服务也够用。比如
</p>
]]></content:encoded></item><item><title>一些nvim的配置和使用技巧</title><link>https://hiraethecho.github.io/docs/software/nvim-trick/</link><pubDate>Wed, 06 Aug 2025 00:00:00 +0000</pubDate><author>wyz2016zxc@outlook.com(Hiraeth)</author><guid>https://hiraethecho.github.io/docs/software/nvim-trick/</guid><description>&lt;h1 id="一些nvim的配置和使用技巧"&gt;
&lt;a class="anchor inpage" href="#%e4%b8%80%e4%ba%9bnvim%e7%9a%84%e9%85%8d%e7%bd%ae%e5%92%8c%e4%bd%bf%e7%94%a8%e6%8a%80%e5%b7%a7"&gt;#&lt;/a&gt;一些nvim的配置和使用技巧&lt;/h1&gt;
&lt;h2 id="cmd"&gt;
&lt;a class="anchor inpage" href="#cmd"&gt;##&lt;/a&gt;cmd&lt;/h2&gt;
&lt;p&gt;Lua 输出：&lt;/p&gt;
&lt;details open&gt;
&lt;summary&gt;nvim&lt;/summary&gt;&lt;pre
class="codeblock"
&gt;&lt;code class="language-nvim" data-lang="nvim"&gt;:lua =vim.opt.runtimepath:get()&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;:setl ma! ma?&lt;/code&gt; 可以切换一个buffer的只读状态。
注意其他编辑器的只读一般是“你可以修改但不能保存“，这个是你根本不能修改，比如说根本就不能进入插入模式。
可以设一个顺手的keymap，比如说我是nnoremap &lt;silent&gt; ;m :setl ma! ma?&lt;cr&gt; 。&lt;/p&gt;</description><content:encoded><![CDATA[<h1 id="一些nvim的配置和使用技巧">
  <a class="anchor inpage" href="#%e4%b8%80%e4%ba%9bnvim%e7%9a%84%e9%85%8d%e7%bd%ae%e5%92%8c%e4%bd%bf%e7%94%a8%e6%8a%80%e5%b7%a7">#</a>一些nvim的配置和使用技巧</h1>
<h2 id="cmd">
  <a class="anchor inpage" href="#cmd">##</a>cmd</h2>
<p>Lua 输出：</p>
<details open>
    <summary>nvim</summary><pre
        class="codeblock"
      ><code class="language-nvim" data-lang="nvim">:lua =vim.opt.runtimepath:get()</code><button onclick="copyCode(this)" class="copybtn">copy</button></pre></details>

  <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>:setl ma! ma?</code> 可以切换一个buffer的只读状态。
注意其他编辑器的只读一般是“你可以修改但不能保存“，这个是你根本不能修改，比如说根本就不能进入插入模式。
可以设一个顺手的keymap，比如说我是nnoremap <silent> ;m :setl ma! ma?<cr> 。</p>
<p>另外，:setl xxx! xxx? 这个是一个常用切换option开关的模式，比如说:nnoremap <silent> <space>w<space> <CMD>setl wrap! wrap?<cr>设keymap来切换自动换行，并在状态栏显示当前实际状态。</p>
<details open>
    <summary>vimscript</summary><pre
        class="codeblock"
      ><code class="language-vimscript" data-lang="vimscript">xnoremap ,x &lt;ESC&gt;`.`gvp`P
abbrev ,f &lt;C-R&gt;=expand(&#34;%:&#34;)&lt;left&gt;&lt;left&gt;
abbrev ,c &lt;C-R&gt;=getcwd()&lt;cr&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>下面的keymap可以直接执行一行vimscript或者lua （取决于当前文件类型）。用来调整或者测试vim配置非常方便，改完一行就执行一下，不需要source整个vimrc文件了。</p>
<details open>
    <summary>vimscript</summary><pre
        class="codeblock"
      ><code class="language-vimscript" data-lang="vimscript">command! -range ExecVimL call execute(getline(&lt;line1&gt;, &lt;line2&gt;), &#39;&#39;)
command! -range ExecLua call execute(&#39;lua &#39; . join(getline(&lt;line1&gt;, &lt;line2&gt;), &#34; \n &#34;), &#39;&#39;)
nnoremap &lt;silent&gt; &lt;expr&gt; ,r ((&amp;ft==&#39;lua&#39; ? &#39;:ExecLua&#39; : &#39;:ExecVimL&#39;) . &#39;&lt;cr&gt;:&lt;c-u&gt;echo &#34;Current line executed&#34;&lt;cr&gt;&#39;)
xnoremap &lt;silent&gt; &lt;expr&gt; ,r ((&amp;ft==&#39;lua&#39; ? &#39;:ExecLua&#39; : &#39;:ExecVimL&#39;) . &#39;&lt;cr&gt;:&lt;c-u&gt;echo &#34;Selected range executed&#34;&lt;cr&gt;&#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>链接：https://www.zhihu.com/question/636018229/answer/3386613023
著作权归作者所有。商业转载请联系作者获得授权，非商业转载请注明出处。</p>
<p>用<code>.!</code>（当前行），<code>%!</code>（整个buff），<code>'&lt;,'&gt;!</code> (选中）可以把文本作为stdin传给一个外部shell命令，并用其stdout输出内容替换相应文本，用来调外部的格式化命令很方便。另外，如果传给bash或zsh的话就相当于把文本作为shell命令执行。</p>
<p>「修改 1」→「撤销」→「修改 2」，这时如果想退回到「修改 1」，按 <code>u</code> 是回不去的。</p>
<p>可以按 <code>g-</code>（反方向是 <code>g+</code>）</p>
<p>实际上等同于 <code>:earlier</code> 和 <code>:later</code> 。这两个命令后边是可以跟「次数」而不是「时间」的顺便一说，不写默认是 1 次。</p>
<p>test 2</p>
<h2 id="start-up-of-nvim">
  <a class="anchor inpage" href="#start-up-of-nvim">##</a>start up of nvim</h2>
<p>
</p>
<h2 id="lazynvim">
  <a class="anchor inpage" href="#lazynvim">##</a>lazy.nvim</h2>
<p>
 <code>lazy.nvim</code> 配置的表合并情况。例如假设<code>treesitter</code>的默认配置为</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">return</span> {
</span></span><span style="display:flex;"><span>  <span style="color:#e6db74">&#34;nvim-treesitter/nvim-treesitter&#34;</span>,
</span></span><span style="display:flex;"><span>  opts <span style="color:#f92672">=</span> {
</span></span><span style="display:flex;"><span>    ensure_installed <span style="color:#f92672">=</span> { <span style="color:#e6db74">&#34;lua&#34;</span>, <span style="color:#e6db74">&#34;vim&#34;</span> },
</span></span><span style="display:flex;"><span>    highlight <span style="color:#f92672">=</span> {
</span></span><span style="display:flex;"><span>      enable <span style="color:#f92672">=</span> <span style="color:#66d9ef">true</span>,
</span></span><span style="display:flex;"><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>手动配置</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">return</span> {
</span></span><span style="display:flex;"><span>  <span style="color:#e6db74">&#34;nvim-treesitter/nvim-treesitter&#34;</span>,
</span></span><span style="display:flex;"><span>  opts <span style="color:#f92672">=</span> {
</span></span><span style="display:flex;"><span>    ensure_installed <span style="color:#f92672">=</span> { <span style="color:#e6db74">&#34;python&#34;</span> },
</span></span><span style="display:flex;"><span>    highlight <span style="color:#f92672">=</span> {
</span></span><span style="display:flex;"><span>      enable <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>    indent <span style="color:#f92672">=</span> {
</span></span><span style="display:flex;"><span>      enable <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></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>那么最后会得到<code>ensure_installed = { &quot;python&quot; }</code>。如何要拓展表，则要用</p>
<details open>
    <summary>lua</summary><pre
        class="chroma codeblock"
      ><code class="language-lua" data-lang="lua"
          ><span style="display:flex;"><span>table.insert(opts.ensure_installed, <span style="color:#e6db74">&#34;python&#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>]]></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>timewarrior</title><link>https://hiraethecho.github.io/docs/software/timewarrior/</link><pubDate>Wed, 18 Jun 2025 00:00:00 +0000</pubDate><author>wyz2016zxc@outlook.com(Hiraeth)</author><guid>https://hiraethecho.github.io/docs/software/timewarrior/</guid><description>&lt;h1 id="timewarrior"&gt;
&lt;a class="anchor inpage" href="#timewarrior"&gt;#&lt;/a&gt;timewarrior&lt;/h1&gt;
&lt;h2 id="help"&gt;
&lt;a class="anchor inpage" href="#help"&gt;##&lt;/a&gt;help&lt;/h2&gt;
&lt;p&gt;A time tracking tool used to measure the duration of activities.
.&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;
Start tracking an activity:
timew start
Tag the current activity:
timew tag activity_tag
Start tracking and tag a new activity:
timew start activity_tag
Stop the current activity:
timew stop
Track an activity in the past:
timew track start_time - end_time activity_tag
View tracked items of the day:
timew summary
View report for the last day, week, current month, etc.:
timew summary :today|yesterday|week|lastweek|month|lastmonth|year|lastyear&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;Usage: timew [--version]
timew annotate @&amp;lt;id&amp;gt; [@&amp;lt;id&amp;gt; ...] &amp;lt;annotation&amp;gt;
timew cancel
timew config [&amp;lt;name&amp;gt; [&amp;lt;value&amp;gt; | &amp;#39;&amp;#39;]]
timew continue [@&amp;lt;id&amp;gt;] [&amp;lt;date&amp;gt;|&amp;lt;interval&amp;gt;]
timew day [&amp;lt;interval&amp;gt;] [&amp;lt;tag&amp;gt; ...]
timew delete @&amp;lt;id&amp;gt; [@&amp;lt;id&amp;gt; ...]
timew diagnostics
timew export [&amp;lt;interval&amp;gt;] [&amp;lt;tag&amp;gt; ...]
timew extensions
timew gaps [&amp;lt;interval&amp;gt;] [&amp;lt;tag&amp;gt; ...]
timew get &amp;lt;DOM&amp;gt; [&amp;lt;DOM&amp;gt; ...]
timew help [&amp;lt;command&amp;gt; | dates | dom | durations | hints | ranges]
timew join @&amp;lt;id&amp;gt; @&amp;lt;id&amp;gt;
timew lengthen @&amp;lt;id&amp;gt; [@&amp;lt;id&amp;gt; ...] &amp;lt;duration&amp;gt;
timew modify (start|end) @&amp;lt;id&amp;gt; &amp;lt;date&amp;gt;
timew modify range @&amp;lt;id&amp;gt; &amp;lt;interval&amp;gt;
timew month [&amp;lt;interval&amp;gt;] [&amp;lt;tag&amp;gt; ...]
timew move @&amp;lt;id&amp;gt; &amp;lt;date&amp;gt;
timew [report] &amp;lt;report&amp;gt; [&amp;lt;interval&amp;gt;] [&amp;lt;tag&amp;gt; ...]
timew retag @&amp;lt;id&amp;gt; [@&amp;lt;id&amp;gt; ...] &amp;lt;tag&amp;gt; [&amp;lt;tag&amp;gt; ...]
timew shorten @&amp;lt;id&amp;gt; [@&amp;lt;id&amp;gt; ...] &amp;lt;duration&amp;gt;
timew show
timew split @&amp;lt;id&amp;gt; [@&amp;lt;id&amp;gt; ...]
timew start [&amp;lt;date&amp;gt;] [&amp;lt;tag&amp;gt; ...]
timew stop [&amp;lt;tag&amp;gt; ...]
timew summary [&amp;lt;interval&amp;gt;] [&amp;lt;tag&amp;gt; ...]
timew tag @&amp;lt;id&amp;gt; [@&amp;lt;id&amp;gt; ...] &amp;lt;tag&amp;gt; [&amp;lt;tag&amp;gt; ...]
timew tags [&amp;lt;interval&amp;gt;] [&amp;lt;tag&amp;gt; ...]
timew track &amp;lt;interval&amp;gt; [&amp;lt;tag&amp;gt; ...]
timew undo
timew untag @&amp;lt;id&amp;gt; [@&amp;lt;id&amp;gt; ...] &amp;lt;tag&amp;gt; [&amp;lt;tag&amp;gt; ...]
timew week [&amp;lt;interval&amp;gt;] [&amp;lt;tag&amp;gt; ...]
Additional help:
timew help &amp;lt;command&amp;gt;
timew help dates
timew help dom
timew help durations
timew help hints
timew help ranges
Interval:
[from] &amp;lt;date&amp;gt;
[from] &amp;lt;date&amp;gt; to/- &amp;lt;date&amp;gt;
[from] &amp;lt;date&amp;gt; for &amp;lt;duration&amp;gt;
&amp;lt;duration&amp;gt; before/after &amp;lt;date&amp;gt;
&amp;lt;duration&amp;gt; ago
[for] &amp;lt;duration&amp;gt;
Tag:
Word
&amp;#39;Single Quoted Words&amp;#39;
&amp;#34;Double Quoted Words&amp;#34;
Escaped\ Spaces
Configuration overrides:
rc.&amp;lt;name&amp;gt;=&amp;lt;value&amp;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="timew-dom---timewarrior-dom"&gt;
&lt;a class="anchor inpage" href="#timew-dom---timewarrior-dom"&gt;##&lt;/a&gt;timew-dom - Timewarrior DOM&lt;/h2&gt;
&lt;p&gt;Supported DOM references are:&lt;/p&gt;</description><content:encoded><![CDATA[<h1 id="timewarrior">
  <a class="anchor inpage" href="#timewarrior">#</a>timewarrior</h1>
<h2 id="help">
  <a class="anchor inpage" href="#help">##</a>help</h2>
<p>A time tracking tool used to measure the duration of activities. 
.</p>
<details open>
    <summary>TEXT</summary><pre
        class="codeblock"
      ><code class="language-" data-lang="">
  Start tracking an activity:

      timew start

  Tag the current activity:

      timew tag activity_tag

  Start tracking and tag a new activity:

      timew start activity_tag

  Stop the current activity:

      timew stop

  Track an activity in the past:

      timew track start_time - end_time activity_tag

  View tracked items of the day:

      timew summary

  View report for the last day, week, current month, etc.:

      timew summary :today|yesterday|week|lastweek|month|lastmonth|year|lastyear</code><button onclick="copyCode(this)" class="copybtn">copy</button></pre></details>

  <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="">Usage: timew [--version]
       timew annotate @&lt;id&gt; [@&lt;id&gt; ...] &lt;annotation&gt;
       timew cancel
       timew config [&lt;name&gt; [&lt;value&gt; | &#39;&#39;]]
       timew continue [@&lt;id&gt;] [&lt;date&gt;|&lt;interval&gt;]
       timew day [&lt;interval&gt;] [&lt;tag&gt; ...]
       timew delete @&lt;id&gt; [@&lt;id&gt; ...]
       timew diagnostics
       timew export [&lt;interval&gt;] [&lt;tag&gt; ...]
       timew extensions
       timew gaps [&lt;interval&gt;] [&lt;tag&gt; ...]
       timew get &lt;DOM&gt; [&lt;DOM&gt; ...]
       timew help [&lt;command&gt; | dates | dom | durations | hints | ranges]
       timew join @&lt;id&gt; @&lt;id&gt;
       timew lengthen @&lt;id&gt; [@&lt;id&gt; ...] &lt;duration&gt;
       timew modify (start|end) @&lt;id&gt; &lt;date&gt;
       timew modify range @&lt;id&gt; &lt;interval&gt;
       timew month [&lt;interval&gt;] [&lt;tag&gt; ...]
       timew move @&lt;id&gt; &lt;date&gt;
       timew [report] &lt;report&gt; [&lt;interval&gt;] [&lt;tag&gt; ...]
       timew retag @&lt;id&gt; [@&lt;id&gt; ...] &lt;tag&gt; [&lt;tag&gt; ...]
       timew shorten @&lt;id&gt; [@&lt;id&gt; ...] &lt;duration&gt;
       timew show
       timew split @&lt;id&gt; [@&lt;id&gt; ...]
       timew start [&lt;date&gt;] [&lt;tag&gt; ...]
       timew stop [&lt;tag&gt; ...]
       timew summary [&lt;interval&gt;] [&lt;tag&gt; ...]
       timew tag @&lt;id&gt; [@&lt;id&gt; ...] &lt;tag&gt; [&lt;tag&gt; ...]
       timew tags [&lt;interval&gt;] [&lt;tag&gt; ...]
       timew track &lt;interval&gt; [&lt;tag&gt; ...]
       timew undo
       timew untag @&lt;id&gt; [@&lt;id&gt; ...] &lt;tag&gt; [&lt;tag&gt; ...]
       timew week [&lt;interval&gt;] [&lt;tag&gt; ...]

Additional help:
       timew help &lt;command&gt;
       timew help dates
       timew help dom
       timew help durations
       timew help hints
       timew help ranges

Interval:
       [from] &lt;date&gt;
       [from] &lt;date&gt; to/- &lt;date&gt;
       [from] &lt;date&gt; for &lt;duration&gt;
       &lt;duration&gt; before/after &lt;date&gt;
       &lt;duration&gt; ago
       [for] &lt;duration&gt;

Tag:
       Word
       &#39;Single Quoted Words&#39;
       &#34;Double Quoted Words&#34;
       Escaped\ Spaces

Configuration overrides:
       rc.&lt;name&gt;=&lt;value&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="timew-dom---timewarrior-dom">
  <a class="anchor inpage" href="#timew-dom---timewarrior-dom">##</a>timew-dom - Timewarrior DOM</h2>
<p>Supported DOM references are:</p>
<details open>
    <summary>TEXT</summary><pre
        class="codeblock"
      ><code class="language-" data-lang="">dom.tag.count             Count of all tags
dom.tag.1                 Nth tag used</code><button onclick="copyCode(this)" class="copybtn">copy</button></pre></details>

  <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="">dom.active                &#39;1&#39; if there is active tracking, otherwise &#39;0&#39;
dom.active.tag.count      Count of active tags
dom.active.tag.1          Active Nth tag
dom.active.start          Active start timestamp (ISO Extended local date)
dom.active.duration       Active elapsed (ISO Period)
dom.active.json           Active interval as JSON</code><button onclick="copyCode(this)" class="copybtn">copy</button></pre></details>

  <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="">dom.tracked.count         Count of tracked intervals
dom.tracked.1.tag.count   Count of active tags
dom.tracked.1.tag.1       Tracked Nth, Nth tag
dom.tracked.1.start       Tracked Nth, start time
dom.tracked.1.end         Tracked Nth, end time, blank if closed
dom.tracked.1.duration    Tracked Nth, elapsed
dom.tracked.1.json        Tracked Nth, interval as JSON</code><button onclick="copyCode(this)" class="copybtn">copy</button></pre></details>

  <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="">dom.rc.&lt;name&gt;             Configuration setting</code><button onclick="copyCode(this)" class="copybtn">copy</button></pre></details>

  <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>ffmpeg</title><link>https://hiraethecho.github.io/docs/software/ffmpeg/</link><pubDate>Tue, 17 Jun 2025 00:00:00 +0000</pubDate><author>wyz2016zxc@outlook.com(Hiraeth)</author><guid>https://hiraethecho.github.io/docs/software/ffmpeg/</guid><description>&lt;h1 id="ffmpeg"&gt;
&lt;a class="anchor inpage" href="#ffmpeg"&gt;#&lt;/a&gt;ffmpeg&lt;/h1&gt;
&lt;details open&gt;
&lt;summary&gt;tldr&lt;/summary&gt;&lt;pre
class="codeblock"
&gt;&lt;code class="language-tldr" data-lang="tldr"&gt; Video conversion tool.
More information: &amp;lt;https://ffmpeg.org&amp;gt;.
Extract the sound from a video and save it as MP3:
ffmpeg -i path/to/video.mp4 -vn path/to/sound.mp3
Transcode a FLAC file to Red Book CD format (44100kHz, 16bit):
ffmpeg -i path/to/input_audio.flac -ar 44100 -sample_fmt s16 path/to/output_audio.wav
Save a video as GIF, scaling the height to 1000px and setting framerate to 15:
ffmpeg -i path/to/video.mp4 [-vf|-filter:v] &amp;#39;scale=-1:1000&amp;#39; -r 15 path/to/output.gif
Combine numbered images (`frame_1.jpg`, `frame_2.jpg`, etc) into a video or GIF:
ffmpeg -i path/to/frame_%d.jpg -f image2 video.mpg|video.gif
Trim a video from a given start time mm:ss to an end time mm2:ss2 (omit the -to flag to trim till the end):
ffmpeg -i path/to/input_video.mp4 -ss mm:ss -to mm2:ss2 [-c|-codec] copy path/to/output_video.mp4
Convert AVI video to MP4. AAC Audio @ 128kbit, h264 Video @ CRF 23:
ffmpeg -i path/to/input_video.avi [-c|-codec]:a aac -b:a 128k [-c|-codec]:v libx264 -crf 23 path/to/output_video.mp4
Remux MKV video to MP4 without re-encoding audio or video streams:
ffmpeg -i path/to/input_video.mkv [-c|-codec] copy path/to/output_video.mp4
Convert MP4 video to VP9 codec. For the best quality, use a CRF value (recommended range 15-35) and -b:v MUST be 0:
ffmpeg -i path/to/input_video.mp4 [-c|-codec]:v libvpx-vp9 -crf 30 -b:v 0 [-c|-codec]:a libopus -vbr on -threads number_of_threads path/to/output_video.webm&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="ffmpeg">
  <a class="anchor inpage" href="#ffmpeg">#</a>ffmpeg</h1>
<details open>
    <summary>tldr</summary><pre
        class="codeblock"
      ><code class="language-tldr" data-lang="tldr">  Video conversion tool.
  More information: &lt;https://ffmpeg.org&gt;.

  Extract the sound from a video and save it as MP3:

      ffmpeg -i path/to/video.mp4 -vn path/to/sound.mp3

  Transcode a FLAC file to Red Book CD format (44100kHz, 16bit):

      ffmpeg -i path/to/input_audio.flac -ar 44100 -sample_fmt s16 path/to/output_audio.wav

  Save a video as GIF, scaling the height to 1000px and setting framerate to 15:

      ffmpeg -i path/to/video.mp4 [-vf|-filter:v] &#39;scale=-1:1000&#39; -r 15 path/to/output.gif

  Combine numbered images (`frame_1.jpg`, `frame_2.jpg`, etc) into a video or GIF:

      ffmpeg -i path/to/frame_%d.jpg -f image2 video.mpg|video.gif

  Trim a video from a given start time mm:ss to an end time mm2:ss2 (omit the -to flag to trim till the end):

      ffmpeg -i path/to/input_video.mp4 -ss mm:ss -to mm2:ss2 [-c|-codec] copy path/to/output_video.mp4

  Convert AVI video to MP4. AAC Audio @ 128kbit, h264 Video @ CRF 23:

      ffmpeg -i path/to/input_video.avi [-c|-codec]:a aac -b:a 128k [-c|-codec]:v libx264 -crf 23 path/to/output_video.mp4

  Remux MKV video to MP4 without re-encoding audio or video streams:

      ffmpeg -i path/to/input_video.mkv [-c|-codec] copy path/to/output_video.mp4

  Convert MP4 video to VP9 codec. For the best quality, use a CRF value (recommended range 15-35) and -b:v MUST be 0:

      ffmpeg -i path/to/input_video.mp4 [-c|-codec]:v libvpx-vp9 -crf 30 -b:v 0 [-c|-codec]:a libopus -vbr on -threads number_of_threads path/to/output_video.webm</code><button onclick="copyCode(this)" class="copybtn">copy</button></pre></details>

  <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>taskwarrior</title><link>https://hiraethecho.github.io/docs/software/taskwarrior/</link><pubDate>Tue, 17 Jun 2025 00:00:00 +0000</pubDate><author>wyz2016zxc@outlook.com(Hiraeth)</author><guid>https://hiraethecho.github.io/docs/software/taskwarrior/</guid><description>&lt;h1 id="taskwarrior"&gt;
&lt;a class="anchor inpage" href="#taskwarrior"&gt;#&lt;/a&gt;taskwarrior&lt;/h1&gt;
&lt;p&gt;Command-line to-do list manager.
.&lt;/p&gt;
&lt;h2 id="overview"&gt;
&lt;a class="anchor inpage" href="#overview"&gt;##&lt;/a&gt;overview&lt;/h2&gt;
&lt;p&gt;Taskwarrior has a flexible command line syntax, but it may not be clear at first what the underlying structure means. Here is the general form of the syntax:&lt;/p&gt;
&lt;p&gt;&lt;figure&gt;
&lt;a
href="https://taskwarrior.org/images/syntax.png"
class="img-link"
data-sub-html=""
target="_blank"
&gt;
&lt;img
src="https://taskwarrior.org/images/syntax.png"
alt=""loading="lazy"
/&gt;
&lt;/a&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p&gt;There are four parts to the syntax (&lt;code&gt;filter&lt;/code&gt;, &lt;code&gt;command&lt;/code&gt;, &lt;code&gt;modifications&lt;/code&gt;, and &lt;code&gt;miscellaneous&lt;/code&gt;), and each part is optional.&lt;/p&gt;
&lt;details open&gt;
&lt;summary&gt;tldr&lt;/summary&gt;&lt;pre
class="codeblock"
&gt;&lt;code class="language-tldr" data-lang="tldr"&gt; Add a new task which is due tomorrow:
task add description due:tomorrow
Update a task&amp;#39;s priority:
task task_id modify priority:H|M|L
Complete a task:
task task_id done
Delete a task:
task task_id delete
List all open tasks:
task list
List open tasks due before the end of the week:
task list due.before:eow
Show a graphical burndown chart, by day:
task burndown.daily
List all reports:
task reports&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;man:&lt;/p&gt;</description><content:encoded><![CDATA[<h1 id="taskwarrior">
  <a class="anchor inpage" href="#taskwarrior">#</a>taskwarrior</h1>
<p>Command-line to-do list manager. 
.</p>
<h2 id="overview">
  <a class="anchor inpage" href="#overview">##</a>overview</h2>
<p>Taskwarrior has a flexible command line syntax, but it may not be clear at first what the underlying structure means. Here is the general form of the syntax:</p>
<p><figure>
  <a
    href="https://taskwarrior.org/images/syntax.png"
    class="img-link"
    data-sub-html=""
    target="_blank"
  >
    <img
      src="https://taskwarrior.org/images/syntax.png"
      alt=""loading="lazy"
    />
  </a></figure>
</p>
<p>There are four parts to the syntax (<code>filter</code>, <code>command</code>, <code>modifications</code>, and <code>miscellaneous</code>), and each part is optional.</p>
<details open>
    <summary>tldr</summary><pre
        class="codeblock"
      ><code class="language-tldr" data-lang="tldr">  Add a new task which is due tomorrow:
      task add description due:tomorrow

  Update a task&#39;s priority:

      task task_id modify priority:H|M|L

  Complete a task:

      task task_id done

  Delete a task:

      task task_id delete

  List all open tasks:

      task list

  List open tasks due before the end of the week:

      task list due.before:eow

  Show a graphical burndown chart, by day:

      task burndown.daily

  List all reports:

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

  <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>man:</p>
<details open>
    <summary>man</summary><pre
        class="chroma codeblock"
      ><code class="language-man" data-lang="man"
          ><span style="display:flex;"><span>Documentation for Taskwarrior can be found using &#39;man task&#39;, &#39;man taskrc&#39;, &#39;man task-color&#39;, &#39;man task-sync&#39; or at https://taskwarrior.org
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span>The general form of commands is:
</span></span><span style="display:flex;"><span>  task [&lt;filter&gt;] &lt;command&gt; [&lt;mods&gt;]
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span>The &lt;mods&gt; consist of zero or more changes to apply to the selected tasks, such as:
</span></span><span style="display:flex;"><span>  task &lt;filter&gt; &lt;command&gt; project:Home
</span></span><span style="display:flex;"><span>  task &lt;filter&gt; &lt;command&gt; +weekend +garden due:tomorrow
</span></span><span style="display:flex;"><span>  task &lt;filter&gt; &lt;command&gt; Description/annotation text
</span></span><span style="display:flex;"><span>  task &lt;filter&gt; &lt;command&gt; /from/to/     &lt;- replace first match
</span></span><span style="display:flex;"><span>  task &lt;filter&gt; &lt;command&gt; /from/to/g    &lt;- replace all matches
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span>Tags are arbitrary words, any quantity:
</span></span><span style="display:flex;"><span>  +tag       The + means add the tag
</span></span><span style="display:flex;"><span>  -tag       The - means remove the tag
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span>Built-in attributes are:
</span></span><span style="display:flex;"><span>  description:    Task description text
</span></span><span style="display:flex;"><span>  status:         Status of task - pending, completed, deleted, waiting
</span></span><span style="display:flex;"><span>  project:        Project name
</span></span><span style="display:flex;"><span>  priority:       Priority
</span></span><span style="display:flex;"><span>  due:            Due date
</span></span><span style="display:flex;"><span>  recur:          Recurrence frequency
</span></span><span style="display:flex;"><span>  until:          Expiration date of a task
</span></span><span style="display:flex;"><span>  limit:          Desired number of rows in report, or &#39;page&#39;
</span></span><span style="display:flex;"><span>  wait:           Date until task becomes pending
</span></span><span style="display:flex;"><span>  entry:          Date task was created
</span></span><span style="display:flex;"><span>  end:            Date task was completed/deleted
</span></span><span style="display:flex;"><span>  start:          Date task was started
</span></span><span style="display:flex;"><span>  scheduled:      Date task is scheduled to start
</span></span><span style="display:flex;"><span>  modified:       Date task was last modified
</span></span><span style="display:flex;"><span>  depends:        Other tasks that this task depends upon
</span></span><span style="display:flex;"><span>Alternately algebraic expressions support:
</span></span><span style="display:flex;"><span>  and  or  xor            Logical operators
</span></span><span style="display:flex;"><span>  &lt;  &lt;=  =  !=  &gt;=  &gt;     Relational operators
</span></span><span style="display:flex;"><span>  (  )                    Precedence
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span>  task due.before:eom priority.not:L   list
</span></span><span style="display:flex;"><span>  task &#39;(due &lt; eom and priority != L)&#39;  list</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="filter">
  <a class="anchor inpage" href="#filter">###</a>Filter</h3>
<p>A filter is a means of addressing a subset of tasks. Because filters are optional, the simplest case is no filter. A command with no filter addresses all tasks.</p>
<p>Generally filter arguments appear before the command, so any arguments to the left of the command are considered filter arguments.</p>
<p>There is a special case, in which a command that does not support modifications or miscellaneous arguments, expects only filter arguments, and so they can appear before or after the command, without confusing Taskwarrior:</p>
<p><figure>
  <a
    href="https://taskwarrior.org/images/filter.png"
    class="img-link"
    data-sub-html=""
    target="_blank"
  >
    <img
      src="https://taskwarrior.org/images/filter.png"
      alt=""loading="lazy"
    />
  </a></figure>
</p>
<h3 id="command">
  <a class="anchor inpage" href="#command">###</a>Command</h3>
<p>Each time you run Taskwarrior, you are issuing a <code>command</code> either explicitly, or implicitly with the default command (the <code>default.command</code> configuration setting). The command you specify determines how the command line is understood by Taskwarrior. Here are some examples of that:</p>
<p><figure>
  <a
    href="https://taskwarrior.org/images/syntaxes.png"
    class="img-link"
    data-sub-html=""
    target="_blank"
  >
    <img
      src="https://taskwarrior.org/images/syntaxes.png"
      alt=""loading="lazy"
    />
  </a></figure>
</p>
<p>The first example, <code>task list</code> is a report with no filter, and the second, <code>task +home list</code> is with a filter. The third, <code>task 12 modify project:Garden</code> has both a filter and modifications. The last example, <code>task show editor</code> has a miscellaneous argument.</p>
<p>Taskwarrior looks for the first argument on the command line that looks like an exact command name, and failing that, looks for an abbreviated command name. It is better to use the full name of a command to avoid ambiguity.</p>
<p>It is the position of the <code>command</code> argument, and the type of command that determines how the arguments are understood.</p>
<p>task的列信息</p>
<details open>
    <summary>task</summary><pre
        class="codeblock"
      ><code class="language-task" data-lang="task">Command          Category  R/W ID GC Recur Context Filter Mods Misc Description
columns          config     RO                                 Misc All supported columns and formatting styles
config           config     RO                                 Misc Change settings in the task configuration
reports          config     RO                                      Lists all supported reports
show             config     RO                                 Misc Shows all configuration variables or subset
udas             config     RO                                      Shows all the defined UDA details
commands         metadata   RO                                      Generates a list of all commands, with behavior details
stats            metadata   RO    GC          Ctxt   Filt           Shows task database statistics
ids              metadata   RO ID GC Recur           Filt           Shows the IDs of matching tasks, as a range
count            metadata   RO    GC Recur    Ctxt   Filt           Counts matching tasks
projects         metadata   RO    GC Recur    Ctxt   Filt           Shows all project names used
tags             metadata   RO    GC          Ctxt   Filt           Shows a list of all tags used
uuids            metadata   RO    GC Recur           Filt           Shows the UUIDs of matching tasks, as a space-separated list
context          context    RO                                 Misc Set and define contexts (default filters / modifications)</code><button onclick="copyCode(this)" class="copybtn">copy</button></pre></details>

  <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>internals</summary><pre
        class="codeblock"
      ><code class="language-internals" data-lang="internals">_aliases         internal   RO                                      Generates a list of all aliases, for autocompletion purposes
_columns         internal   RO                                      Displays only a list of supported columns
_commands        internal   RO                                      Generates a list of all commands, for autocompletion purposes
_config          internal   RO                                      Lists all supported configuration variables, for completion purposes
_context         internal   RO                                      Lists all supported contexts, for completion purposes
_get             internal   RO                                 Misc DOM Accessor
_ids             internal   RO ID GC Recur           Filt           Shows the IDs of matching tasks, in the form of a list
_projects        internal   RO    GC Recur           Filt           Shows only a list of all project names used
_show            internal   RO    GC                                Shows all configuration settings in a machine-readable format
_tags            internal   RO    GC Recur           Filt           Shows only a list of all tags used, for autocompletion purposes
_udas            internal   RO                                      Shows the defined UDAs for completion purposes
_unique          internal   RO ID GC                 Filt      Misc Generates lists of unique attribute values
_urgency         internal   RO    GC                 Filt           Displays the urgency measure of a task
_uuids           internal   RO    GC Recur           Filt           Shows the UUIDs of matching tasks, as a list
_version         internal   RO                                      Shows only the Taskwarrior version number
_zshattributes   internal   RO                                      Generates a list of all attributes, for zsh autocompletion purposes
_zshcommands     internal   RO                                      Generates a list of all commands, for zsh autocompletion purposes
_zshids          internal   RO ID GC Recur           Filt           Shows the IDs and descriptions of matching tasks
_zshuuids        internal   RO    GC Recur           Filt           Shows the UUIDs and descriptions of matching tasks</code><button onclick="copyCode(this)" class="copybtn">copy</button></pre></details>

  <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>operation</summary><pre
        class="codeblock"
      ><code class="language-operation" data-lang="operation">add              operation  RW                Ctxt        Mods      Adds a new task
annotate         operation  RW                       Filt Mods      Adds an
append           operation  RW                       Filt Mods      Appends text to
delete           operation  RW                Ctxt   Filt Mods      Deletes the
denotate         operation  RW                Ctxt   Filt      Misc Deletes an
done             operation  RW                Ctxt   Filt Mods      Marks the
duplicate        operation  RW                Ctxt   Filt Mods      Duplicates the
edit             operation  RW       Recur    Ctxt   Filt           Launches an
log              operation  RW                Ctxt        Mods      Adds a new task
modify           operation  RW                       Filt Mods      Modifies the
prepend          operation  RW                Ctxt   Filt Mods      Prepends text to
purge            operation  RW    GC          Ctxt   Filt           Removes the
start            operation  RW                Ctxt   Filt Mods      Marks specified
stop             operation  RW                Ctxt   Filt Mods      Removes the
undo             operation  RW                                      Reverts the most</code><button onclick="copyCode(this)" class="copybtn">copy</button></pre></details>

  <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>graphs</summary><pre
        class="codeblock"
      ><code class="language-graphs" data-lang="graphs">burndown.daily   graphs     RO    GC Recur    Ctxt   Filt           Shows a
burndown.monthly graphs     RO    GC Recur    Ctxt   Filt           Shows a
burndown.weekly  graphs     RO    GC Recur    Ctxt   Filt           Shows a
calendar         graphs     RO ID GC                           Misc Shows a
ghistory.annual  graphs     RO       Recur    Ctxt   Filt           Shows a
ghistory.daily   graphs     RO       Recur    Ctxt   Filt           Shows a
ghistory.monthly graphs     RO       Recur    Ctxt   Filt           Shows a
ghistory.weekly  graphs     RO       Recur    Ctxt   Filt           Shows a
history.annual   graphs     RO       Recur    Ctxt   Filt           Shows a report
history.daily    graphs     RO       Recur    Ctxt   Filt           Shows a report
history.monthly  graphs     RO       Recur    Ctxt   Filt           Shows a report
history.weekly   graphs     RO       Recur    Ctxt   Filt           Shows a report
summary          graphs     RO    GC          Ctxt   Filt           Shows a report</code><button onclick="copyCode(this)" class="copybtn">copy</button></pre></details>

  <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="modifications">
  <a class="anchor inpage" href="#modifications">###</a>Modifications</h3>
<p>If a command accepts modifications, they generally appear after the command. Most commands that accept modifications also accept filters, and so the filter arguments appear before the command, while the modifications appear after. Here is an example:</p>
<p><figure>
  <a
    href="https://taskwarrior.org/images/modification.png"
    class="img-link"
    data-sub-html=""
    target="_blank"
  >
    <img
      src="https://taskwarrior.org/images/modification.png"
      alt=""loading="lazy"
    />
  </a></figure>
</p>
<p>This command specifies a compound filter, consisting of more than one term. These terms are logically combined with an <code>and</code> operator by default, unless otherwise specified. In this case, tasks that have both the <code>home</code> tag, and a <code>status</code> value of <code>pending</code> are to be modified.</p>
<p>The modifications, appearing after the command, set the <code>priority</code> to <code>H</code> igh, and the <code>due</code> date to the end of the month (<code>eom</code>).</p>
<p>Because the filter is evaluated at runtime, we don’t know how many tasks will be modified. It could be none, one, many or all of the tasks. It could be determined with:</p>
<details open>
    <summary>TEXT</summary><pre
        class="codeblock"
      ><code class="language-" data-lang="">task &#43;home status:pending count</code><button onclick="copyCode(this)" class="copybtn">copy</button></pre></details>

  <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>The user writing this command would have an idea of how many tasks this will affect, but this is just an example, with no contextual data shown.</p>
<h3 id="miscellaneous">
  <a class="anchor inpage" href="#miscellaneous">###</a>Miscellaneous</h3>
<p>Some commands accept neither a filter, nor modifications, but do accept miscellaneous arguments. An example is the <code>show</code> command, that queries configuration settings, and does not accept a filter:</p>
<p><figure>
  <a
    href="https://taskwarrior.org/images/miscellaneous.png"
    class="img-link"
    data-sub-html=""
    target="_blank"
  >
    <img
      src="https://taskwarrior.org/images/miscellaneous.png"
      alt=""loading="lazy"
    />
  </a></figure>
</p>
<p>This is another special case, in which the command only accepts miscellaneous arguments, and so they can appear before or after the command.</p>
<h3 id="overrides">
  <a class="anchor inpage" href="#overrides">###</a>Overrides</h3>
<p>Overrides are temporary values for configuration settings, and can be specified anywhere on the command line, because they are not considered to be either filter, modification or miscellaneous. In fact, the command itself doesn’t see the overrides, instead they are handled before the command runs.</p>
<p><figure>
  <a
    href="https://taskwarrior.org/images/override.png"
    class="img-link"
    data-sub-html=""
    target="_blank"
  >
    <img
      src="https://taskwarrior.org/images/override.png"
      alt=""loading="lazy"
    />
  </a></figure>
</p>
<p>There can be any number of overrides on the command line, and they have no effect on the syntax.</p>
<h2 id="reports">
  <a class="anchor inpage" href="#reports">##</a>reports</h2>
<p>Taskwarrior has three kinds of reports. There are built-in reports that cannot be modified, such as <code>info</code> and <code>summary</code>. There are built-in reports which can be redefined completely or eliminated, such as <code>list</code>, <code>next</code>. And finally there are your own custom reports. To generate a list of <em>all</em> the reports, use the <code>reports</code> command:</p>
<details open>
    <summary>reposts</summary><pre
        class="codeblock"
      ><code class="language-reposts" data-lang="reposts">Report           Description
---------------- --------------------------------------------------
active           Active tasks
all              All tasks
blocked          Blocked tasks
blocking         Blocking tasks
burndown.daily   Shows a graphical burndown chart, by day
burndown.monthly Shows a graphical burndown chart, by month
burndown.weekly  Shows a graphical burndown chart, by week
completed        Completed tasks
ghistory.annual  Shows a graphical report of task history, by year
ghistory.monthly Shows a graphical report of task history, by month
history.annual   Shows a report of task history, by year
history.monthly  Shows a report of task history, by month
information      Shows all data and metadata
list             Most details of tasks
long             All details of tasks
ls               Few details of tasks
minimal          Minimal details of tasks
newest           Newest tasks
next             Most urgent tasks
oldest           Oldest tasks
overdue          Overdue tasks
projects         Shows all project names used
ready            Most urgent actionable tasks
recurring        Recurring Tasks
summary          Shows a report of task status by project
tags             Shows a list of all tags used
unblocked        Unblocked tasks
waiting          Waiting (hidden) tasks

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

  <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="built-in-static-reports">
  <a class="anchor inpage" href="#built-in-static-reports">###</a>Built-In Static Reports</h3>
<p>Typically, a report consists of a table of data, with one row of data corresponding to a single task, with the task attributes represented as columns. But there are other reports which do not conform to this structure. Those are the built-in static reports, and they are not modifiable, because they are quirky and require custom code. These reports are:</p>
<details open>
    <summary>TEXT</summary><pre
        class="codeblock"
      ><code class="language-" data-lang="">burndown.daily
burndown.monthly
burndown.weekly
calendar
colors
export
ghistory.annual
ghistory.monthly
history.annual
history.monthly
information
summary
timesheet</code><button onclick="copyCode(this)" class="copybtn">copy</button></pre></details>

  <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>Each of these reports takes non-standard arguments, may or may not support filters, and generates distinctive output.</p>
<h3 id="built-in-modifiable-reports">
  <a class="anchor inpage" href="#built-in-modifiable-reports">###</a>Built-In Modifiable Reports</h3>
<p>These reports are standard format, using standard arguments, and are also modifiable.</p>
<details open>
    <summary>TEXT</summary><pre
        class="codeblock"
      ><code class="language-" data-lang="">active
all
blocked
blocking
completed
list
long
ls
minimal
newest
next
oldest
overdue
ready
recurring
unblocked
waiting</code><button onclick="copyCode(this)" class="copybtn">copy</button></pre></details>

  <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>Suppose you wanted to remove a column from one of these reports, for example removing <code>tags</code> from the <code>minimal</code> report. First look at the existing columns and labels of the <code>minimal</code> report:</p>
<p><code>task show report.minimal.labels</code> shows</p>
<details open>
    <summary>TEXT</summary><pre
        class="codeblock"
      ><code class="language-" data-lang="">Config Variable       Value
--------------------- ---------------------------
report.minimal.labels ID,Project,Tags,Description</code><button onclick="copyCode(this)" class="copybtn">copy</button></pre></details>

  <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>and <code>task show report.minimal.columns</code> shows</p>
<details open>
    <summary>TEXT</summary><pre
        class="codeblock"
      ><code class="language-" data-lang="">Config Variable        Value
---------------------- ---------------------------------------
report.minimal.columns id,project,tags.count,description.count</code><button onclick="copyCode(this)" class="copybtn">copy</button></pre></details>

  <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>Having determined what the current values are, simply override with the new values:</p>
<details open>
    <summary>shell</summary><pre
        class="chroma codeblock"
      ><code class="language-shell" data-lang="shell"
          ><span style="display:flex;"><span>$ task config report.minimal.labels  <span style="color:#e6db74">&#39;ID,Project,Description&#39;</span>
</span></span><span style="display:flex;"><span>...
</span></span><span style="display:flex;"><span>$ task config report.minimal.columns <span style="color:#e6db74">&#39;id,project,description.count&#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>You can think of the built-in modifiable reports as a set of default custom reports.</p>
<h3 id="custom-reports">
  <a class="anchor inpage" href="#custom-reports">###</a>Custom Reports</h3>
<p>Defining a custom report is straightforward. You have control over the data shown, the sort order and the column labels. A custom report is simply a set of configuration values, and those values include:</p>
<ul>
<li>description</li>
<li>columns</li>
<li>labels</li>
<li>sort</li>
<li>filter</li>
</ul>
<p>Let us quickly create a custom report, which will be named <code>simple</code>. This report will display the task ID, project name and description. We will need to gather the five settings listed above.</p>
<p>The description is the easiest, and in this case the report will be described:</p>
<details open>
    <summary>coffeescript</summary><pre
        class="chroma codeblock"
      ><code class="language-coffeescript" data-lang="coffeescript"
          ><span style="display:flex;"><span><span style="color:#a6e22e">Simple</span> <span style="color:#a6e22e">list</span> <span style="color:#66d9ef">of</span> <span style="color:#a6e22e">open</span> <span style="color:#a6e22e">tasks</span> <span style="color:#66d9ef">by</span> <span style="color:#a6e22e">project</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>This is just a descriptive label that will be used when the report is listed. Next we need to specify the columns in the report, and the order in which those are shown. Here the <code>_columns</code> helper command will show the columns available:</p>
<p><code>task _columns</code> shows</p>
<details open>
    <summary>TEXT</summary><pre
        class="codeblock"
      ><code class="language-" data-lang="">depends
description
due
end
entry
foo
id
imask
mask
modified
parent
priority
project
recur
scheduled
start
status
tags
until
urgency
uuid
wait</code><button onclick="copyCode(this)" class="copybtn">copy</button></pre></details>

  <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>That represents all the data that Taskwarrior stores, and therefore all the data that may be shown in a report. Our <code>simple</code> report will show id, project and description, which are all in the list. This means our column list is simply:</p>
<details open>
    <summary>TEXT</summary><pre
        class="codeblock"
      ><code class="language-" data-lang="">id,project,description</code><button onclick="copyCode(this)" class="copybtn">copy</button></pre></details>

  <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>But there are also formats for each column, and the <code>columns</code> command shows them, with examples. Here are the formats for our three columns: <code>task columns id</code></p>
<details open>
    <summary>TEXT</summary><pre
        class="codeblock"
      ><code class="language-" data-lang="">Columns Supported Formats Example
------- ----------------- ------------------------------------
id      number*           123
uuid    long*             f30cb9c3-3fc0-483f-bfb2-3bf134f00694
        short             f30cb9c3</code><button onclick="copyCode(this)" class="copybtn">copy</button></pre></details>

  <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>This is easy, because there is only one <code>id</code> format. <code>task columns project</code></p>
<details open>
    <summary>TEXT</summary><pre
        class="codeblock"
      ><code class="language-" data-lang="">Columns Supported Formats Example
------- ----------------- -------------
project full*             home.garden
        parent            home
        indented            home.garden</code><button onclick="copyCode(this)" class="copybtn">copy</button></pre></details>

  <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>There are three formats for the <code>project</code> column, and the default, <code>full</code> is the one we want. <code>task columns description</code></p>
<details open>
    <summary>TEXT</summary><pre
        class="codeblock"
      ><code class="language-" data-lang="">Columns     Supported Formats Example
----------- ----------------- -----------------------------------------------------------------------------
description combined*         Move your clothes down on to the lower peg
                                2014-02-08 Immediately before your lunch
                                2014-02-08 If you are playing in the match this afternoon
                                2014-02-08 Before you write your letter home
                                2014-02-08 If you&#39;re not getting your hair cut
            desc              Move your clothes down on to the lower peg
            oneline           Move your clothes down on to the lower peg 2014-02-08 Immediately before ...
                              this afternoon 2014-02-08 Before you write your letter home 2014-02-08 If ...
            truncated         Move your clothes do...
            count             Move your clothes down on to the lower peg [4]</code><button onclick="copyCode(this)" class="copybtn">copy</button></pre></details>

  <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>There are five formats for description. This time we prefer the <code>count</code> format, so our columns list is now:</p>
<details open>
    <summary>TEXT</summary><pre
        class="codeblock"
      ><code class="language-" data-lang="">id,project,description.count</code><button onclick="copyCode(this)" class="copybtn">copy</button></pre></details>

  <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>Labels are the column heading labels in the report. There are defaults, but we wish to specify these like this:</p>
<details open>
    <summary>TEXT</summary><pre
        class="codeblock"
      ><code class="language-" data-lang="">ID,Proj,Desc</code><button onclick="copyCode(this)" class="copybtn">copy</button></pre></details>

  <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>Sorting is also straightforward, and we want the tasks sorted by project, and then by entry, which is the creation date for a task. This illustrates that a task attribute that is not visible can be used in the sort. The sort order is then:</p>
<details open>
    <summary>TEXT</summary><pre
        class="codeblock"
      ><code class="language-" data-lang="">project&#43;/,entry&#43;</code><button onclick="copyCode(this)" class="copybtn">copy</button></pre></details>

  <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>The <code>+</code> means an ascending order, but we could have used <code>-</code> for descending. The <code>/</code> solidus indicates that <code>project</code> is a break column, which means a blank line is inserted between unique values, for a visual grouping effect. 2.4.0</p>
<p>Finally, we need a filter, otherwise our report will just display all tasks, which is rarely wanted. Here we wish to see only pending tasks, and that means the filter is:</p>
<details open>
    <summary>TEXT</summary><pre
        class="codeblock"
      ><code class="language-" data-lang="">status:pending</code><button onclick="copyCode(this)" class="copybtn">copy</button></pre></details>

  <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>Now we have our report definition, so we just create the five configuration entries like this:</p>
<details open>
    <summary>shell</summary><pre
        class="chroma codeblock"
      ><code class="language-shell" data-lang="shell"
          ><span style="display:flex;"><span>task config report.simple.description <span style="color:#e6db74">&#39;Simple list of open tasks by project&#39;</span>
</span></span><span style="display:flex;"><span>task config report.simple.columns     <span style="color:#e6db74">&#39;id,project,description.count&#39;</span>
</span></span><span style="display:flex;"><span>task config report.simple.labels      <span style="color:#e6db74">&#39;ID,Proj,Desc&#39;</span>
</span></span><span style="display:flex;"><span>task config report.simple.sort        <span style="color:#e6db74">&#39;project+/,entry+&#39;</span>
</span></span><span style="display:flex;"><span>task config report.simple.filter      <span style="color:#e6db74">&#39;status:pending&#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>Note the equivalent report directly from the config file would look like that:</p>
<details open>
    <summary>config</summary><pre
        class="codeblock"
      ><code class="language-config" data-lang="config">report.simple.description=Simple list of open tasks by project
report.simple.columns=id,project,description.count
report.simple.labels=ID,Proj,Desc
report.simple.sort=project&#43;\/,entry&#43;
report.simple.filter=status:pending</code><button onclick="copyCode(this)" class="copybtn">copy</button></pre></details>

  <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>And it is finished. Run the report like this:</p>
<details open>
    <summary>shell</summary><pre
        class="chroma codeblock"
      ><code class="language-shell" data-lang="shell"
          ><span style="display:flex;"><span>task simple
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span>ID Proj Desc
</span></span><span style="display:flex;"><span>-- ---- -----------------
</span></span><span style="display:flex;"><span> <span style="color:#ae81ff">1</span> Home Wash the windows
</span></span><span style="display:flex;"><span> <span style="color:#ae81ff">3</span> Home Vacuum the floors
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span> <span style="color:#ae81ff">2</span>      Food shopping</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>Custom reports also show up in the help output.</p>
<details open>
    <summary>shell</summary><pre
        class="chroma codeblock"
      ><code class="language-shell" data-lang="shell"
          ><span style="display:flex;"><span>task help | grep simple
</span></span><span style="display:flex;"><span>task  simple              Simple list of open tasks by project</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>I can inspect the configuration.</p>
<details open>
    <summary>shell</summary><pre
        class="chroma codeblock"
      ><code class="language-shell" data-lang="shell"
          ><span style="display:flex;"><span>task show report.simple
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span>Config Variable           Value
</span></span><span style="display:flex;"><span>------------------------- ------------------------------------
</span></span><span style="display:flex;"><span>report.simple.columns     id,project,description.count
</span></span><span style="display:flex;"><span>report.simple.description Simple list of open tasks by project
</span></span><span style="display:flex;"><span>report.simple.filter      status:pending
</span></span><span style="display:flex;"><span>report.simple.labels      ID,Proj,Desc
</span></span><span style="display:flex;"><span>report.simple.sort        project+/,entry+</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>Now the report is fully configured, it joins the others and is used in the same way.</p>
<h2 id="attributes">
  <a class="anchor inpage" href="#attributes">##</a>attributes</h2>
<h3 id="built-in">
  <a class="anchor inpage" href="#built-in">###</a>built-in</h3>
<details open>
    <summary>TEXT</summary><pre
        class="codeblock"
      ><code class="language-" data-lang="">Built-in attributes are:
  description:    Task description text
  status:         Status of task - pending, completed, deleted, waiting
  project:        Project name
  priority:       Priority
  due:            Due date
  recur:          Recurrence frequency
  until:          Expiration date of a task
  limit:          Desired number of rows in report, or &#39;page&#39;
  wait:           Date until task becomes pending
  entry:          Date task was created
  end:            Date task was completed/deleted
  start:          Date task was started
  scheduled:      Date task is scheduled to start
  modified:       Date task was last modified
  depends:        Other tasks that this task depends upon</code><button onclick="copyCode(this)" class="copybtn">copy</button></pre></details>

  <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="modifiers">
  <a class="anchor inpage" href="#modifiers">###</a>modifiers</h3>
<p>Attribute modifiers make filters more precise. Supported modifiers are:</p>
<details open>
    <summary>TEXT</summary><pre
        class="codeblock"
      ><code class="language-" data-lang="">  Modifiers         Example            Equivalent           Meaning
  ----------------  -----------------  -------------------  -------------------------
                    due:today          due = today          Fuzzy match
  not               due.not:today      due != today         Fuzzy non-match
  before, below     due.before:today   due &lt; today          Exact date comparison
  after, above      due.after:today    due &gt;= tomorrow      Exact date comparison
  none              project.none:      project == &#39;&#39;        Empty
  any               project.any:       project !== &#39;&#39;       Not empty
  is, equals        project.is:x       project == x         Exact match
  isnt              project.isnt:x     project !== x        Exact non-match
  has, contains     desc.has:Hello     desc ~ Hello         Pattern match
  hasnt,            desc.hasnt:Hello   desc !~ Hello        Pattern non-match
  startswith, left  desc.left:Hel      desc ~ &#39;^Hel&#39;        Beginning match
  endswith, right   desc.right:llo     desc ~ &#39;llo$&#39;        End match
  word              desc.word:Hello    desc ~ &#39;\bHello\b&#39;   Boundaried word match
  noword            desc.noword:Hello  desc !~ &#39;\bHello\b&#39;  Boundaried word non-match

Alternately algebraic expressions support:
  and  or  xor            Logical operators
  &lt;  &lt;=  =  !=  &gt;=  &gt;     Relational operators
  (  )                    Precedence

  task due.before:eom priority.not:L   list
  task &#39;(due &lt; eom and priority != L)&#39;  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><p>note that</p>
<details open>
    <summary>TEXT</summary><pre
        class="codeblock"
      ><code class="language-" data-lang="">  by         due.by:today       due &lt;= today         Exact date comparison</code><button onclick="copyCode(this)" class="copybtn">copy</button></pre></details>

  <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="how-recurrence-works">
  <a class="anchor inpage" href="#how-recurrence-works">###</a>How Recurrence Works</h3>
<p>A recurring task is a task with a due date that keeps coming back as a reminder. Here is an example:</p>
<details open>
    <summary>TEXT</summary><pre
        class="codeblock"
      ><code class="language-" data-lang="">task add Pay the rent due:1st recur:monthly until:2015-03-31
Created task 123.</code><button onclick="copyCode(this)" class="copybtn">copy</button></pre></details>

  <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>This task has a due date, a monthly recurrence, and an optional until date coinciding with the end of the lease.</p>
<p>A recurring task is given a status of <code>recurring</code> which hides it from view, although you can see it in the <code>all</code> report. The recurring task you create is called the template task, from which recurring tasks instances are created. So the template remains hidden, and the recurring instances that spawn from it are the tasks that you will see and complete.</p>
<p>Here is a look at the template task:</p>
<details open>
    <summary>shell</summary><pre
        class="chroma codeblock"
      ><code class="language-shell" data-lang="shell"
          ><span style="display:flex;"><span>task <span style="color:#ae81ff">123</span> info
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span>Name        Value
</span></span><span style="display:flex;"><span>ID          <span style="color:#ae81ff">123</span>
</span></span><span style="display:flex;"><span>Description Pay the rent
</span></span><span style="display:flex;"><span>Status      Recurring
</span></span><span style="display:flex;"><span>Recurrence  monthly
</span></span><span style="display:flex;"><span>Entered     2014-03-01 12:13:28 <span style="color:#f92672">(</span><span style="color:#ae81ff">42</span> secs<span style="color:#f92672">)</span>
</span></span><span style="display:flex;"><span>Due         2014-04-01 00:00:00
</span></span><span style="display:flex;"><span>Until       2015-03-31 00:00:00
</span></span><span style="display:flex;"><span>UUID        64bcf8fd-74d5-40d2-9e57-1d6a5922cdfc
</span></span><span style="display:flex;"><span>Urgency     2.4</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>Now if you run a report, such as <code>task list</code>, you will see the first instance of that recurring task generated. We can take a look at the instance:</p>
<details open>
    <summary>shell</summary><pre
        class="chroma codeblock"
      ><code class="language-shell" data-lang="shell"
          ><span style="display:flex;"><span>task <span style="color:#ae81ff">124</span> info
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span>Name        Value
</span></span><span style="display:flex;"><span>ID          <span style="color:#ae81ff">124</span>
</span></span><span style="display:flex;"><span>Description Pay the rent
</span></span><span style="display:flex;"><span>Status      Pending
</span></span><span style="display:flex;"><span>Recurrence  monthly
</span></span><span style="display:flex;"><span>Parent task 64bcf8fd-74d5-40d2-9e57-1d6a5922cdfc
</span></span><span style="display:flex;"><span>Mask Index  <span style="color:#ae81ff">0</span>
</span></span><span style="display:flex;"><span>Entered     2014-03-01 12:17:03 <span style="color:#f92672">(</span><span style="color:#ae81ff">15</span> secs<span style="color:#f92672">)</span>
</span></span><span style="display:flex;"><span>Due         2014-04-01 00:00:00
</span></span><span style="display:flex;"><span>Until       2015-03-31 00:00:00
</span></span><span style="display:flex;"><span>UUID        29d2df7a-1165-4559-b974-a727519e00f1
</span></span><span style="display:flex;"><span>Urgency     2.4</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>Notice how the instance has a status <code>pending</code>, and a reference back to the template task (Parent task). In addition, you can see it inherited the recurrence and description, and if there was a project, priority and tags, those would also be inherited.</p>
<p>The recurring instance has an attribute named ‘Mask Index’, which is zero. This indicates that it is the first of the many recurring task instances, the counting being zero-based.</p>
<p>Now if we look back at the template task, we see changes:</p>
<details open>
    <summary>shell</summary><pre
        class="chroma codeblock"
      ><code class="language-shell" data-lang="shell"
          ><span style="display:flex;"><span>task <span style="color:#ae81ff">123</span> info
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span>Name          Value
</span></span><span style="display:flex;"><span>ID            <span style="color:#ae81ff">123</span>
</span></span><span style="display:flex;"><span>Description   Pay the rent
</span></span><span style="display:flex;"><span>Status        Recurring
</span></span><span style="display:flex;"><span>Recurrence    monthly
</span></span><span style="display:flex;"><span>Mask          -
</span></span><span style="display:flex;"><span>Entered       2014-03-01 12:13:28 <span style="color:#f92672">(</span><span style="color:#ae81ff">3</span> mins<span style="color:#f92672">)</span>
</span></span><span style="display:flex;"><span>Due           2014-04-01 00:00:00
</span></span><span style="display:flex;"><span>Until         2015-03-31 00:00:00
</span></span><span style="display:flex;"><span>Last modified 2014-03-01 12:17:03 <span style="color:#f92672">(</span><span style="color:#ae81ff">24</span> secs<span style="color:#f92672">)</span>
</span></span><span style="display:flex;"><span>UUID          64bcf8fd-74d5-40d2-9e57-1d6a5922cdfc
</span></span><span style="display:flex;"><span>Urgency       2.4
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span>Date                Modification
</span></span><span style="display:flex;"><span>2014-03-01 12:17:03 Mask set to <span style="color:#e6db74">&#39;-&#39;</span>.
</span></span><span style="display:flex;"><span>                    Modified set to <span style="color:#e6db74">&#39;2014-03-01 12:17:03&#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><blockquote class="alert alert-note">
      <p class="alert-heading">template mask</p><p>The template task now has a <code>mask</code> attribute, and some change history. That <code>mask</code> is a string of task statuses. It has a value of <code>-</code> which indicates that one instance was created, task 124, because it is one character long. The <code>-</code> means that instance is still pending. This is how the template task keeps track of what it does and does not need to generate. When the task instance changes status that <code>-</code> becomes <code>+</code> (completed) or <code>X</code> (deleted) or <code>W</code> (waiting).</p></blockquote><p>Note that you never directly interact with task 123, the template task. It is hidden for a reason. Instead, you interact with the recurring task instances, and in most cases, changes are propagated to the template task and optionally other sibling tasks.</p>
<p>In this example one task instance is generated for the next due period. This is because the configuration setting <code>recurrence.limit</code> is set to 1, the default. If this number is increased to 2, then you would see the next 2 instances generated. Note that this only generates two steps into the future, without regard for whether those two instances are completed or not - don’t expect to complete the first task and see a new one pop up immediately.</p>
<h2 id="filter-1">
  <a class="anchor inpage" href="#filter-1">##</a>filter</h2>
<details open>
    <summary>TEXT</summary><pre
        class="codeblock"
      ><code class="language-" data-lang="">The &lt;filter&gt; consists of zero or more restrictions on which tasks to select, such as:
  task                                      &lt;command&gt; &lt;mods&gt;
  task 28                                   &lt;command&gt; &lt;mods&gt;
  task &#43;weekend                             &lt;command&gt; &lt;mods&gt;
  task project:Home due.before:today        &lt;command&gt; &lt;mods&gt;
  task ebeeab00-ccf8-464b-8b58-f7f2d606edfb &lt;command&gt; &lt;mods&gt;

By default, filter elements are combined with an implicit &#39;and&#39; operator, but &#39;or&#39; and &#39;xor&#39; may also be used, provided parentheses are included:
  task &#39;(/[Cc]at|[Dd]og/ or /[0-9]&#43;/)&#39;      &lt;command&gt; &lt;mods&gt;

A filter may target specific tasks using ID or UUID numbers.  To specify multiple tasks use one of these forms:
  task 1,2,3                                    delete
  task 1-3                                      info
  task 1,2-5,19                                 modify pri:H
  task 4-7 ebeeab00-ccf8-464b-8b58-f7f2d606edfb info</code><button onclick="copyCode(this)" class="copybtn">copy</button></pre></details>

  <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="tags-virtual-tags">
  <a class="anchor inpage" href="#tags-virtual-tags">###</a>Tags, Virtual Tags</h3>
<p>Tags are arbitrary words, any quantity:</p>
<p>+tag The + means add the tag
-tag The - means remove the tag</p>
<p>The basic tag syntax is very powerful and simple to use. There are two ways to use this, shown here:</p>
<details open>
    <summary>shell</summary><pre
        class="chroma codeblock"
      ><code class="language-shell" data-lang="shell"
          ><span style="display:flex;"><span>task +HOME list
</span></span><span style="display:flex;"><span>task -WORK list</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>These two commands illustrate the complete tag interface. The first command is a filter that lists only tasks that have the <code>HOME</code> tag. The second command is a filter that lists only tasks that <em>do not</em> have the <code>WORK</code> tag. The + and - syntax therefore means presence and absence of a tag. This is simple to use, and can be combined like this:</p>
<details open>
    <summary>shell</summary><pre
        class="chroma codeblock"
      ><code class="language-shell" data-lang="shell"
          ><span style="display:flex;"><span>task +HOME -WORK list</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>This shows tasks that have the <code>HOME</code> tag, but do not have the <code>WORK</code> tag. This is a very simple and easy to use mechanism, but it does require that your tasks are properly tagged. In other words, it is based directly on task metadata.</p>
<p>A tag may be any single word that does not start with a digit, punctuation, or mathematical operator.</p>
<h4 id="supported-virtual-tags">
  <a class="anchor inpage" href="#supported-virtual-tags">####</a>Supported Virtual Tags</h4>
<p>Since version 2.2.0, Taskwarrior has supported virtual tags, and the list will continue to grow. Here is the full list of supported virtual tags:</p>
<ul>
<li><code>BLOCKED</code> - Is the task dependent on another incomplete task?</li>
<li><code>UNBLOCKED</code> - The opposite of <code>BLOCKED</code>, for convenience. Note <code>+BLOCKED</code> == <code>-UNBLOCKED</code> and vice versa.</li>
<li><code>BLOCKING</code> - Does another task depend on this incomplete task?</li>
<li><code>DUE</code> - Is this task due within 7 days? Determined by <code>rc.due</code></li>
<li><code>DUETODAY</code> - Is this task due sometime today?</li>
<li><code>TODAY</code> - Is this task due sometime today?</li>
<li><code>OVERDUE</code> - Is this task past its due date?</li>
<li><code>WEEK</code> - Is this task due this week? 2.3.0</li>
<li><code>MONTH</code> - Is this task due this month? 2.3.0</li>
<li><code>QUARTER</code> - Is this task due this quarter? 2.6.0</li>
<li><code>YEAR</code> - Is this task due this year? 2.3.0</li>
<li><code>ACTIVE</code> - Is the task active, i.e. does it have a start date?</li>
<li><code>SCHEDULED</code> - Is the task scheduled, i.e. does it have a scheduled date?</li>
<li><code>PARENT</code> - Is the task a hidden parent recurring task? 2.3.0</li>
<li><code>CHILD</code> - Is the task a recurring child task?</li>
<li><code>UNTIL</code> - Does the task expire, i.e. does it have an until date?</li>
<li><code>WAITING</code> - Is the task hidden, i.e. does it have a wait date?</li>
<li><code>ANNOTATED</code> - Does the task have any annotations?</li>
<li><code>READY</code> - Is the task pending, not blocked, and either not scheduled, or scheduled before now. 2.4.0</li>
<li><code>YESTERDAY</code> - Was the task due yesterday? 2.4.0</li>
<li><code>TOMORROW</code> - Is the task due tomorrow? 2.4.0</li>
<li><code>TAGGED</code> - Does the task have any tags?</li>
<li><code>PENDING</code> - Is the task in the pending state? 2.4.0</li>
<li><code>COMPLETED</code> - Is the task in the completed state? 2.4.0</li>
<li><code>DELETED</code> - Is the task in the deleted state? 2.4.0</li>
<li><code>UDA</code> - Does the task contain any UDA values? 2.5.0</li>
<li><code>ORPHAN</code> - Does the task contain any orphaned UDA values? 2.5.0</li>
<li><code>PRIORITY</code> - Does the task have a priority? 2.5.0</li>
<li><code>PROJECT</code> - Does the task have a project? 2.5.0</li>
<li><code>LATEST</code> - Is the task the most recently added task? 2.5.0</li>
</ul>
<h3 id="filters-usage">
  <a class="anchor inpage" href="#filters-usage">###</a>filters usage</h3>
<h4 id="complex-filters">
  <a class="anchor inpage" href="#complex-filters">####</a>Complex Filters</h4>
<p>Some Taskwarrior filters are simple in concept, but the syntax is not that straightforward. For example, to determine whether a task has a due date that falls on the current day, you need to use this filter:</p>
<details open>
    <summary>shell</summary><pre
        class="chroma codeblock"
      ><code class="language-shell" data-lang="shell"
          ><span style="display:flex;"><span>task due.after:yesterday and due.before:tomorrow list</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>This filters tasks with a due date during the narrow time window of ’today’. Note that it is not sufficient to just specify the date, because due dates all have associated times (defaulting to 0:00:00), and if you want to match the date, you need to consider the time. So for example, this command <em>does not</em> list tasks due today:</p>
<details open>
    <summary>shell</summary><pre
        class="chroma codeblock"
      ><code class="language-shell" data-lang="shell"
          ><span style="display:flex;"><span>task due:today list</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>Instead, this filter matches tasks with a due date of today, and a time of 0:00. In order to see all tasks due today, you need to provide proper range bracketing.</p>
<h4 id="simplification">
  <a class="anchor inpage" href="#simplification">####</a>Simplification</h4>
<p>Here is where virtual tags can help, by providing a simple tag interface to more complex state conditions of the task. There is a virtual tag, named <code>TODAY</code> that can be used in filters, and it means that instead of this filter:</p>
<details open>
    <summary>sh</summary><pre
        class="chroma codeblock"
      ><code class="language-sh" data-lang="sh"
          ><span style="display:flex;"><span>task due.after:yesterday and due.before:tomorrow list</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>We can now use this:</p>
<details open>
    <summary>shell</summary><pre
        class="chroma codeblock"
      ><code class="language-shell" data-lang="shell"
          ><span style="display:flex;"><span>task +TODAY list</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>Which is a much simpler way of filtering tasks due today. Because this is a tag interface, we can also invert it:</p>
<details open>
    <summary>shell</summary><pre
        class="chroma codeblock"
      ><code class="language-shell" data-lang="shell"
          ><span style="display:flex;"><span>task -TODAY list</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>This shows only tasks that are not due today.</p>
<p>Virtual tags are built in to Taskwarrior. They are evaluated at run time, which means they do not require direct metadata, and therefore do not occupy space in the database, but are determined according to the state of the task in the same way that the complex filter example above is determined.</p>
<p>Thus virtual tags combine the simplicity of the tag interface with more complex defined conditions, for convenience.</p>
<h2 id="using-dates-effectively">
  <a class="anchor inpage" href="#using-dates-effectively">##</a>Using Dates Effectively</h2>
<p>A task does not require a due date, and can simply be a statement of need:</p>
<details open>
    <summary>shell</summary><pre
        class="chroma codeblock"
      ><code class="language-shell" data-lang="shell"
          ><span style="display:flex;"><span>$ task add Send Alice a birthday card</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>However, this is exactly the kind of task can benefit from having a due date, and perhaps several other dates also.</p>
<p>There are several dates that can decorate a task, each with its own meaning and effects. You can choose to use some, all or none of these, but like all Taskwarrior features, they are there in case your needs require it, but you do not pay a performance or friction penalty by not using them.</p>
<h3 id="the-due-date">
  <a class="anchor inpage" href="#the-due-date">###</a>The due Date</h3>
<p>Use a <code>due</code> date to specify the exact date by which a task must be completed. This corresponds to the last possible moment when the task can be considered on-time. Using our example, we can set the <code>due</code> date to be Alice’s birthday (line breaks added for clarity):</p>
<details open>
    <summary>shell</summary><pre
        class="chroma codeblock"
      ><code class="language-shell" data-lang="shell"
          ><span style="display:flex;"><span>$ task add Send Alice a birthday card <span style="color:#ae81ff">\
</span></span></span><span style="display:flex;"><span><span style="color:#ae81ff"></span>           due:2016-11-08</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>Now your task has an associated <code>due</code> date, to help you determine when you need to work on it. But what effect does this have on Taskwarrior? How can it be used to best advantage?</p>
<p>We call the <code>due</code> date of a task ‘metadata’. As such, it is just a piece of data associated with the task, and therefore it can become part of a filter:</p>
<details open>
    <summary>shell</summary><pre
        class="chroma codeblock"
      ><code class="language-shell" data-lang="shell"
          ><span style="display:flex;"><span>$ task due:today list
</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>This is one way to find out if any of your tasks are due today. You could also use:</p>
<details open>
    <summary>shell</summary><pre
        class="chroma codeblock"
      ><code class="language-shell" data-lang="shell"
          ><span style="display:flex;"><span>$ task +TODAY list
</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>That is an example of a virtual tag, <code>TODAY</code>, which is not a real tag, but is something you can query, and is equivalent to the previous example. Additionally, you can use <code>DUE</code> which filters tasks that have a due date today or within the next 7 days, or <code>WEEK</code> for all tasks due within the current calendar week, or <code>YESTERDAY</code>, <code>TOMORROW</code>, <code>MONTH</code> and <code>YEAR</code>.</p>
<p>Note that number of days in which a task is considered <code>DUE</code> can be configured using the <code>rc.due</code> setting.</p>
<p>You can find tasks that have any due date at all:</p>
<details open>
    <summary>shell</summary><pre
        class="chroma codeblock"
      ><code class="language-shell" data-lang="shell"
          ><span style="display:flex;"><span>$ task due.any: list
</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>Or no due date:</p>
<details open>
    <summary>shell</summary><pre
        class="chroma codeblock"
      ><code class="language-shell" data-lang="shell"
          ><span style="display:flex;"><span>$ task due.none: list
</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>There is also an <code>overdue</code> report that makes use of the <code>OVERDUE</code> virtual tag, to show you what is already late. If you run the <code>calendar</code> report, your due date will be highlighted on it.</p>
<p>What we see here is that Taskwarrior leverages the metadata to drive various features. Several reports will sort by <code>due</code> date, and as we see above, a task that has a due date now belongs on your schedule.</p>
<h3 id="the-scheduled-date">
  <a class="anchor inpage" href="#the-scheduled-date">###</a>The scheduled Date</h3>
<p>A <code>scheduled</code> date is different from a <code>due</code> date, and represents the earliest opportunity to work on a task. Let’s continue with the same example above. You need to send a birthday card to Alice, but her birthday isn’t until November, so it’s not the kind of task that can be done in advance. Ideally this would be done a few days ahead of the <code>due</code> date:</p>
<details open>
    <summary>shell</summary><pre
        class="chroma codeblock"
      ><code class="language-shell" data-lang="shell"
          ><span style="display:flex;"><span>$ task add Send Alice a birthday card <span style="color:#ae81ff">\
</span></span></span><span style="display:flex;"><span><span style="color:#ae81ff"></span>           due:2016-11-08 <span style="color:#ae81ff">\
</span></span></span><span style="display:flex;"><span><span style="color:#ae81ff"></span>           scheduled:2016-11-04</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>This means that you need to send Alice a birthday card, no later than 2016-11-08, and no earlier than 2016-11-04.</p>
<p>If a task has a <code>scheduled</code> date, then once that date passes, the task is considered ready, and there is a <code>ready</code> report and a <code>READY</code> virtual tag for this:</p>
<details open>
    <summary>shell</summary><pre
        class="chroma codeblock"
      ><code class="language-shell" data-lang="shell"
          ><span style="display:flex;"><span>$ task ready
</span></span><span style="display:flex;"><span>...
</span></span><span style="display:flex;"><span>$ task +READY list
</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>Tasks that have no <code>scheduled</code> date are considered always ready. Again, metadata drives the sophistication of your task list.</p>
<h3 id="the-wait-date">
  <a class="anchor inpage" href="#the-wait-date">###</a>The wait Date</h3>
<p>Many people do not like to look at long task lists, finding them daunting, or just distracting. You can add a <code>wait</code> date to a task, which has the effect of hiding the task from you until that date. In our example, Alice’s birthday isn’t close yet, so we applied a <code>scheduled</code> date to indicate that we should not begin the task yet, as it is not ready. Now let’s add a <code>wait</code> date to the task:</p>
<details open>
    <summary>shell</summary><pre
        class="chroma codeblock"
      ><code class="language-shell" data-lang="shell"
          ><span style="display:flex;"><span>$ task add Send Alice a birthday card <span style="color:#ae81ff">\
</span></span></span><span style="display:flex;"><span><span style="color:#ae81ff"></span>           due:2016-11-08 <span style="color:#ae81ff">\
</span></span></span><span style="display:flex;"><span><span style="color:#ae81ff"></span>           scheduled:2016-11-04 <span style="color:#ae81ff">\
</span></span></span><span style="display:flex;"><span><span style="color:#ae81ff"></span>           wait:november</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>Here the task is given a <code>wait</code> date of 2016-11-01, via the useful shortcut ’november’, which means the task will not appear on lists until November. At that time, it will reappear, but it will still not be ready until 2016-11-04.</p>
<p>You can view all the hidden waiting tasks using the <code>waiting</code> report:</p>
<details open>
    <summary>shell</summary><pre
        class="chroma codeblock"
      ><code class="language-shell" data-lang="shell"
          ><span style="display:flex;"><span>$ task waiting
</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>There is a <code>WAITING</code> virtual tag to select these tasks, but note that you have to use the <code>all</code> report with it, otherwise you get conflicts with the other reports that specify a ‘pending’ status, because a waiting task is not pending.</p>
<h3 id="the-until-date">
  <a class="anchor inpage" href="#the-until-date">###</a>The until Date</h3>
<p>Now suppose I miss Alice’s birthday completely. Shame on me. The task would be overdue, but this is the kind of task where I don’t want to complete it late, I’d rather just forget it, and wish Alice a belated happy birthday in person. I could simply delete or complete the task, but there is another option, which is to add an <code>until</code> date:</p>
<details open>
    <summary>perl</summary><pre
        class="chroma codeblock"
      ><code class="language-perl" data-lang="perl"
          ><span style="display:flex;"><span>$ task add Send Alice a birthday card <span style="color:#f92672">\</span>
</span></span><span style="display:flex;"><span>           due:2016<span style="color:#f92672">-</span><span style="color:#ae81ff">11</span><span style="color:#f92672">-</span><span style="color:#ae81ff">08</span> <span style="color:#f92672">\</span>
</span></span><span style="display:flex;"><span>           scheduled:2016<span style="color:#f92672">-</span><span style="color:#ae81ff">11</span><span style="color:#f92672">-</span><span style="color:#ae81ff">04</span> <span style="color:#f92672">\</span>
</span></span><span style="display:flex;"><span>           wait:november <span style="color:#f92672">\</span>
</span></span><span style="display:flex;"><span>           <span style="color:#66d9ef">until</span>:<span style="color:#ae81ff">2016</span><span style="color:#f92672">-</span><span style="color:#ae81ff">11</span><span style="color:#f92672">-</span><span style="color:#ae81ff">10</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>This means that on 2016-11-10, the task self-destructs, and is automatically deleted. This might be the right thing to do for a birthday card task, but is not suitable for a “Pay the rent” task. Beware!</p>
<p>There is a DOM-based shortcut you can use, to make the command above a little more formulaic:</p>
<details open>
    <summary>perl</summary><pre
        class="chroma codeblock"
      ><code class="language-perl" data-lang="perl"
          ><span style="display:flex;"><span>$ task add Send Alice a birthday card <span style="color:#f92672">\</span>
</span></span><span style="display:flex;"><span>           due:2016<span style="color:#f92672">-</span><span style="color:#ae81ff">11</span><span style="color:#f92672">-</span><span style="color:#ae81ff">08</span> <span style="color:#f92672">\</span>
</span></span><span style="display:flex;"><span>           scheduled:due<span style="color:#f92672">-</span><span style="color:#ae81ff">4</span>d <span style="color:#f92672">\</span>
</span></span><span style="display:flex;"><span>           wait:due<span style="color:#f92672">-</span><span style="color:#ae81ff">7</span>d <span style="color:#f92672">\</span>
</span></span><span style="display:flex;"><span>           <span style="color:#66d9ef">until</span>:due<span style="color:#f92672">+</span><span style="color:#ae81ff">2</span>d</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>This is evaluated only at task creation time, so if you change the due date, you also need to change the other dates. Note there is an <code>UNTIL</code> virtual tag to show you all tasks that are set to auto-expire.</p>
<h3 id="other-dates">
  <a class="anchor inpage" href="#other-dates">###</a>Other Dates</h3>
<p>There are other dates associated with a task, but these are more for internal use, and are less useful for you.</p>
<p>Each task has an <code>entry</code> date which records when it was created. Each completed or deleted task has an <code>end</code> date, which records when it was completed or deleted. An active, or started task has a <code>start</code> date, but only while it is in the active state. Finally, every task has a <code>modification</code> date, which records when it was last modified. This is used as a hint when tasks are being synced.</p>
<p>In addition, you may find you have a use case for a different kind of date for your task lists. For example, you may adhere to an agile development process, and a task may be assigned to a sprint, and that sprint may be identified by its end date. You can add arbitrary dates like this to Taskwarrior by defining a 
 (UDA) and then storing that metadata with your tasks. In this case, Taskwarrior will do nothing with your UDA but store it, and let you use it in reports and filters.</p>
<h3 id="urgency">
  <a class="anchor inpage" href="#urgency">###</a>Urgency</h3>
<p>The presence and values of date metadata in your tasks affects the urgency calculations. For example, if a task is blocked by a dependency, the urgency is reduced. Similarly, tasks that are ready have an elevated urgency.</p>
<h2 id="dom---document-object-model">
  <a class="anchor inpage" href="#dom---document-object-model">##</a>DOM - Document Object Model</h2>
<p>Taskwarrior has a Document Object Model, or DOM, which defines a way to reference all the data managed by taskwarrior. You may be familiar with the DOM implemented by web browsers that let you access details on a page programmatically. For example:</p>
<details open>
    <summary>javascript</summary><pre
        class="chroma codeblock"
      ><code class="language-javascript" data-lang="javascript"
          ><span style="display:flex;"><span>document.<span style="color:#a6e22e">getElementById</span>(<span style="color:#e6db74">&#34;myAnchor&#34;</span>).<span style="color:#a6e22e">href</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>Taskwarrior allows the same kind of data access in a similar form, for example:</p>
<details open>
    <summary>sh</summary><pre
        class="chroma codeblock"
      ><code class="language-sh" data-lang="sh"
          ><span style="display:flex;"><span>task _get 1.description</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>This references the description text of task 1. There is a 
 that queries data using a DOM reference. Let’s see it in action, by first creating a detailed task.</p>
<details open>
    <summary>shell</summary><pre
        class="chroma codeblock"
      ><code class="language-shell" data-lang="shell"
          ><span style="display:flex;"><span>task add Buy milk due:tomorrow +store project:Home pri:H
</span></span><span style="display:flex;"><span>task <span style="color:#ae81ff">1</span> info
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span>Name          Value
</span></span><span style="display:flex;"><span>------------- ------------------------------------------
</span></span><span style="display:flex;"><span>ID            <span style="color:#ae81ff">1</span>
</span></span><span style="display:flex;"><span>Description   Buy milk
</span></span><span style="display:flex;"><span>Status        Pending
</span></span><span style="display:flex;"><span>Project       Home
</span></span><span style="display:flex;"><span>Priority      H
</span></span><span style="display:flex;"><span>Entered       2014-09-28 21:53:59 <span style="color:#f92672">(</span><span style="color:#ae81ff">4</span> seconds<span style="color:#f92672">)</span>
</span></span><span style="display:flex;"><span>Due           2014-09-29 00:00:00
</span></span><span style="display:flex;"><span>Last modified 2014-09-28 21:53:59 <span style="color:#f92672">(</span><span style="color:#ae81ff">4</span> seconds<span style="color:#f92672">)</span>
</span></span><span style="display:flex;"><span>Tags          store
</span></span><span style="display:flex;"><span>UUID          c0ab2bf6-b4f5-45c2-8420-18ab4f1ba7e7
</span></span><span style="display:flex;"><span>Urgency       16.56
</span></span><span style="display:flex;"><span>                           project     <span style="color:#ae81ff">1</span>  *    1 <span style="color:#f92672">=</span>     <span style="color:#ae81ff">1</span>
</span></span><span style="display:flex;"><span>                          priority     <span style="color:#ae81ff">1</span>  *    6 <span style="color:#f92672">=</span>     <span style="color:#ae81ff">6</span>
</span></span><span style="display:flex;"><span>                              tags   0.8  *    1 <span style="color:#f92672">=</span>   0.8
</span></span><span style="display:flex;"><span>                               due  0.73  *   12 <span style="color:#f92672">=</span>  8.76</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>All the attributes of that task are available via DOM references. Here are some examples:</p>
<details open>
    <summary>shell</summary><pre
        class="chroma codeblock"
      ><code class="language-shell" data-lang="shell"
          ><span style="display:flex;"><span>$ task _get 1.description
</span></span><span style="display:flex;"><span>Buy milk
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span>$ task _get 1.uuid
</span></span><span style="display:flex;"><span>c0ab2bf6-b4f5-45c2-8420-18ab4f1ba7e7
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span>$ task _get c0ab2bf6-b4f5-45c2-8420-18ab4f1ba7e7.id
</span></span><span style="display:flex;"><span>    <span style="color:#ae81ff">1</span>
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span>$ task _get 1.due.year
</span></span><span style="display:flex;"><span><span style="color:#ae81ff">2014</span>
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span>$ task _get 1.due.julian
</span></span><span style="display:flex;"><span><span style="color:#ae81ff">272</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="supported-references">
  <a class="anchor inpage" href="#supported-references">###</a>Supported References</h3>
<p>system.version: The version of taskwarrior, for example:</p>
<details open>
    <summary>shell</summary><pre
        class="chroma codeblock"
      ><code class="language-shell" data-lang="shell"
          ><span style="display:flex;"><span>$ task _get system.version
</span></span><span style="display:flex;"><span>2.4.0</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>system.os: The operating system, for example:</p>
<details open>
    <summary>shell</summary><pre
        class="chroma codeblock"
      ><code class="language-shell" data-lang="shell"
          ><span style="display:flex;"><span>$ task _get system.os
</span></span><span style="display:flex;"><span>FreeBSD</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>rc.<name>: Any configuration value default, with any overrides from the <code>.taskrc</code> applied, then with any command line overrides applied last. For example:</p>
<details open>
    <summary>shell</summary><pre
        class="chroma codeblock"
      ><code class="language-shell" data-lang="shell"
          ><span style="display:flex;"><span>$ task _get rc.data.location
</span></span><span style="display:flex;"><span>~/.task</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><attribute>: Any task attribute. Note that no task ID or UUID is specified, so this variant is only useful on the command line like this:</p>
<details open>
    <summary>shell</summary><pre
        class="chroma codeblock"
      ><code class="language-shell" data-lang="shell"
          ><span style="display:flex;"><span>$ task add Pay rent due:eom wait:<span style="color:#e6db74">&#39;due - 3days&#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>Note that ‘due’ is a DOM reference from earlier on the command line.</p>
<p><id>.<attribute>: Any attribute of the specified task ID. For example:</p>
<details open>
    <summary>shell</summary><pre
        class="chroma codeblock"
      ><code class="language-shell" data-lang="shell"
          ><span style="display:flex;"><span>$ task add Fix the leak depends:3 scheduled:3.due</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>This makes the new task dependent on task 3, and scheduled on the due date of task 3. Note that ‘3.due’ is a DOM reference of a specific task.</p>
<p><uuid>.<attribute>: Any attribute of the specified task UUID, as above.</p>
<p>Any attribute that is of type <code>date</code> can be directly accessed as a date, or it can be accessed by the elements of that date. For example:</p>
<ul>
<li><code>&lt;date&gt;.year</code> - 2.4.0 The year, for example:
<details open>
    <summary>shell</summary><pre
        class="chroma codeblock"
      ><code class="language-shell" data-lang="shell"
          ><span style="display:flex;"><span>$ task _get 1.due.year
</span></span><span style="display:flex;"><span><span style="color:#ae81ff">2014</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>
<li><code>&lt;date&gt;.month</code> - 2.4.0 The month, for example:
<details open>
    <summary>shell</summary><pre
        class="chroma codeblock"
      ><code class="language-shell" data-lang="shell"
          ><span style="display:flex;"><span>$ task _get 1.due.month
</span></span><span style="display:flex;"><span><span style="color:#ae81ff">9</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>
<li><code>&lt;date&gt;.day</code> - 2.4.0 The day of the month, for example:
<details open>
    <summary>shell</summary><pre
        class="chroma codeblock"
      ><code class="language-shell" data-lang="shell"
          ><span style="display:flex;"><span>$ task _get 1.due.day
</span></span><span style="display:flex;"><span><span style="color:#ae81ff">29</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>
<li><code>&lt;date&gt;.week</code> - 2.4.0 The week number of the date, for example:
<details open>
    <summary>shell</summary><pre
        class="chroma codeblock"
      ><code class="language-shell" data-lang="shell"
          ><span style="display:flex;"><span>$ task _get 1.due.week
</span></span><span style="display:flex;"><span><span style="color:#ae81ff">40</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>
<li><code>&lt;date&gt;.weekday</code> - 2.4.0 The numbered weekday of the date, where 0 is Sunday and 6 is Saturday. For example:
<details open>
    <summary>shell</summary><pre
        class="chroma codeblock"
      ><code class="language-shell" data-lang="shell"
          ><span style="display:flex;"><span>$ task _get 1.due.weekday
</span></span><span style="display:flex;"><span><span style="color:#ae81ff">1</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>
<li><code>&lt;date&gt;.julian</code> - 2.4.0 The Julian day of the date, which is the day number of the date in the year. For example, January 1st is 1, February 10th is 41. For example:
<details open>
    <summary>shell</summary><pre
        class="chroma codeblock"
      ><code class="language-shell" data-lang="shell"
          ><span style="display:flex;"><span>$ task _get 1.due.julian
</span></span><span style="display:flex;"><span><span style="color:#ae81ff">272</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>
<li><code>&lt;date&gt;.hour</code> - 2.4.0 The hour of the day, for example:
<details open>
    <summary>shell</summary><pre
        class="chroma codeblock"
      ><code class="language-shell" data-lang="shell"
          ><span style="display:flex;"><span>$ task _get 1.due.hour
</span></span><span style="display:flex;"><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></li>
<li><code>&lt;date&gt;.minute</code> - 2.4.0 The minute of the hour, for example:
<details open>
    <summary>shell</summary><pre
        class="chroma codeblock"
      ><code class="language-shell" data-lang="shell"
          ><span style="display:flex;"><span>$ task _get 1.due.minute
</span></span><span style="display:flex;"><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></li>
<li><code>&lt;date&gt;.second</code> - 2.4.0 The seconds of the minute, for example:
<details open>
    <summary>shell</summary><pre
        class="chroma codeblock"
      ><code class="language-shell" data-lang="shell"
          ><span style="display:flex;"><span>$ task _get 1.due.second
</span></span><span style="display:flex;"><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></li>
</ul>
<p>Tags can be accessed as a single item as an <code>&lt;attribute&gt;</code>, of the individual tags can be accessed:</p>
<ul>
<li><code>tags.&lt;literal&gt;</code> - 2.4.0 Direct access, per-tag, for example:
<details open>
    <summary>shell</summary><pre
        class="chroma codeblock"
      ><code class="language-shell" data-lang="shell"
          ><span style="display:flex;"><span>$ task _get 1.tag.home
</span></span><span style="display:flex;"><span>home</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>If the tag is present, it is shown, otherwise the result is blank, and Taskwarrior exits with a non-zero status.
<details open>
    <summary>shell</summary><pre
        class="chroma codeblock"
      ><code class="language-shell" data-lang="shell"
          ><span style="display:flex;"><span>$ task _get 1.tag.DUE
</span></span><span style="display:flex;"><span>DUE
</span></span><span style="display:flex;"><span>$ task _get 1.tag.OVERDUE</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>Workѕ for virtual tags too, in the same manner.</li>
</ul>
<p>Annotations are compound data structures, with two elements, which are <code>description</code> and <code>entry</code>. Annotations are accessed by an ordinal.</p>
<ul>
<li><code>annotations.&lt;N&gt;.description</code> - 2.4.0 The description of the Nth annotation, for example:
<details open>
    <summary>shell</summary><pre
        class="chroma codeblock"
      ><code class="language-shell" data-lang="shell"
          ><span style="display:flex;"><span>$ task _get 1.annotations.0.description</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>
<li><code>annotations.&lt;N&gt;.entry</code> - 2.4.0 The creation timestamp of the Nth annotation, for example:
<details open>
    <summary>shell</summary><pre
        class="chroma codeblock"
      ><code class="language-shell" data-lang="shell"
          ><span style="display:flex;"><span>$ task _get 1.annotations.0.entry</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>Note that because <code>entry</code> is of type <code>date</code>, the individual elements can be addressed, as above, for example:
<details open>
    <summary>shell</summary><pre
        class="chroma codeblock"
      ><code class="language-shell" data-lang="shell"
          ><span style="display:flex;"><span>$ task _get 1.annotations.0.entry.year
</span></span><span style="display:flex;"><span><span style="color:#ae81ff">2014</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>UDA values can be accessed in the same manner.</p>
]]></content:encoded></item><item><title>Filesystem Hierarchy Standard</title><link>https://hiraethecho.github.io/docs/linux/fhs/</link><pubDate>Mon, 09 Jun 2025 00:00:00 +0000</pubDate><author>wyz2016zxc@outlook.com(Hiraeth)</author><guid>https://hiraethecho.github.io/docs/linux/fhs/</guid><description>linux文件结构标准</description><content:encoded><![CDATA[<h1 id="filesystem-hierarchy-standard">
  <a class="anchor inpage" href="#filesystem-hierarchy-standard">#</a>Filesystem Hierarchy Standard</h1>
<p>
</p>
<p>This standard consists of a set of requirements and guidelines for file and directory placement under UNIX-like operating systems. The guidelines are intended to support interoperability of applications, system administration tools, development tools, and scripts as well as greater uniformity of documentation for these systems.</p>
<h2 id="general-setting">
  <a class="anchor inpage" href="#general-setting">##</a>General setting</h2>
<h3 id="under-">
  <a class="anchor inpage" href="#under-">###</a>under <code>/</code></h3>
<p><code>/bin</code> : Essential user command binaries (for use by all users). <code>/sbin</code> : System binaries. stored in /sbin, /usr/sbin, and /usr/local/sbin.
<code>/lib</code> : Essential shared libraries and kernel modules <code>lib32</code> and <code>lib64</code>: Alternate format essential shared libraries (optional)
<code>/etc</code> : Host-specific system configuration. A &ldquo;configuration file&rdquo; is a local file used to control the operation of a program; it must be static and cannot be an executable binary.</p>
<p><code>/media</code> : Mount point for removable media
<code>/mnt</code> : Mount point for a temporarily mounted filesystem
<code>/opt</code> : Add-on application software packages
<code>/run</code> : Run-time variable data
<code>/srv</code> : Data for services provided by this system
<code>/tmp</code> : Temporary files</p>
<h3 id="usr">
  <a class="anchor inpage" href="#usr">###</a><code>/usr</code></h3>
<details open>
    <summary>TEXT</summary><pre
        class="codeblock"
      ><code class="language-" data-lang="">/
└── usr
    ├── bin
    ├── include
    ├── lib
    ├── sbin
    ├── share
    └── src</code><button onclick="copyCode(this)" class="copybtn">copy</button></pre></details>

  <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</code> is the second major section of the filesystem. /usr is shareable, read-only data. That means that /usr should be shareable between various FHS-compliant hosts and must not be written to. Any information that is host-specific or varies with time is stored elsewhere.<br>
Large software packages must not use a direct subdirectory under the /usr hierarchy. (maybe <code>/opt</code>)</p>
<ul>
<li><code>/usr/share</code> : Architecture-independent data. The /usr/share hierarchy is for all read-only architecture independent data files.<br>
This hierarchy is intended to be shareable among all architecture platforms of a given OS; thus, for example, a site with i386, Alpha, and PPC platforms might maintain a single /usr/share directory that is centrally-mounted. Note, however, that /usr/share is generally not intended to be shared by different OSes or by different releases of the same OS.<br>
Any program or package which contains or requires data that doesn&rsquo;t need to be modified should store that data in /usr/share (or /usr/local/share, if installed locally). It is recommended that a subdirectory be used in /usr/share for this purpose. Applications using a single file may use /usr/share/misc.<br>
Game data stored in /usr/share/games must be purely static data. Any modifiable files, such as score files, game play logs, and so forth, should be placed in /var/games.</li>
<li><code>/usr/lib</code>: Includes object files and libraries. On some systems, it may also include internal binaries that are not intended to be executed directly by users or shell scripts.<br>
Applications may use a single subdirectory under /usr/lib. If an application uses a subdirectory, all architecture-dependent data exclusively used by the application must be placed within that subdirectory.</li>
<li><code>/usr/local</code> : Local hierarchy (empty after main installation) The /usr/local hierarchy is for use by the system administrator when installing software locally. It needs to be safe from being overwritten when the system software is updated. It may be used for programs and data that are shareable amongst a group of hosts, but not found in /usr.</li>
</ul>
<p>And others:</p>
<ul>
<li><code>games</code>: Games and educational binaries (optional)</li>
<li><code>include</code>: Header files included by C programs. This is where all of the system&rsquo;s general-use include files for the C programming language should be placed.</li>
<li><code>libexec</code>: Binaries run by other programs (optional)</li>
<li><code>src</code>: Source code (optional)</li>
</ul>
<h3 id="summary">
  <a class="anchor inpage" href="#summary">###</a>Summary</h3>
<table>
  <thead>
      <tr>
          <th></th>
          <th>shareable</th>
          <th>unshareable</th>
      </tr>
  </thead>
  <tbody>
      <tr>
          <td>static</td>
          <td><code>/usr</code>, <code>/opt</code></td>
          <td><code>/etc</code>, <code>/boot</code></td>
      </tr>
      <tr>
          <td>variable</td>
          <td><code>/var/mail</code>, <code>/var/spool/news</code></td>
          <td><code>/var/run</code>, <code>/var/lock</code></td>
      </tr>
  </tbody>
</table>
<ul>
<li>May under &lsquo;/&rsquo;,<code>/usr</code>,<code>/var</code></li>
</ul>
<details open>
    <summary>TEXT</summary><pre
        class="codeblock"
      ><code class="language-" data-lang="">├── bin # binary
├── lib # library
├── include # C header
├── games   # games
├── opt # opt
├── share   # data that share with other
└── src     # sources</code><button onclick="copyCode(this)" class="copybtn">copy</button></pre></details>

  <script>
    function copyCode(btn) {
      const code = btn.previousElementSibling.textContent.trim();
      navigator.clipboard.writeText(code).then(() => {
        btn.innerText = "copied";
        setTimeout(() => (btn.innerText = "copy"), 2000);
      });
    }
  </script><ul>
<li>only under <code>/</code></li>
</ul>
<details open>
    <summary>TEXT</summary><pre
        class="codeblock"
      ><code class="language-" data-lang="">/
├── boot
├── etc # configraturation
├── dev
├── media
├── mnt
├── proc
├── run
├── srv
├── sys
└── tmp</code><button onclick="copyCode(this)" class="copybtn">copy</button></pre></details>

  <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="on-archlinux">
  <a class="anchor inpage" href="#on-archlinux">##</a>On archlinux,</h2>
<details open>
    <summary>TEXT</summary><pre
        class="codeblock"
      ><code class="language-" data-lang="">/
├── bin ⇒ usr/bin
├── boot
├── dev
├── etc
├── home
├── lib ⇒ usr/lib
├── lib64 ⇒ usr/lib
├── mnt
├── opt
├── proc
├── root
├── run
├── sbin ⇒ usr/bin
├── srv
├── sys
├── tmp
├── usr
└── var</code><button onclick="copyCode(this)" class="copybtn">copy</button></pre></details>

  <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>lib32</code> and <code>lib64</code> for 32-bit and 64-bit. <code>sbin</code> binaries for super user. (On debian, only root can <code>reboot</code>.)</p>
<details open>
    <summary>TEXT</summary><pre
        class="codeblock"
      ><code class="language-" data-lang="">/
└── opt
    ├── waterfox
    ├── wechat-universal
    └── wemeet</code><button onclick="copyCode(this)" class="copybtn">copy</button></pre></details>

  <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="">/
└── usr
    └── share
        ├── alsa
        ├── applications
        ├── awk
        ├── blueman
        ├── mime
        ├── nvim
        ├── wayland
        ├── wayland-sessions
        ├── X11
        └── zsh</code><button onclick="copyCode(this)" class="copybtn">copy</button></pre></details>

  <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="">/
└── usr
    └── local
        ├── bin
        ├── etc
        ├── games
        ├── include
        ├── lib
        ├── man
        ├── sbin
        ├── share
        └── src</code><button onclick="copyCode(this)" class="copybtn">copy</button></pre></details>

  <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="">/
└── var
    ├── cache
    ├── db
    ├── empty
    ├── games
    ├── lib
    ├── local
    ├── lock ⇒ ../run/lock
    ├── log
    ├── mail ⇒ spool/mail
    ├── opt
    ├── run ⇒ ../run
    ├── spool
    └── tmp</code><button onclick="copyCode(this)" class="copybtn">copy</button></pre></details>

  <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="special-directories">
  <a class="anchor inpage" href="#special-directories">###</a>special directories</h3>
<details open>
    <summary>TEXT</summary><pre
        class="codeblock"
      ><code class="language-" data-lang="">/
├── boot
│   ├── efi
│   ├── grub
│   ├── initramfs-linux.img
│   └── vmlinuz-linux
├── dev
│   ├── disk
│   ├── null
│   ├── random
│   └── zero
├── mnt
├── proc
│   ├── 1
│   ├── uptime
│   └── zoneinfo
├── run
│   ├── dhcpcd
│   ├── initramfs
│   ├── media # This is different
│   ├── libvirt
│   ├── systemd
│   └── xtables.lock
├── srv
│   ├── ftp
│   └── http
├── sys
│   ├── kernel
│   └── power
└── tmp</code><button onclick="copyCode(this)" class="copybtn">copy</button></pre></details>

  <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="homes">
  <a class="anchor inpage" href="#homes">##</a>homes</h2>
<details open>
    <summary>TEXT</summary><pre
        class="codeblock"
      ><code class="language-" data-lang="">/
├── home
│   └── user
│       ├── Desktop
│       ├── Documents
│       ├── Downloads
│       ├── Music
│       ├── Pictures
│       ├── Public
│       ├── Templates
│       └── Videos
└── root
    ├── Desktop
    ├── Documents
    ├── Downloads
    ├── Music
    ├── Pictures
    ├── Public
    ├── Templates
    └── Videos</code><button onclick="copyCode(this)" class="copybtn">copy</button></pre></details>

  <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>Archlinux 上的包管理</title><link>https://hiraethecho.github.io/docs/linux/pacman/</link><pubDate>Sun, 08 Jun 2025 00:00:00 +0000</pubDate><author>wyz2016zxc@outlook.com(Hiraeth)</author><guid>https://hiraethecho.github.io/docs/linux/pacman/</guid><description>pacman的一些使用技巧</description><content:encoded><![CDATA[<h1 id="package-manage-on-arch">
  <a class="anchor inpage" href="#package-manage-on-arch">#</a>Package manage on Arch</h1>
<h2 id="pacman">
  <a class="anchor inpage" href="#pacman">##</a>pacman</h2>
<details open>
    <summary>sh</summary><pre
        class="chroma codeblock"
      ><code class="language-sh" data-lang="sh"
          ><span style="display:flex;"><span>pacman -Qqe | fzf --preview <span style="color:#e6db74">&#39;pacman -Qiil {}&#39;</span> --layout<span style="color:#f92672">=</span>reverse --bind <span style="color:#e6db74">&#39;enter:execute(pacman -Qiil {} | less)&#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>pacman -Slq | fzf --preview <span style="color:#e6db74">&#39;pacman -Si {}&#39;</span> --layout<span style="color:#f92672">=</span>reverse</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>pacman -D --asdeps <span style="color:#66d9ef">$(</span>pacman -Qqe<span style="color:#66d9ef">)</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>pacman -D --asexplicit base linux linux-firmware</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>cat explicit | sudo pacman -D --asexplicit -</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>pacman -Qii | awk <span style="color:#e6db74">&#39;/^MODIFIED/ {print $2}&#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>pacman -Qi | awk <span style="color:#e6db74">&#39;/^Name/{name=$3} /^Install Date/{print $4,$5,$6,name}&#39;</span> | sort</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="paru">
  <a class="anchor inpage" href="#paru">##</a>paru</h2>
<h2 id="tools">
  <a class="anchor inpage" href="#tools">##</a>tools</h2>
<h3 id="pacfiles">
  <a class="anchor inpage" href="#pacfiles">###</a>pacfiles</h3>
<h3 id="expac">
  <a class="anchor inpage" href="#expac">###</a>expac</h3>
<p>A data extraction tool for alpm databases, offering printf-like flexibility for pacman-based utilities.

</p>
<details open>
    <summary>man</summary><pre
        class="chroma codeblock"
      ><code class="language-man" data-lang="man"
          ><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span>SYNOPSIS
</span></span><span style="display:flex;"><span>       Usage: expac [options] &lt;format&gt; targets...
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span>OPTIONS
</span></span><span style="display:flex;"><span>       -Q, --query
</span></span><span style="display:flex;"><span>           Search  the local database for provided targets. This is the default
</span></span><span style="display:flex;"><span>           behavior.
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span>       -S, --sync
</span></span><span style="display:flex;"><span>           Search the sync databases for provided targets.
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span>       -s, --search
</span></span><span style="display:flex;"><span>           Search for packages matching the strings specified by targets.  This
</span></span><span style="display:flex;"><span>           is a boolean AND query and regex is allowed.
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span>       -g, --group
</span></span><span style="display:flex;"><span>           Return packages matching the specified targets as package groups.
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span>       --config &lt;file&gt;
</span></span><span style="display:flex;"><span>           Read from file for alpm initialization instead of /etc/pacman.conf.
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span>       -H, --humansize &lt;size&gt;
</span></span><span style="display:flex;"><span>           Format  package  sizes  in SI units according to size. Valid options
</span></span><span style="display:flex;"><span>           are:
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span>             B, K, M, G, T, P, E, Z, Y
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span>       -1, --readone
</span></span><span style="display:flex;"><span>           Stop searching after the first result. This only has an effect on -S
</span></span><span style="display:flex;"><span>           operations without -s.
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span>       -d, --delim &lt;string&gt;
</span></span><span style="display:flex;"><span>           Separate each package with the specified string. The  default  value
</span></span><span style="display:flex;"><span>           is a newline character.
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span>       -l, --listdelim &lt;string&gt;
</span></span><span style="display:flex;"><span>           Separate  each  list  item  with the specified string. Lists are any
</span></span><span style="display:flex;"><span>           interpreted sequence specified with a capital  letter.  The  default
</span></span><span style="display:flex;"><span>           value is two spaces.
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span>       -p, --file
</span></span><span style="display:flex;"><span>           Interpret targets as paths to local files.
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span>       -t, --timefmt &lt;format&gt;
</span></span><span style="display:flex;"><span>           Output time described by the specified format. This string is passed
</span></span><span style="display:flex;"><span>           directly to strftime(3). The default format is %c.
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span>       -v, --verbose
</span></span><span style="display:flex;"><span>           Output  more.  ‘Package  not  found&#39; errors will be shown, and empty
</span></span><span style="display:flex;"><span>           field values will display as &#39;None&#39;.
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span>       -V, --version
</span></span><span style="display:flex;"><span>           Display version information and quit.
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span>       -h, --help
</span></span><span style="display:flex;"><span>           Display the help message and quit.
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span>FORMATTING
</span></span><span style="display:flex;"><span>       The format argument allows the following interpreted sequences:
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span>         %a    architecture
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span>         %B    backup files
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span>         %b    build date
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span>         %C    conflicts with (no version strings)
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span>         %D    depends on
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span>         %d    description
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span>         %E    depends on (no version strings)
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span>         %e    package base
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span>         %f    filename (only with -S)
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span>         %F    files (only with -Q)
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span>         %g    base64 encoded PGP signature (only with -S)
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span>         %G    groups
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span>         %H    conflicts with
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span>         %h    sha256sum
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span>         %i    has install scriptlet (only with -Q)
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span>         %k    download size (only with -S)
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span>         %l    install date (only with -Q)
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span>         %L    licenses
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span>         %m    install size
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span>         %M    modified backup files (only with -Q)
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span>         %n    package name
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span>         %N    required by
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span>         %O    optional deps
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span>         %o    optional deps (no descriptions)
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span>         %p    packager name
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span>         %P    provides
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span>         %R    replaces (no version strings)
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span>         %r    repo
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span>         %s    md5sum
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span>         %S    provides (no version strings)
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span>         %T    replaces
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span>         %u    project URL
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span>         %V    package validation method
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span>         %v    version
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span>         %w    install reason (only with -Q)
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span>         %!    result number (auto-incremented counter, starts at 0)
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span>         %%    literal %
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span>       Note that for any lowercase tokens aside from %m  and  %k,  full  printf
</span></span><span style="display:flex;"><span>       support  is  allowed, e.g. %-20n. This does not apply to any list based,
</span></span><span style="display:flex;"><span>       date, or numerical output.
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span>       Standard backslash escape sequences are supported, as per printf(1).
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span>EXAMPLES
</span></span><span style="display:flex;"><span>       Emulate pacman&#39;s search function:
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span>         $ expac -Ss &#39;%r/%n %v<span style="color:#ae81ff">\n</span>    %d&#39; &lt;search terms&gt;
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span>       List the oldest 10 installed packages (by build date):
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span>         $ expac --timefmt=%s &#39;%b<span style="color:#ae81ff">\t</span>%n&#39; | sort -n | head -10</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>tldr</summary><pre
        class="codeblock"
      ><code class="language-tldr" data-lang="tldr">  List the dependencies of a package:

      expac [-S|--sync] &#39;%D&#39; package

  List the optional dependencies of a package:

      expac [-S|--sync] &#34;%o&#34; package

  List the download size of packages in MiB:

      expac [-S|--sync] [-H|--humansize] M &#39;%k\t%n&#39; package1 package2 ...

  List packages marked for upgrade with their download size:

      expac [-S|--sync] [-H|--humansize] M &#39;%k\t%n&#39; $(pacman -Qqu) | sort [-sh|--sort --human-numeric-sort]

  List explicitly-installed packages with their optional dependencies:

      expac [-d|--delim] &#39;\n\n&#39; [-l|listdelim] &#39;\n\t&#39; [-Q|--query] &#39;%n\n\t%O&#39; $(pacman -Qeq)</code><button onclick="copyCode(this)" class="copybtn">copy</button></pre></details>

  <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="">expac -Q &#34;%n %w %M&#34; | grep explicit | awk &#39;{print $3}&#39; | grep -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><h3 id="pacman-contrib">
  <a class="anchor inpage" href="#pacman-contrib">###</a>pacman-contrib</h3>
<h2 id="pkgbuild">
  <a class="anchor inpage" href="#pkgbuild">##</a>PKGBUILD</h2>
<h3 id="tips">
  <a class="anchor inpage" href="#tips">###</a>tips</h3>
<p>pacman 进行升级时会将修改后的软件包升级到仓库中的最新版本，可以通过下面方式避免这个行为：</p>
<p>在 PKGBUILD 中将软件包加入 modified 组：</p>
<details open>
    <summary>PKGBUILD</summary><pre
        class="chroma codeblock"
      ><code class="language-PKGBUILD" data-lang="PKGBUILD"
          ><span style="display:flex;"><span>groups<span style="color:#f92672">=(</span><span style="color:#e6db74">&#39;modified&#39;</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><p>然后将此组加入 <code>/etc/pacman.conf</code> 的 <code>IgnoreGroup</code>：</p>
<details open>
    <summary>/etc/pacman.conf</summary><pre
        class="chroma codeblock"
      ><code class="language-/etc/pacman.conf" data-lang="/etc/pacman.conf"
          ><span style="display:flex;"><span><span style="color:#a6e22e">IgnoreGroup</span> <span style="color:#f92672">=</span> modified</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>当系统升级发现官方仓库中有新版本时，pacman 会显示软件包因为在 IgnoreGroup 中而被忽略的提示，这时需要从 ABS 编译更新的软件包以防止部分升级。</p>
]]></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>Display Manager</title><link>https://hiraethecho.github.io/docs/linux/sddm/</link><pubDate>Thu, 05 Jun 2025 00:00:00 +0000</pubDate><author>wyz2016zxc@outlook.com(Hiraeth)</author><guid>https://hiraethecho.github.io/docs/linux/sddm/</guid><description>在Linux系统中配置显示管理器（Display Manager）的指南，包括无显示管理器和sddm的自动登录设置。</description><content:encoded><![CDATA[<h1 id="display-manager">
  <a class="anchor inpage" href="#display-manager">#</a>Display Manager</h1>
<h2 id="no-dm">
  <a class="anchor inpage" href="#no-dm">##</a>No DM</h2>
<p>skip username: <code>/etc/systemd/system/getty@tty1.service.d/skip-username.conf</code></p>
<details open>
    <summary>TEXT</summary><pre
        class="codeblock"
      ><code class="language-" data-lang="">[Service]
ExecStart=
ExecStart=-/sbin/agetty -o &#39;-p -- hiraeth&#39; --noclear --skip-login - $TERM</code><button onclick="copyCode(this)" class="copybtn">copy</button></pre></details>

  <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="sddm">
  <a class="anchor inpage" href="#sddm">##</a>sddm</h2>
<h3 id="autologin">
  <a class="anchor inpage" href="#autologin">###</a>autologin</h3>
<p>默认session <code>/etc/sddm.conf</code></p>
<details open>
    <summary>TEXT</summary><pre
        class="codeblock"
      ><code class="language-" data-lang="">[Theme]
Current=chili

[Autologin]
User=hiraeth
Session=dwm.desktop</code><button onclick="copyCode(this)" class="copybtn">copy</button></pre></details>

  <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>免密码
You must then also be part of the nopasswdlogin group to be able to login interactively without entering your password:</p>
<details open>
    <summary>sh</summary><pre
        class="chroma codeblock"
      ><code class="language-sh" data-lang="sh"
          ><span style="display:flex;"><span>groupadd -r nopasswdlogin
</span></span><span style="display:flex;"><span>gpasswd -a username nopasswdlogin</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>SDDM goes through PAM so you must configure the SDDM configuration of PAM: <code>/etc/pam.d/sddm</code></p>
<details open>
    <summary>TEXT</summary><pre
        class="codeblock"
      ><code class="language-" data-lang="">#%PAM-1.0
auth        sufficient  pam_succeed_if.so user ingroup nopasswdlogin
auth        include     system-login
-auth       optional    pam_gnome_keyring.so
-auth       optional    pam_kwallet5.so

account     include     system-login

password    include     system-login
-password   optional    pam_gnome_keyring.so    use_authtok

session     optional    pam_keyinit.so          force revoke
session     include     system-login
-session    optional    pam_gnome_keyring.so    auto_start
-session    optional    pam_kwallet5.so         auto_start</code><button onclick="copyCode(this)" class="copybtn">copy</button></pre></details>

  <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/pam.d/sddm-autologin</code></p>
<details open>
    <summary>TEXT</summary><pre
        class="codeblock"
      ><code class="language-" data-lang="">#%PAM-1.0
auth        required    pam_env.so
auth        required    pam_faillock.so preauth
auth        required    pam_shells.so
auth        required    pam_nologin.so
auth        required    pam_permit.so
-auth       optional    pam_gnome_keyring.so
-auth       optional    pam_kwallet5.so
account     include     system-local-login
password    include     system-local-login
session     include     system-local-login
-session    optional    pam_gnome_keyring.so auto_start
-session    optional    pam_kwallet5.so auto_start</code><button onclick="copyCode(this)" class="copybtn">copy</button></pre></details>

  <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="files">
  <a class="anchor inpage" href="#files">##</a>files</h2>
<details open>
    <summary>/etc/zsh/zshenv</summary><pre
        class="codeblock"
      ><code class="language-/etc/zsh/zshenv" data-lang="/etc/zsh/zshenv">export ERRFILE=&#34;$XDG_CACHE_HOME/X11/xsession-errors&#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>]]></content:encoded></item><item><title>豆瓣记录导入obsidian</title><link>https://hiraethecho.github.io/docs/software/obsidian_douban/</link><pubDate>Wed, 28 May 2025 00:00:00 +0000</pubDate><author>wyz2016zxc@outlook.com(Hiraeth)</author><guid>https://hiraethecho.github.io/docs/software/obsidian_douban/</guid><description>&lt;h1 id="obsidian-和豆瓣"&gt;
&lt;a class="anchor inpage" href="#obsidian-%e5%92%8c%e8%b1%86%e7%93%a3"&gt;#&lt;/a&gt;obsidian 和豆瓣&lt;/h1&gt;
&lt;h2 id="plugins"&gt;
&lt;a class="anchor inpage" href="#plugins"&gt;##&lt;/a&gt;plugins&lt;/h2&gt;
&lt;p&gt;发现一些插件可以把豆瓣的信息导入到obsidian，可以作为阅读管理统计。&lt;/p&gt;
&lt;p&gt;首先是豆瓣的
，可以登陆豆瓣账户，然后可以同步自己的书影音。&lt;/p&gt;</description><content:encoded><![CDATA[<h1 id="obsidian-和豆瓣">
  <a class="anchor inpage" href="#obsidian-%e5%92%8c%e8%b1%86%e7%93%a3">#</a>obsidian 和豆瓣</h1>
<h2 id="plugins">
  <a class="anchor inpage" href="#plugins">##</a>plugins</h2>
<p>发现一些插件可以把豆瓣的信息导入到obsidian，可以作为阅读管理统计。</p>
<p>首先是豆瓣的
，可以登陆豆瓣账户，然后可以同步自己的书影音。</p>
<p>
导出划线，这个和豆瓣的不能是同一个文件，会有同步的问题。可以看完了再把划线移动到其他文档。</p>
<p>用bookshelf来查看，和记录阅读进度。这个似乎可以用base之类的方法代替。</p>
<h2 id="模板配置">
  <a class="anchor inpage" href="#%e6%a8%a1%e6%9d%bf%e9%85%8d%e7%bd%ae">##</a>模板配置</h2>
<h3 id="豆瓣">
  <a class="anchor inpage" href="#%e8%b1%86%e7%93%a3">###</a>豆瓣</h3>
<p>book</p>
<details open>
    <summary>temple</summary><pre
        class="codeblock"
      ><code class="language-temple" data-lang="temple">---
title: {{title}}
lists: {{type}}
score: {{score}}
rating: {{myRating}}
originalTitle: {{originalTitle}}
published: {{datePublished}}
pages: {{totalPage}}
author: {{author}}
tags: {{myTags}}
state: {{myState}}
url: {{url}}
country: {{country}}
language: {{language}}
time: {{time}}
comment: {{desc}}
cover:
---

# {{title}}

![image]({{image}})

comment: {{desc}}

{{myComment}}

doubanId: {{id}}

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

  <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>movie</p>
<details open>
    <summary>template</summary><pre
        class="codeblock"
      ><code class="language-template" data-lang="template">---
doubanId: {{id}}
title: {{title}}
lists: {{type}}
score: {{score}}
rating: {{myRating}}
originalTitle: {{originalTitle}}
published: {{datePublished}}
director: {{director}}
actor: {{actor}}
author: {{author}}
tags: {{myTags}}
url: {{url}}
aliases: {{aliases}}
country: {{country}}
language: {{language}}
time: {{time}}
comment: {{desc}}
cover:
---

# {{title}}
![]({{image}})
IMDb: {{IMDb}}</code><button onclick="copyCode(this)" class="copybtn">copy</button></pre></details>

  <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="weread">
  <a class="anchor inpage" href="#weread">###</a>weread</h3>
<p>这个是只导出划线和高亮没有评论，因为我不怎么在微信阅读写评论。</p>
<details open>
    <summary>template</summary><pre
        class="codeblock"
      ><code class="language-template" data-lang="template">---
title: {{ metaData.title }}
lists: book
author: {{ metaData.author }}
time: {{ metaData.publishTime }}
comment: {{ metaData.intro }}
cover: {{ metaDate.cover }}
---

![{{metaData.title}}|200]({{metaData.cover}})

作者： {{metaData.author}}
简介： {{metaData.intro}}
类型： {{metaData.category}}

## highlights

{% for chapter in chapterHighlights %}### {{chapter.chapterTitle}}

{% for highlight in chapter.highlights %}- {{ highlight.markText |trim }}
{% endfor %}
{% endfor %}</code><button onclick="copyCode(this)" class="copybtn">copy</button></pre></details>

  <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="bookshelf">
  <a class="anchor inpage" href="#bookshelf">###</a>bookshelf</h3>
<p>这个json可以直接放在<code>obsidian-repo/.obsidian/plugins/bookshelf/data.json</code>中。</p>
<details open>
    <summary>json</summary><pre
        class="chroma codeblock"
      ><code class="language-json" data-lang="json"
          ><span style="display:flex;"><span>{
</span></span><span style="display:flex;"><span>    <span style="color:#f92672">&#34;settingsVersion&#34;</span>: <span style="color:#ae81ff">20250408</span>,
</span></span><span style="display:flex;"><span>    <span style="color:#f92672">&#34;booksFolder&#34;</span>: <span style="color:#e6db74">&#34;gallery&#34;</span>,
</span></span><span style="display:flex;"><span>    <span style="color:#f92672">&#34;bookProperties&#34;</span>: {
</span></span><span style="display:flex;"><span>        <span style="color:#f92672">&#34;cover&#34;</span>: <span style="color:#e6db74">&#34;cover&#34;</span>,
</span></span><span style="display:flex;"><span>        <span style="color:#f92672">&#34;author&#34;</span>: <span style="color:#e6db74">&#34;author&#34;</span>,
</span></span><span style="display:flex;"><span>        <span style="color:#f92672">&#34;published&#34;</span>: <span style="color:#e6db74">&#34;published&#34;</span>,
</span></span><span style="display:flex;"><span>        <span style="color:#f92672">&#34;pages&#34;</span>: <span style="color:#e6db74">&#34;pages&#34;</span>,
</span></span><span style="display:flex;"><span>        <span style="color:#f92672">&#34;tags&#34;</span>: <span style="color:#e6db74">&#34;tags&#34;</span>,
</span></span><span style="display:flex;"><span>        <span style="color:#f92672">&#34;rating&#34;</span>: <span style="color:#e6db74">&#34;rating&#34;</span>,
</span></span><span style="display:flex;"><span>        <span style="color:#f92672">&#34;lists&#34;</span>: <span style="color:#e6db74">&#34;lists&#34;</span>,
</span></span><span style="display:flex;"><span>        <span style="color:#f92672">&#34;comment&#34;</span>: <span style="color:#e6db74">&#34;comment&#34;</span>,
</span></span><span style="display:flex;"><span>        <span style="color:#f92672">&#34;links&#34;</span>: <span style="color:#e6db74">&#34;links&#34;</span>,
</span></span><span style="display:flex;"><span>        <span style="color:#f92672">&#34;series&#34;</span>: <span style="color:#e6db74">&#34;series&#34;</span>,
</span></span><span style="display:flex;"><span>        <span style="color:#f92672">&#34;positionInSeries&#34;</span>: <span style="color:#e6db74">&#34;position-in-series&#34;</span>,
</span></span><span style="display:flex;"><span>        <span style="color:#f92672">&#34;duration&#34;</span>: <span style="color:#e6db74">&#34;duration&#34;</span>
</span></span><span style="display:flex;"><span>    },
</span></span><span style="display:flex;"><span>    <span style="color:#f92672">&#34;bookNote&#34;</span>: {
</span></span><span style="display:flex;"><span>        <span style="color:#f92672">&#34;enabled&#34;</span>: <span style="color:#66d9ef">true</span>,
</span></span><span style="display:flex;"><span>        <span style="color:#f92672">&#34;heading&#34;</span>: <span style="color:#e6db74">&#34;log&#34;</span>,
</span></span><span style="display:flex;"><span>        <span style="color:#f92672">&#34;dateFormat&#34;</span>: <span style="color:#e6db74">&#34;yyyy-MM-dd&#34;</span>,
</span></span><span style="display:flex;"><span>        <span style="color:#f92672">&#34;patterns&#34;</span>: {
</span></span><span style="display:flex;"><span>            <span style="color:#f92672">&#34;started&#34;</span>: <span style="color:#e6db74">&#34;{date}: Started&#34;</span>,
</span></span><span style="display:flex;"><span>            <span style="color:#f92672">&#34;finished&#34;</span>: <span style="color:#e6db74">&#34;{date}: Finished&#34;</span>,
</span></span><span style="display:flex;"><span>            <span style="color:#f92672">&#34;abandoned&#34;</span>: <span style="color:#e6db74">&#34;{date}: Abandoned&#34;</span>,
</span></span><span style="display:flex;"><span>            <span style="color:#f92672">&#34;absoluteProgress&#34;</span>: <span style="color:#e6db74">&#34;{date}: {start}-{end}&#34;</span>,
</span></span><span style="display:flex;"><span>            <span style="color:#f92672">&#34;relativeProgress&#34;</span>: <span style="color:#e6db74">&#34;{date}: {end}&#34;</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:#f92672">&#34;dailyNote&#34;</span>: {
</span></span><span style="display:flex;"><span>        <span style="color:#f92672">&#34;enabled&#34;</span>: <span style="color:#66d9ef">true</span>,
</span></span><span style="display:flex;"><span>        <span style="color:#f92672">&#34;heading&#34;</span>: <span style="color:#e6db74">&#34;Reading&#34;</span>,
</span></span><span style="display:flex;"><span>        <span style="color:#f92672">&#34;patterns&#34;</span>: {
</span></span><span style="display:flex;"><span>            <span style="color:#f92672">&#34;started&#34;</span>: <span style="color:#e6db74">&#34;Started {{book}}&#34;</span>,
</span></span><span style="display:flex;"><span>            <span style="color:#f92672">&#34;finished&#34;</span>: <span style="color:#e6db74">&#34;Finished {book}&#34;</span>,
</span></span><span style="display:flex;"><span>            <span style="color:#f92672">&#34;abandoned&#34;</span>: <span style="color:#e6db74">&#34;Abandoned {book}&#34;</span>,
</span></span><span style="display:flex;"><span>            <span style="color:#f92672">&#34;absoluteProgress&#34;</span>: <span style="color:#e6db74">&#34;Read {book}: {start}-{end}&#34;</span>,
</span></span><span style="display:flex;"><span>            <span style="color:#f92672">&#34;relativeProgress&#34;</span>: <span style="color:#e6db74">&#34;Read {book}: {end}&#34;</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:#f92672">&#34;readingProgress&#34;</span>: {
</span></span><span style="display:flex;"><span>        <span style="color:#f92672">&#34;newEntryLocation&#34;</span>: <span style="color:#e6db74">&#34;bookNote&#34;</span>
</span></span><span style="display:flex;"><span>    },
</span></span><span style="display:flex;"><span>    <span style="color:#f92672">&#34;previousVersion&#34;</span>: <span style="color:#e6db74">&#34;0.18.0&#34;</span>,
</span></span><span style="display:flex;"><span>    <span style="color:#f92672">&#34;showReleaseNotes&#34;</span>: <span style="color:#66d9ef">true</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><h2 id="解释">
  <a class="anchor inpage" href="#%e8%a7%a3%e9%87%8a">##</a>解释</h2>
<p>我的文件放在<code>obsidian-repo/gallery/</code>目录下，用bookshelf的lists来区分书、电影和音乐</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>shell概览</title><link>https://hiraethecho.github.io/docs/linux/shell/</link><pubDate>Mon, 05 May 2025 00:00:00 +0000</pubDate><author>wyz2016zxc@outlook.com(Hiraeth)</author><guid>https://hiraethecho.github.io/docs/linux/shell/</guid><description>主要靠ai生成的shell基本知识手册</description><content:encoded><![CDATA[<h1 id="shell">
  <a class="anchor inpage" href="#shell">#</a>shell</h1>
<h2 id="intro">
  <a class="anchor inpage" href="#intro">##</a>intro</h2>
<p>A shell is a command-line interpreter that provides a user interface for interacting with the operating system. It allows users to execute commands, run scripts, and manage system processes. Popular shells include bash, zsh, and fish.</p>
<h3 id="history">
  <a class="anchor inpage" href="#history">###</a>history</h3>
<p>The shell originated in the early days of UNIX, providing users a way to interact with the operating system. The Bourne Shell (sh) was one of the earliest, followed by more advanced shells like Bash, Zsh, and Fish. Each new shell introduced features that improved usability, scripting, and customization for users and administrators.</p>
<h3 id="posix">
  <a class="anchor inpage" href="#posix">###</a>posix</h3>
<p>POSIX stands for &ldquo;Portable Operating System Interface.&rdquo; It is a set of standardized operating system interfaces and shell command standards, maintained by the IEEE. POSIX ensures compatibility between Unix-like operating systems by defining common APIs, command-line utilities, and scripting interfaces.</p>
<p>In the context of shells, POSIX compliance ensures that shell scripts and commands written for one POSIX-compliant shell will work on another, regardless of the underlying operating system. For example, the <code>sh</code> shell is often used as a reference implementation for POSIX-compliant scripting. However, advanced shells like Bash and Zsh often extend POSIX standards with additional features and functionalities.</p>
<p>Key aspects of POSIX include:</p>
<ol>
<li><strong>Shell Command Language</strong>: Specifies syntax and utilities for scripting.</li>
<li><strong>System Interfaces</strong>: Defines APIs for file system operations, process control, and more.</li>
<li><strong>Utility Programs</strong>: Standardizes common tools like <code>grep</code>, <code>awk</code>, and <code>sed</code>.</li>
</ol>
<p>POSIX plays a critical role in ensuring interoperability and portability across different Unix-based systems, making it a cornerstone of modern shell environments.</p>
<h2 id="start-a-shell">
  <a class="anchor inpage" href="#start-a-shell">##</a>Start a shell</h2>
<p>There are three main cases that start a shell: login, interact, and in the shell scripts.</p>
<p>Linux starts a shell in the following situations:</p>
<ol>
<li><strong>Login Shell</strong>: Automatically invoked when a user logs in via TTY, SSH, or terminal emulator.</li>
<li><strong>Interactive Shell</strong>: When a user opens a new terminal window or manually starts a shell.</li>
<li><strong>Shell in Scripts</strong>: When a script containing a shebang (e.g., <code>#!/bin/bash</code>) is executed, the specified shell is started.</li>
</ol>
<p>there are also other cases, like ssh, getty, rescure mode etc</p>
<h3 id="login-shell">
  <a class="anchor inpage" href="#login-shell">###</a>login shell</h3>
<p>A shell starts automatically when you log in through a TTY, SSH, or terminal emulator. You can also start a shell manually by running its executable (e.g., bash, zsh, fish) from an existing shell or script. Shells start when prompted by the operating system or when explicitly invoked.</p>
<h3 id="interact-shell">
  <a class="anchor inpage" href="#interact-shell">###</a>interact shell</h3>
<p>After login, starting a new non-login shell (like opening a new terminal window) usually loads only the interactive shell configuration file (<code>~/.bashrc</code> for Bash, <code>~/.zshrc</code> for Zsh`). Environment variables and settings exported in the login shell are inherited by the new shell, unless overridden in the new shell&rsquo;s config file.</p>
<p>You can start most shells without loading configuration files by passing specific flags. For example, Bash: <code>bash --noprofile --norc</code>; Zsh: <code>zsh -f</code>. This launches the shell in a minimal state, ignoring personal and system-wide configuration files.</p>
<p>To start a shell as a different user, use the <code>su - username</code> or <code>sudo -i -u username</code> commands. The login shell for the specified user will be started, and it will load that user&rsquo;s configuration files (such as those in their home directory). Controlling which files are loaded depends on the shell and options passed; for example, you can use <code>bash --noprofile --norc</code> after switching users to avoid loading configs.</p>
<p>When starting a new shell with a different user, to avoid inheriting unwanted configuration, use options that bypass user config files (e.g. for Bash: <code>bash --noprofile --norc</code>; for Zsh: <code>zsh -f</code>). If you want to inherit configurations from the parent shell, you can manually export the desired environment variables before starting the new shell, or source config files as needed.</p>
<p>By default, when a new shell is started, the present working directory (PWD) is inherited from the parent process (the shell or terminal that launched it). If a shell is started during login (for example, via TTY or SSH), the default directory is usually the user&rsquo;s home directory (<code>$HOME</code>).</p>
<h3 id="shell-in-de">
  <a class="anchor inpage" href="#shell-in-de">###</a>shell in DE</h3>
<p>A special case is starting a shell in a DE (Desktop Environment).</p>
<p>Launcher programs like dmenu or rofi typically use the shell specified in the <code>SHELL</code> environment variable of the running user. If <code>SHELL</code> is not set, they may default to <code>/bin/sh</code> or whatever is configured in <code>/etc/passwd</code> for the user.</p>
<p>The default working directory (PWD) for a shell launched by a program like dmenu or rofi is typically the user&rsquo;s home directory (<code>$HOME</code>). However, this can be changed by the launcher or by the environment from which the launcher itself was started.</p>
<h3 id="shell-in-script">
  <a class="anchor inpage" href="#shell-in-script">###</a>shell in script</h3>
<p>Yes, when running a shell within a script (using shebang like <code>#!/bin/bash</code> or <code>#!/bin/zsh</code>), the script may behave differently depending on the shell used. Some shells have distinct syntax, built-ins, or environment handling. Scripts can also use subshells to isolate environments, and you can explicitly invoke subshells with commands like <code>(command)</code> or by calling another shell executable within the script.</p>
<p>When a shell is used in a script, it uses the environment variables defined in the parent shell or operating system environment where the script is executed. These may include system-wide variables (e.g., PATH, HOME) and user-defined variables from configuration files (e.g., ~/.bashrc, ~/.zshrc). The script can also define its own environment variables, which will only persist during the script&rsquo;s execution. Additionally, the shell may load configuration files specific to the shell being used, depending on whether the script is executed in a login or non-login context.</p>
<p>For example:</p>
<ul>
<li>A script that starts with <code>#!/bin/bash</code> as the shebang will inherit environment variables from the parent Bash shell.</li>
<li>If the script explicitly sources configuration files (e.g., <code>source ~/.bashrc</code>), it may load additional variables or settings.</li>
<li>Subshells started within the script can have isolated environments, which can either inherit variables or define new ones for their scope.</li>
</ul>
<p>To inspect or modify the environment variables in a script, commands like <code>export</code>, <code>printenv</code>, or <code>env</code> can be used.</p>
<p>Keep in mind that some shells have distinct syntax and behaviors concerning environment variables, so the choice of shell can influence the script&rsquo;s behavior.</p>
<p>To avoid unintended configurations, you can start the shell with options to bypass configuration files or explicitly define the environment variables needed by the script.</p>
<p>Example:</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/bash --noprofile --norc
</span></span></span><span style="display:flex;"><span><span style="color:#75715e"></span>export MY_VARIABLE<span style="color:#f92672">=</span><span style="color:#e6db74">&#34;value&#34;</span>
</span></span><span style="display:flex;"><span>echo <span style="color:#e6db74">&#34;Current PATH: </span>$PATH<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><h2 id="configuration">
  <a class="anchor inpage" href="#configuration">##</a>configuration</h2>
<h3 id="set-shell">
  <a class="anchor inpage" href="#set-shell">###</a>set shell</h3>
<p>To change the default shell for a user, use the command:</p>
<details open>
    <summary>sh</summary><pre
        class="chroma codeblock"
      ><code class="language-sh" data-lang="sh"
          ><span style="display:flex;"><span>chsh -s /path/to/shell</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>For example, to set Zsh as the default shell:</p>
<details open>
    <summary>sh</summary><pre
        class="chroma codeblock"
      ><code class="language-sh" data-lang="sh"
          ><span style="display:flex;"><span>chsh -s <span style="color:#66d9ef">$(</span>which zsh<span style="color:#66d9ef">)</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="configuration-files">
  <a class="anchor inpage" href="#configuration-files">###</a>configuration files</h3>
<p>zsh</p>
<table>
  <thead>
      <tr>
          <th>Shell Type</th>
          <th>System Configurations</th>
          <th>User Configurations</th>
      </tr>
  </thead>
  <tbody>
      <tr>
          <td>Login Shell</td>
          <td><code>/etc/zprofile</code>, <code>/etc/zlogin</code></td>
          <td><code>~/.zprofile</code>, <code>~/.zlogin</code></td>
      </tr>
      <tr>
          <td>Interactive Shell</td>
          <td><code>/etc/zshrc</code></td>
          <td><code>~/.zshrc</code></td>
      </tr>
      <tr>
          <td>Shell in a Script</td>
          <td><code>/etc/zshenv</code></td>
          <td><code>~/.zshenv</code></td>
      </tr>
  </tbody>
</table>
<p>bash</p>
<table>
  <thead>
      <tr>
          <th>Shell Type</th>
          <th>System Configurations</th>
          <th>User Configurations</th>
      </tr>
  </thead>
  <tbody>
      <tr>
          <td>Login Shell</td>
          <td><code>/etc/profile</code></td>
          <td><code>~/.bash_profile</code>, <code>~/.bash_login</code>, <code>~/.profile</code></td>
      </tr>
      <tr>
          <td>Interactive Shell</td>
          <td><code>/etc/bash.bashrc</code></td>
          <td><code>~/.bashrc</code></td>
      </tr>
      <tr>
          <td>Shell in a Script</td>
          <td>None (scripts do not load config files)</td>
          <td>None</td>
      </tr>
  </tbody>
</table>
<h3 id="syntax">
  <a class="anchor inpage" href="#syntax">###</a>syntax</h3>
<p>Zsh Configuration Files:</p>
<ol>
<li>
<p><strong>Setting Environment Variables</strong>:</p>
<details open>
    <summary>zsh</summary><pre
        class="chroma codeblock"
      ><code class="language-zsh" data-lang="zsh"
          ><span style="display:flex;"><span>export PATH<span style="color:#f92672">=</span><span style="color:#e6db74">&#34;</span>$PATH<span style="color:#e6db74">:/new/path&#34;</span>
</span></span><span style="display:flex;"><span>export EDITOR<span style="color:#f92672">=</span><span style="color:#e6db74">&#34;vim&#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></li>
<li>
<p><strong>Defining Aliases</strong>:</p>
<details open>
    <summary>zsh</summary><pre
        class="chroma codeblock"
      ><code class="language-zsh" data-lang="zsh"
          ><span style="display:flex;"><span>alias ll<span style="color:#f92672">=</span><span style="color:#e6db74">&#34;ls -la&#34;</span>
</span></span><span style="display:flex;"><span>alias gs<span style="color:#f92672">=</span><span style="color:#e6db74">&#34;git status&#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></li>
<li>
<p><strong>Creating Functions</strong>:</p>
<details open>
    <summary>zsh</summary><pre
        class="chroma codeblock"
      ><code class="language-zsh" data-lang="zsh"
          ><span style="display:flex;"><span><span style="color:#66d9ef">function</span> greet<span style="color:#f92672">()</span> <span style="color:#f92672">{</span>
</span></span><span style="display:flex;"><span>    echo <span style="color:#e6db74">&#34;Hello, </span>$1<span style="color:#e6db74">!&#34;</span>
</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></li>
<li>
<p><strong>Sourcing Other Files</strong>:</p>
<details open>
    <summary>zsh</summary><pre
        class="chroma codeblock"
      ><code class="language-zsh" data-lang="zsh"
          ><span style="display:flex;"><span>source ~/.zshrc</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>
</ol>
<p>Bash Configuration Files:</p>
<ol>
<li>
<p><strong>Setting Environment Variables</strong>:</p>
<details open>
    <summary>bash</summary><pre
        class="chroma codeblock"
      ><code class="language-bash" data-lang="bash"
          ><span style="display:flex;"><span>export PATH<span style="color:#f92672">=</span><span style="color:#e6db74">&#34;</span>$PATH<span style="color:#e6db74">:/new/path&#34;</span>
</span></span><span style="display:flex;"><span>export EDITOR<span style="color:#f92672">=</span><span style="color:#e6db74">&#34;vim&#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></li>
<li>
<p><strong>Defining Aliases</strong>:</p>
<details open>
    <summary>bash</summary><pre
        class="chroma codeblock"
      ><code class="language-bash" data-lang="bash"
          ><span style="display:flex;"><span>alias ll<span style="color:#f92672">=</span><span style="color:#e6db74">&#34;ls -la&#34;</span>
</span></span><span style="display:flex;"><span>alias gs<span style="color:#f92672">=</span><span style="color:#e6db74">&#34;git status&#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></li>
<li>
<p><strong>Creating Functions</strong>:</p>
<details open>
    <summary>bash</summary><pre
        class="chroma codeblock"
      ><code class="language-bash" data-lang="bash"
          ><span style="display:flex;"><span>greet<span style="color:#f92672">()</span> <span style="color:#f92672">{</span>
</span></span><span style="display:flex;"><span>    echo <span style="color:#e6db74">&#34;Hello, </span>$1<span style="color:#e6db74">!&#34;</span>
</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></li>
<li>
<p><strong>Sourcing Other Files</strong>:</p>
<details open>
    <summary>bash</summary><pre
        class="chroma codeblock"
      ><code class="language-bash" data-lang="bash"
          ><span style="display:flex;"><span>source ~/.bashrc</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>
</ol>
<h2 id="shells">
  <a class="anchor inpage" href="#shells">##</a>shells</h2>
<p>Commonly used shells include:</p>
<ul>
<li>Bash (Bourne Again SHell): Default on many Linux systems</li>
<li>Zsh (Z Shell): Known for advanced features and customization</li>
<li>Fish (Friendly Interactive Shell): User-friendly and interactive</li>
<li>sh (Bourne Shell): The original UNIX shell</li>
<li>tcsh/csh: C Shell and its enhanced version</li>
</ul>
<table>
  <thead>
      <tr>
          <th>Shell</th>
          <th>Pros</th>
          <th>Cons</th>
      </tr>
  </thead>
  <tbody>
      <tr>
          <td>Bash</td>
          <td>Widely supported, strong scripting capabilities</td>
          <td>Less modern interactive features</td>
      </tr>
      <tr>
          <td>Zsh</td>
          <td>Powerful completion, interactive features, customization</td>
          <td>Slightly heavier than Bash</td>
      </tr>
      <tr>
          <td>Fish</td>
          <td>User-friendly syntax and autocompletion</td>
          <td>Less POSIX-compatible for scripting</td>
      </tr>
      <tr>
          <td>sh</td>
          <td>Minimal and portable</td>
          <td>Limited interactivity and scripting features</td>
      </tr>
      <tr>
          <td>tcsh/csh</td>
          <td>C-like syntax, good for some users</td>
          <td>Less common, some scripting limitations</td>
      </tr>
  </tbody>
</table>
]]></content:encoded></item><item><title>Latex Tricks</title><link>https://hiraethecho.github.io/docs/software/latex-trick/</link><pubDate>Sun, 04 May 2025 00:00:00 +0000</pubDate><author>wyz2016zxc@outlook.com(Hiraeth)</author><guid>https://hiraethecho.github.io/docs/software/latex-trick/</guid><description>&lt;h1 id="latex-tricks"&gt;
&lt;a class="anchor inpage" href="#latex-tricks"&gt;#&lt;/a&gt;Latex tricks&lt;/h1&gt;
&lt;h2 id="note"&gt;
&lt;a class="anchor inpage" href="#note"&gt;##&lt;/a&gt;note&lt;/h2&gt;
&lt;h2 id="comment"&gt;
&lt;a class="anchor inpage" href="#comment"&gt;##&lt;/a&gt;comment&lt;/h2&gt;
&lt;p&gt;use following to comment mulilines:&lt;/p&gt;
&lt;details open&gt;
&lt;summary&gt;tex&lt;/summary&gt;&lt;pre
class="chroma codeblock"
&gt;&lt;code class="language-tex" data-lang="tex"
&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#66d9ef"&gt;\iffalse&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;comments
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;another line
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#66d9ef"&gt;\fi&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;tex&lt;/summary&gt;&lt;pre
class="chroma codeblock"
&gt;&lt;code class="language-tex" data-lang="tex"
&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;\newcommand&lt;/span&gt;{&lt;span style="color:#66d9ef"&gt;\chen&lt;/span&gt;}[1]{{&lt;span style="color:#66d9ef"&gt;\textcolor&lt;/span&gt;{red}{[Chen: #1]}}}
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#66d9ef"&gt;\newcommand&lt;/span&gt;{&lt;span style="color:#66d9ef"&gt;\liu&lt;/span&gt;}[1]{{&lt;span style="color:#66d9ef"&gt;\textcolor&lt;/span&gt;{magenta}{[Liu: #1]}}}
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#66d9ef"&gt;\newcommand&lt;/span&gt;{&lt;span style="color:#66d9ef"&gt;\wang&lt;/span&gt;}[1]{{&lt;span style="color:#66d9ef"&gt;\textcolor&lt;/span&gt;{blue}{[Wang: #1]}}}
&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;\begin&lt;/span&gt;{document}
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#66d9ef"&gt;\liu&lt;/span&gt;{test}
&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;\chen&lt;/span&gt;{test}
&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;\wang&lt;/span&gt;{test}
&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;{document}&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="diff"&gt;
&lt;a class="anchor inpage" href="#diff"&gt;##&lt;/a&gt;diff&lt;/h2&gt;
&lt;p&gt;&lt;code&gt;latexdiff&lt;/code&gt; to diff in pdf. tldr:&lt;/p&gt;</description><content:encoded><![CDATA[<h1 id="latex-tricks">
  <a class="anchor inpage" href="#latex-tricks">#</a>Latex tricks</h1>
<h2 id="note">
  <a class="anchor inpage" href="#note">##</a>note</h2>
<h2 id="comment">
  <a class="anchor inpage" href="#comment">##</a>comment</h2>
<p>use following to comment mulilines:</p>
<details open>
    <summary>tex</summary><pre
        class="chroma codeblock"
      ><code class="language-tex" data-lang="tex"
          ><span style="display:flex;"><span><span style="color:#66d9ef">\iffalse</span>
</span></span><span style="display:flex;"><span>comments
</span></span><span style="display:flex;"><span>another line
</span></span><span style="display:flex;"><span><span style="color:#66d9ef">\fi</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>tex</summary><pre
        class="chroma codeblock"
      ><code class="language-tex" data-lang="tex"
          ><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span><span style="color:#66d9ef">\newcommand</span>{<span style="color:#66d9ef">\chen</span>}[1]{{<span style="color:#66d9ef">\textcolor</span>{red}{[Chen: #1]}}}
</span></span><span style="display:flex;"><span><span style="color:#66d9ef">\newcommand</span>{<span style="color:#66d9ef">\liu</span>}[1]{{<span style="color:#66d9ef">\textcolor</span>{magenta}{[Liu: #1]}}}
</span></span><span style="display:flex;"><span><span style="color:#66d9ef">\newcommand</span>{<span style="color:#66d9ef">\wang</span>}[1]{{<span style="color:#66d9ef">\textcolor</span>{blue}{[Wang: #1]}}}
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span><span style="color:#66d9ef">\begin</span>{document}
</span></span><span style="display:flex;"><span><span style="color:#66d9ef">\liu</span>{test}
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span><span style="color:#66d9ef">\chen</span>{test}
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span><span style="color:#66d9ef">\wang</span>{test}
</span></span><span style="display:flex;"><span><span style="color:#66d9ef">\end</span>{document}</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="diff">
  <a class="anchor inpage" href="#diff">##</a>diff</h2>
<p><code>latexdiff</code> to diff in pdf. tldr:</p>
<details open>
    <summary>TEXT</summary><pre
        class="codeblock"
      ><code class="language-" data-lang="">  Determine differences between two LaTeX files.
  More information: &lt;https://ctan.org/pkg/latexdiff&gt;.

  Determine changes between different versions of a LaTeX file (the resulting LaTeX file can be compiled to show differences underlined):

      latexdiff old.tex new.tex &gt; diff.tex

  Determine changes between different versions of a LaTeX file by highlighting differences in boldface:

      latexdiff --type=BOLD old.tex new.tex &gt; diff.tex

  Determine changes between different versions of a LaTeX file, and display minor changes in equations with both added and deleted graphics:

      latexdiff --math-markup=fine --graphics-markup=both old.tex new.tex &gt; diff.tex</code><button onclick="copyCode(this)" class="copybtn">copy</button></pre></details>

  <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-latexdiff</code> compare pdf in git history</p>
<p>Important options:</p>
<details open>
    <summary>TEXT</summary><pre
        class="codeblock"
      ><code class="language-" data-lang="">Usage: git latexdiff [options] OLD [NEW]
OLD and NEW are Git revision identifiers. NEW defaults to HEAD.
If &#34;--&#34; is used for NEW, then diff against the working directory.
    --latex               run latex instead of pdflatex
    --xelatex             run xelatex instead of pdflatex
    --lualatex            run lualatex instead of pdflatex
    --main &lt;file&gt;         name of the main LaTeX, R Sweave,
    --tmpdirprefix        where temporary directory will be created (default: /tmp).
                            Relative path will use repository root as a base
    --ignore-latex-errors keep on going even if latex gives errors, so long as
                          a PDF file is produced</code><button onclick="copyCode(this)" class="copybtn">copy</button></pre></details>

  <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, use <code>git latexdiff HEAD -- --tmpdirprefix tmp --main main.tex</code> to check differences between worktree and last commit.</p>
<h2 id="picture">
  <a class="anchor inpage" href="#picture">##</a>picture</h2>
<p>If fix position:</p>
<details open>
    <summary>tex</summary><pre
        class="chroma codeblock"
      ><code class="language-tex" data-lang="tex"
          ><span style="display:flex;"><span><span style="color:#66d9ef">\usepackage</span>{float} <span style="color:#75715e">% 在导言区添加
</span></span></span><span style="display:flex;"><span><span style="color:#75715e"></span><span style="color:#66d9ef">\usepackage</span>{graphicx} <span style="color:#75715e">% 用于插入图片
</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:#66d9ef">\begin</span>{figure}[H] <span style="color:#75715e">% 使用 [H] 固定位置
</span></span></span><span style="display:flex;"><span><span style="color:#75715e"></span>    <span style="color:#66d9ef">\centering</span>
</span></span><span style="display:flex;"><span>    <span style="color:#66d9ef">\includegraphics</span><span style="color:#a6e22e">[width=0.8\textwidth]</span>{example-image}
</span></span><span style="display:flex;"><span>    <span style="color:#66d9ef">\caption</span>{固定位置的图片}
</span></span><span style="display:flex;"><span>    <span style="color:#66d9ef">\label</span>{fig:example}
</span></span><span style="display:flex;"><span><span style="color:#66d9ef">\end</span>{figure}</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>centering:</p>
<details open>
    <summary>tex</summary><pre
        class="chroma codeblock"
      ><code class="language-tex" data-lang="tex"
          ><span style="display:flex;"><span><span style="color:#66d9ef">\usepackage</span>{graphicx} <span style="color:#75715e">% 在导言区添加
</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:#66d9ef">\centering</span>
</span></span><span style="display:flex;"><span>    <span style="color:#66d9ef">\includegraphics</span><span style="color:#a6e22e">[width=0.8\textwidth]</span>{example-image}
</span></span><span style="display:flex;"><span>    <span style="color:#66d9ef">\par</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>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>Write latex with neovim</title><link>https://hiraethecho.github.io/docs/software/vimtex/</link><pubDate>Sun, 27 Apr 2025 00:00:00 +0000</pubDate><author>wyz2016zxc@outlook.com(Hiraeth)</author><guid>https://hiraethecho.github.io/docs/software/vimtex/</guid><description>&lt;h1 id="write-latex-with-neovim"&gt;
&lt;a class="anchor inpage" href="#write-latex-with-neovim"&gt;#&lt;/a&gt;Write latex with neovim&lt;/h1&gt;
&lt;p&gt;\(\latex\)&lt;/p&gt;
&lt;h2 id="vimtex"&gt;
&lt;a class="anchor inpage" href="#vimtex"&gt;##&lt;/a&gt;vimtex&lt;/h2&gt;
&lt;p&gt;&lt;code&gt;vimtex&lt;/code&gt;基本上是提供了全套的功能，包括&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;目录，标签等&lt;/li&gt;
&lt;li&gt;各种环境，&lt;code&gt;insert&lt;/code&gt;模式下的各种snippets，&lt;code&gt;normal&lt;/code&gt;模式下的文本对象和命令&lt;/li&gt;
&lt;li&gt;编译，报错&lt;/li&gt;
&lt;li&gt;正向搜索（从tex定位到pdf）和反向搜索（从pdf定位到tex）&lt;/li&gt;
&lt;li&gt;conceal （有点影响性能）&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;而且帮助文档非常详尽，维护积极，而且&lt;code&gt;vim&lt;/code&gt;上也能用&lt;/p&gt;</description><content:encoded><![CDATA[<h1 id="write-latex-with-neovim">
  <a class="anchor inpage" href="#write-latex-with-neovim">#</a>Write latex with neovim</h1>
<p>\(\latex\)</p>
<h2 id="vimtex">
  <a class="anchor inpage" href="#vimtex">##</a>vimtex</h2>
<p><code>vimtex</code>基本上是提供了全套的功能，包括</p>
<ul>
<li>目录，标签等</li>
<li>各种环境，<code>insert</code>模式下的各种snippets，<code>normal</code>模式下的文本对象和命令</li>
<li>编译，报错</li>
<li>正向搜索（从tex定位到pdf）和反向搜索（从pdf定位到tex）</li>
<li>conceal （有点影响性能）</li>
</ul>
<p>而且帮助文档非常详尽，维护积极，而且<code>vim</code>上也能用</p>
<p>缺点几乎没有，除了对与某些信奉unix哲学<em>做一件事并做到最好</em>的人（比如说我）来说有些臃肿。另一个是预设置的快捷键很多，但不一定符合所有人习惯（又是我）。</p>
<h2 id="latex">
  <a class="anchor inpage" href="#latex">##</a>latex</h2>
<p>首先需要一个<code>latex</code>发行版，比如<code>texlive</code>或者<code>miktex</code>。实际编译过程很复杂，为了生成目录和参考文献需要多次编译。但是<code>latexmk</code>可以帮助完成复杂的顺序。最重要的是，<code>latexmk</code>可以监听文本变化，自动重新编译，以此实现“实时”预览。</p>
<blockquote class="alert alert-tip">
      <p class="alert-heading">实际上不是实时。会在每次保存文件时编译，所以<code>insert</code>模式下敲字时并不会更新。另一方面还取决于编译速度。</p></blockquote><p>在<code>archlinux</code>上，可以安装整个<code>texlive</code>，如果觉得太臃肿也可以安装其中部分包，例如我只安装了</p>
<details open>
    <summary>TEXT</summary><pre
        class="codeblock"
      ><code class="language-" data-lang="">texlive-bibtexextra
texlive-binextra
texlive-langchinese
texlive-latexextra
texlive-mathscience
texlive-pstricks
texlive-xetex</code><button onclick="copyCode(this)" class="copybtn">copy</button></pre></details>

  <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>tectonic</code>等可用，但是难以实现实时预览。</p>
<blockquote class="alert alert-note">
      <p class="alert-heading">可以用texpresso</p></blockquote><h2 id="lsp">
  <a class="anchor inpage" href="#lsp">##</a>lsp</h2>
<p><code>texlab</code></p>
<p><code>tex-fmt</code></p>
<h2 id="compile">
  <a class="anchor inpage" href="#compile">##</a>compile</h2>
<p>原则上可以直接用命令行编译。但是既然在<code>neovim</code>里，可以用插件封装的命令。</p>
<p>用<code>vimtex</code>或<code>texlab</code></p>
<h2 id="inverse-and-reverse-search">
  <a class="anchor inpage" href="#inverse-and-reverse-search">##</a>inverse and reverse search</h2>
<h2 id="snippets">
  <a class="anchor inpage" href="#snippets">##</a>snippets</h2>
<h3 id="mathzone">
  <a class="anchor inpage" href="#mathzone">###</a>mathzone</h3>
<p>为了在文本和数学公式环境中使用不同的片段，例如<code>CC</code>只在数学公式中自动展开为<code>\mathbb{C}</code>，需要对能检测数学环境。</p>
<p>最简单的方法是调用<code>vimtex</code>的功能。</p>
<p>用<code>python</code>检测。</p>
<p>用treesitter检测。</p>
<h3 id="engine">
  <a class="anchor inpage" href="#engine">###</a>engine</h3>
<p>UltiSnip</p>
<p>LuaSnip</p>
]]></content:encoded></item><item><title>qemu虚拟机</title><link>https://hiraethecho.github.io/docs/linux/virtual-machine/</link><pubDate>Mon, 21 Apr 2025 00:00:00 +0000</pubDate><author>wyz2016zxc@outlook.com(Hiraeth)</author><guid>https://hiraethecho.github.io/docs/linux/virtual-machine/</guid><description>在linux上配置使用qemu虚拟机</description><content:encoded><![CDATA[<h1 id="qemu虚拟机">
  <a class="anchor inpage" href="#qemu%e8%99%9a%e6%8b%9f%e6%9c%ba">#</a>qemu虚拟机</h1>
<h2 id="install">
  <a class="anchor inpage" href="#install">##</a>Install</h2>
<p>Install pakages</p>
<details open>
    <summary>arch</summary><pre
        class="codeblock"
      ><code class="language-arch" data-lang="arch">paru -S qemu-base # basic
paru -S libvirt # 虚拟机一些api的封装
virtual-manager # GUI
paru -S dnsmasq bridge-utils # net</code><button onclick="copyCode(this)" class="copybtn">copy</button></pre></details>

  <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>Add user into groups, and start services<br>
编辑文件<code>/etc/libvirt/libvirtd.conf</code></p>
<details open>
    <summary>conf</summary><pre
        class="codeblock"
      ><code class="language-conf" data-lang="conf">unix_sock_group = &#34;libvirt&#34;
unix_sock_rw_perms = &#34;0770&#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="">sudo usermod -a -G libvirt $(whoami)</code><button onclick="copyCode(this)" class="copybtn">copy</button></pre></details>

  <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 enable libvirtd.service</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="net">
  <a class="anchor inpage" href="#net">##</a>net</h2>
<details open>
    <summary>sh</summary><pre
        class="chroma codeblock"
      ><code class="language-sh" data-lang="sh"
          ><span style="display:flex;"><span>sudo virsh net-list --all
</span></span><span style="display:flex;"><span>sudo virsh net-start --all
</span></span><span style="display:flex;"><span>sudo virsh net-autostart default</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="windows">
  <a class="anchor inpage" href="#windows">##</a>Windows</h2>
<p>
 一个更迷你的win镜像</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>Archlinux从安装到配置</title><link>https://hiraethecho.github.io/docs/linux/archlinux/</link><pubDate>Sat, 04 Jan 2025 00:00:00 +0000</pubDate><author>wyz2016zxc@outlook.com(Hiraeth)</author><guid>https://hiraethecho.github.io/docs/linux/archlinux/</guid><description>关于archlinux的一个汇总</description><content:encoded><![CDATA[<h1 id="关于arch的安装和配置">
  <a class="anchor inpage" href="#%e5%85%b3%e4%ba%8earch%e7%9a%84%e5%ae%89%e8%a3%85%e5%92%8c%e9%85%8d%e7%bd%ae">#</a>关于arch的安装和配置</h1>
<blockquote class="alert alert-important">
      <p class="alert-heading">IMPORTANT</p><p>I use Arch by the way.</p></blockquote><h2 id="start">
  <a class="anchor inpage" href="#start">##</a>start</h2>
<ul>
<li>
</li>
<li>
</li>
</ul>
<h2 id="usage">
  <a class="anchor inpage" href="#usage">##</a>usage</h2>
<ul>
<li>
</li>
</ul>
<h2 id="more">
  <a class="anchor inpage" href="#more">##</a>more</h2>
<ul>
<li>
</li>
<li>
</li>
</ul>
]]></content:encoded></item><item><title>ArchWiki摘抄</title><link>https://hiraethecho.github.io/docs/linux/archwiki/</link><pubDate>Fri, 03 Jan 2025 00:00:00 +0000</pubDate><author>wyz2016zxc@outlook.com(Hiraeth)</author><guid>https://hiraethecho.github.io/docs/linux/archwiki/</guid><description>从archwiki找的一些有用的东西</description><content:encoded><![CDATA[<h1 id="archwiki摘抄">
  <a class="anchor inpage" href="#archwiki%e6%91%98%e6%8a%84">#</a>ArchWiki摘抄</h1>
<h2 id="font">
  <a class="anchor inpage" href="#font">##</a>font</h2>
<p>find the font that contains chinese</p>
<details open>
    <summary>sh</summary><pre
        class="chroma codeblock"
      ><code class="language-sh" data-lang="sh"
          ><span style="display:flex;"><span>fc-list -f <span style="color:#e6db74">&#39;%{file}\n&#39;</span> :lang<span style="color:#f92672">=</span>zh</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>check monospace</p>
<details open>
    <summary>sh</summary><pre
        class="chroma codeblock"
      ><code class="language-sh" data-lang="sh"
          ><span style="display:flex;"><span>fc-match monospace</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>set fallback fonts, edit <code>$XDG_CONFIG_HOME/fontconfig/fonts.conf</code>:</p>
<details open>
    <summary>text</summary><pre
        class="chroma codeblock"
      ><code class="language-text" data-lang="text"
          ><span style="display:flex;"><span>&lt;?xml version=&#34;1.0&#34;?&gt;
</span></span><span style="display:flex;"><span>&lt;!DOCTYPE fontconfig SYSTEM &#34;fonts.dtd&#34;&gt;
</span></span><span style="display:flex;"><span>&lt;fontconfig&gt;
</span></span><span style="display:flex;"><span>&lt;alias&gt;
</span></span><span style="display:flex;"><span>   &lt;family&gt;serif&lt;/family&gt;
</span></span><span style="display:flex;"><span>   &lt;prefer&gt;
</span></span><span style="display:flex;"><span>     &lt;family&gt;LXGW Wenkai mono&lt;/family&gt;
</span></span><span style="display:flex;"><span>   &lt;/prefer&gt;
</span></span><span style="display:flex;"><span> &lt;/alias&gt;
</span></span><span style="display:flex;"><span>&lt;alias&gt;
</span></span><span style="display:flex;"><span>   &lt;family&gt;monospace&lt;/family&gt;
</span></span><span style="display:flex;"><span>   &lt;prefer&gt;
</span></span><span style="display:flex;"><span>     &lt;family&gt;CodeNewRoman Nerd Font&lt;/family&gt;
</span></span><span style="display:flex;"><span>     &lt;family&gt;LXGW Wenkai mono&lt;/family&gt;
</span></span><span style="display:flex;"><span>   &lt;/prefer&gt;
</span></span><span style="display:flex;"><span> &lt;/alias&gt;
</span></span><span style="display:flex;"><span>&lt;/fontconfig&gt;</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="xorg">
  <a class="anchor inpage" href="#xorg">##</a>xorg</h2>
<blockquote class="alert alert-note">
      <p class="alert-heading">NOTE</p><p>注意：Arch 提供了位于 <code>/usr/share/X11/xorg.conf.d</code> 的默认配置文件。通常情况下，用户无需进行额外的配置与修改即可正常使用。</p></blockquote><h2 id="others-tricks">
  <a class="anchor inpage" href="#others-tricks">##</a>others tricks</h2>
<h3 id="short-cuts">
  <a class="anchor inpage" href="#short-cuts">###</a>short cuts</h3>
<p>
</p>
]]></content:encoded></item><item><title>Bash Scripts</title><link>https://hiraethecho.github.io/docs/linux/bash-scripts/</link><pubDate>Tue, 31 Dec 2024 00:00:00 +0000</pubDate><author>wyz2016zxc@outlook.com(Hiraeth)</author><guid>https://hiraethecho.github.io/docs/linux/bash-scripts/</guid><description>编写bash scripts的一些技巧</description><content:encoded><![CDATA[<h1 id="bash-scripts">
  <a class="anchor inpage" href="#bash-scripts">#</a>Bash Scripts</h1>
<h2 id="intro">
  <a class="anchor inpage" href="#intro">##</a>intro</h2>
<h3 id="run">
  <a class="anchor inpage" href="#run">###</a>run</h3>
<p>You can run the script in the following ways:</p>
<p><code>./hello_world.sh</code></p>
<p><code>bash hello_world.sh</code>.</p>
<h3 id="she-bang">
  <a class="anchor inpage" href="#she-bang">###</a>she-bang</h3>
<p>First line of shell Scripts usually is the <code>she-bang</code>:</p>
<details open>
    <summary>TEXT</summary><pre
        class="codeblock"
      ><code class="language-" data-lang="">#!/bin/sh</code><button onclick="copyCode(this)" class="copybtn">copy</button></pre></details>

  <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>Means using <code>/bin/sh</code> to run the script.</p>
<p>但是<code>/bin/sh</code>通常是符号链接，在不同机器上实际上是不同的shell，有时会有以外情况。所以建议写成</p>
<details open>
    <summary>TEXT</summary><pre
        class="codeblock"
      ><code class="language-" data-lang="">#!/bin/bash</code><button onclick="copyCode(this)" class="copybtn">copy</button></pre></details>

  <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="注释">
  <a class="anchor inpage" href="#%e6%b3%a8%e9%87%8a">###</a>注释</h3>
<p>以 # 开头的行就是注释，会被解释器忽略。</p>
<p>多行注释可以使用以下格式：</p>
<details open>
    <summary>bash</summary><pre
        class="chroma codeblock"
      ><code class="language-bash" data-lang="bash"
          ><span style="display:flex;"><span>:<span style="color:#e6db74">&lt;&lt;EOF
</span></span></span><span style="display:flex;"><span><span style="color:#e6db74">注释内容...
</span></span></span><span style="display:flex;"><span><span style="color:#e6db74">注释内容...
</span></span></span><span style="display:flex;"><span><span style="color:#e6db74">注释内容...
</span></span></span><span style="display:flex;"><span><span style="color:#e6db74">EOF</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>以上例子中，: 是一个空命令，用于执行后面的 Here 文档， &laquo;&lsquo;EOF&rsquo; 表示开启 Here 文档，COMMENT 是 Here 文档的标识符，在这两个标识符之间的内容都会被视为注释，不会被执行。</p>
<p>EOF 也可以使用其他符号:</p>
<details open>
    <summary>bash</summary><pre
        class="chroma codeblock"
      ><code class="language-bash" data-lang="bash"
          ><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span>: <span style="color:#e6db74">&lt;&lt;&#39;COMMENT&#39;
</span></span></span><span style="display:flex;"><span><span style="color:#e6db74">这是注释的部分。
</span></span></span><span style="display:flex;"><span><span style="color:#e6db74">可以有多行内容。
</span></span></span><span style="display:flex;"><span><span style="color:#e6db74">COMMENT</span>
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span>:&lt;&lt; <span style="color:#e6db74">&#39;
</span></span></span><span style="display:flex;"><span><span style="color:#e6db74">注释内容...
</span></span></span><span style="display:flex;"><span><span style="color:#e6db74">注释内容...
</span></span></span><span style="display:flex;"><span><span style="color:#e6db74">注释内容...
</span></span></span><span style="display:flex;"><span><span style="color:#e6db74">&#39;</span>
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span>:&lt;&lt;!
</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></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="variables">
  <a class="anchor inpage" href="#variables">##</a>variables</h2>
<h3 id="define">
  <a class="anchor inpage" href="#define">###</a>define</h3>
<p>We can define a variable by using the syntax <code>variable_name=value</code>. To get the value of the variable, add <code>$</code> before the variable.</p>
<details open>
    <summary>bash</summary><pre
        class="chroma codeblock"
      ><code class="language-bash" data-lang="bash"
          ><span style="display:flex;"><span><span style="color:#75715e">#!/bin/bash
</span></span></span><span style="display:flex;"><span><span style="color:#75715e"></span><span style="color:#75715e"># A simple variable example</span>
</span></span><span style="display:flex;"><span>greeting<span style="color:#f92672">=</span>Hello
</span></span><span style="display:flex;"><span>name<span style="color:#f92672">=</span>Tux
</span></span><span style="display:flex;"><span>echo $greeting $name</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>
<p>字符串：</p>
<details open>
    <summary>bash</summary><pre
        class="chroma codeblock"
      ><code class="language-bash" data-lang="bash"
          ><span style="display:flex;"><span>my_string<span style="color:#f92672">=</span><span style="color:#960050;background-color:#1e0010">&#39;</span>Hello, World!my_string<span style="color:#f92672">=</span><span style="color:#e6db74">&#34;Hello, World!&#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><details open>
    <summary>TEXT</summary><pre
        class="codeblock"
      ><code class="language-" data-lang="">RUNOOB=&#34;www.runoob.com&#34;
LD_LIBRARY_PATH=&#34;/bin/&#34;
_var=&#34;123&#34;
var2=&#34;abc&#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>bash</summary><pre
        class="chroma codeblock"
      ><code class="language-bash" data-lang="bash"
          ><span style="display:flex;"><span><span style="color:#66d9ef">for</span> file in <span style="color:#ae81ff">\`</span> ls / etc <span style="color:#ae81ff">\`</span>
</span></span><span style="display:flex;"><span><span style="color:#66d9ef">for</span> file in $ <span style="color:#f92672">(</span>ls / etc<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="">my_array=(1 2 3 4 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>只读变量</p>
<details open>
    <summary>bash</summary><pre
        class="chroma codeblock"
      ><code class="language-bash" data-lang="bash"
          ><span style="display:flex;"><span><span style="color:#75715e">#!/bin/bash
</span></span></span><span style="display:flex;"><span><span style="color:#75715e"></span>
</span></span><span style="display:flex;"><span>myUrl<span style="color:#f92672">=</span><span style="color:#e6db74">&#34;https://www.google.com&#34;</span>
</span></span><span style="display:flex;"><span>readonly myUrl
</span></span><span style="display:flex;"><span>myUrl<span style="color:#f92672">=</span><span style="color:#e6db74">&#34;https://www.runoob.com&#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>使用 unset 命令可以删除变量。语法：</p>
<details open>
    <summary>TEXT</summary><pre
        class="codeblock"
      ><code class="language-" data-lang="">unset variable_name</code><button onclick="copyCode(this)" class="copybtn">copy</button></pre></details>

  <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="变量类型">
  <a class="anchor inpage" href="#%e5%8f%98%e9%87%8f%e7%b1%bb%e5%9e%8b">###</a>变量类型</h3>
<p><strong>字符串变量：</strong> 在 Shell中，变量通常被视为字符串。</p>
<p>你可以使用单引号 &rsquo; 或双引号 &quot; 来定义字符串，例如：</p>
<details open>
    <summary>TEXT</summary><pre
        class="codeblock"
      ><code class="language-" data-lang="">my_string=&#39;Hello, World!&#39;
my_string=&#34;Hello, World!&#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>单引号字符串的限制：</p>
<ul>
<li>单引号里的任何字符都会原样输出，单引号字符串中的变量是无效的；</li>
<li>单引号字符串中不能出现单独一个的单引号（对单引号使用转义符后也不行），但可成对出现，作为字符串拼接使用。</li>
</ul>
<p>双引号的优点：</p>
<ul>
<li>双引号里可以有变量</li>
<li>双引号里可以出现转义字符</li>
</ul>
<p>拼接字符串</p>
<details open>
    <summary>bash</summary><pre
        class="chroma codeblock"
      ><code class="language-bash" data-lang="bash"
          ><span style="display:flex;"><span>your<span style="color:#ae81ff">\_</span>name <span style="color:#f92672">=</span> <span style="color:#e6db74">&#34;runoob&#34;</span>
</span></span><span style="display:flex;"><span><span style="color:#ae81ff">\#</span> 使用双引号拼接
</span></span><span style="display:flex;"><span>greeting <span style="color:#f92672">=</span> <span style="color:#e6db74">&#34;hello, &#34;</span> $your<span style="color:#ae81ff">\_</span>name <span style="color:#e6db74">&#34;!&#34;</span>
</span></span><span style="display:flex;"><span>greeting<span style="color:#ae81ff">\_</span><span style="color:#ae81ff">1</span> <span style="color:#f92672">=</span> <span style="color:#e6db74">&#34;hello, </span><span style="color:#e6db74">${</span>your<span style="color:#ae81ff">\_</span>name<span style="color:#e6db74">}</span><span style="color:#e6db74">!&#34;</span>
</span></span><span style="display:flex;"><span>echo $greeting $greeting<span style="color:#ae81ff">\_</span><span style="color:#ae81ff">1</span>
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span><span style="color:#ae81ff">\#</span> 使用单引号拼接
</span></span><span style="display:flex;"><span>greeting<span style="color:#ae81ff">\_</span><span style="color:#ae81ff">2</span> <span style="color:#f92672">=</span> <span style="color:#e6db74">&#39;hello, &#39;</span> $your<span style="color:#ae81ff">\_</span>name <span style="color:#e6db74">&#39;!&#39;</span>
</span></span><span style="display:flex;"><span>greeting<span style="color:#ae81ff">\_</span><span style="color:#ae81ff">3</span> <span style="color:#f92672">=</span> <span style="color:#e6db74">&#39;hello, ${your\_name}!&#39;</span>
</span></span><span style="display:flex;"><span>echo $greeting<span style="color:#ae81ff">\_</span><span style="color:#ae81ff">2</span> $greeting<span style="color:#ae81ff">\_</span><span style="color:#ae81ff">3</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="">hello, runoob ! hello, runoob !
hello, runoob ! hello, ${your_name} !</code><button onclick="copyCode(this)" class="copybtn">copy</button></pre></details>

  <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>bash</summary><pre
        class="chroma codeblock"
      ><code class="language-bash" data-lang="bash"
          ><span style="display:flex;"><span>string <span style="color:#f92672">=</span> <span style="color:#e6db74">&#34;abcd&#34;</span>
</span></span><span style="display:flex;"><span>echo <span style="color:#e6db74">${#</span>string<span style="color:#e6db74">}</span> <span style="color:#ae81ff">\#</span> 输出 <span style="color:#ae81ff">4</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="数组">
  <a class="anchor inpage" href="#%e6%95%b0%e7%bb%84">###</a>数组</h3>
<p>bash支持一维数组（不支持多维数组），并且没有限定数组的大小。</p>
<p>类似于 C 语言，数组元素的下标由 0 开始编号。获取数组中的元素要利用下标，下标可以是整数或算术表达式，其值应大于或等于 0。</p>
<p>在 Shell 中，用括号来表示数组，数组元素用&quot;空格&quot;符号分割开。定义数组的一般形式为：</p>
<details open>
    <summary>TEXT</summary><pre
        class="codeblock"
      ><code class="language-" data-lang="">数组名=(值1 值2 ... 值n)</code><button onclick="copyCode(this)" class="copybtn">copy</button></pre></details>

  <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="">array_name=(value0 value1 value2 value3)</code><button onclick="copyCode(this)" class="copybtn">copy</button></pre></details>

  <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="">array_name=(
value0
value1
value2
value3
)</code><button onclick="copyCode(this)" class="copybtn">copy</button></pre></details>

  <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="">array_name[0]=value0
array_name[1]=value1
array_name[n]=valuen</code><button onclick="copyCode(this)" class="copybtn">copy</button></pre></details>

  <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>
<p>读取数组元素值的一般格式是：</p>
<details open>
    <summary>TEXT</summary><pre
        class="codeblock"
      ><code class="language-" data-lang="">${数组名[下标]}</code><button onclick="copyCode(this)" class="copybtn">copy</button></pre></details>

  <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="">valuen=${array_name[n]}</code><button onclick="copyCode(this)" class="copybtn">copy</button></pre></details>

  <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="">echo ${array_name[@]}</code><button onclick="copyCode(this)" class="copybtn">copy</button></pre></details>

  <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>bash</summary><pre
        class="chroma codeblock"
      ><code class="language-bash" data-lang="bash"
          ><span style="display:flex;"><span><span style="color:#ae81ff">\#</span> 取得数组元素的个数
</span></span><span style="display:flex;"><span>length <span style="color:#f92672">=</span> <span style="color:#e6db74">${#</span>array<span style="color:#ae81ff">\_</span>name<span style="color:#ae81ff">\[</span>@<span style="color:#ae81ff">\]</span><span style="color:#e6db74">}</span>
</span></span><span style="display:flex;"><span><span style="color:#ae81ff">\#</span> 或者
</span></span><span style="display:flex;"><span>length <span style="color:#f92672">=</span> <span style="color:#e6db74">${#</span>array<span style="color:#ae81ff">\_</span>name<span style="color:#ae81ff">\[\*\]</span><span style="color:#e6db74">}</span>
</span></span><span style="display:flex;"><span><span style="color:#ae81ff">\#</span> 取得数组单个元素的长度
</span></span><span style="display:flex;"><span>length <span style="color:#f92672">=</span> <span style="color:#e6db74">${#</span>array<span style="color:#ae81ff">\_</span>name<span style="color:#ae81ff">\[</span>n<span style="color:#ae81ff">\]</span><span style="color:#e6db74">}</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="运算">
  <a class="anchor inpage" href="#%e8%bf%90%e7%ae%97">###</a>运算</h3>
<p>Arithmetic Expressions:</p>
<p>Below are the operators supported by bash for mathematical calculations:</p>
<table>
  <thead>
      <tr>
          <th>Operator</th>
          <th>Usage</th>
      </tr>
  </thead>
  <tbody>
      <tr>
          <td>+</td>
          <td>addition</td>
      </tr>
      <tr>
          <td>-</td>
          <td>subtraction</td>
      </tr>
      <tr>
          <td>*</td>
          <td>multiplication</td>
      </tr>
      <tr>
          <td>/</td>
          <td>division</td>
      </tr>
      <tr>
          <td>**</td>
          <td>exponentiation</td>
      </tr>
      <tr>
          <td>%</td>
          <td>modulus</td>
      </tr>
  </tbody>
</table>
<p>Numeric Comparison logical operators</p>
<p>Comparison is used to check if statements evaluate to <code>true</code> or <code>false</code>. We can use the below shown operators to compare two statements:</p>
<table>
  <thead>
      <tr>
          <th>Operation</th>
          <th>Syntax</th>
          <th>Explanation</th>
      </tr>
  </thead>
  <tbody>
      <tr>
          <td>Equality</td>
          <td>num1 -eq num2</td>
          <td>is num1 equal to num2</td>
      </tr>
      <tr>
          <td>Greater than equal to</td>
          <td>num1 -ge num2</td>
          <td>is num1 greater than equal to num2</td>
      </tr>
      <tr>
          <td>Greater than</td>
          <td>num1 -gt num2</td>
          <td>is num1 greater than num2</td>
      </tr>
      <tr>
          <td>Less than equal to</td>
          <td>num1 -le num2</td>
          <td>is num1 less than equal to num2</td>
      </tr>
      <tr>
          <td>Less than</td>
          <td>num1 -lt num2</td>
          <td>is num1 less than num2</td>
      </tr>
      <tr>
          <td>Not Equal to</td>
          <td>num1 -ne num2</td>
          <td>is num1 not equal to num2</td>
      </tr>
  </tbody>
</table>
<h3 id="参数">
  <a class="anchor inpage" href="#%e5%8f%82%e6%95%b0">###</a>参数</h3>
<table>
  <thead>
      <tr>
          <th>名称</th>
          <th>含义</th>
      </tr>
  </thead>
  <tbody>
      <tr>
          <td>$#</td>
          <td>传给脚本的参数个数</td>
      </tr>
      <tr>
          <td>$0</td>
          <td>脚本本身的名字</td>
      </tr>
      <tr>
          <td>$1</td>
          <td>传递给该shell脚本的第一个参数</td>
      </tr>
      <tr>
          <td>$2</td>
          <td>传递给该shell脚本的第二个参数</td>
      </tr>
      <tr>
          <td>$@</td>
          <td>传给脚本的所有参数的列表</td>
      </tr>
      <tr>
          <td>$*</td>
          <td>以一个单字符串显示所有向脚本传递的参数，与位置变量不同，参数可超过9个</td>
      </tr>
      <tr>
          <td>$$</td>
          <td>脚本运行的当前进程ID号</td>
      </tr>
      <tr>
          <td>$?</td>
          <td>显示最后命令的退出状态，0表示没有错误，其他表示有错误</td>
      </tr>
  </tbody>
</table>
<p>假设执行 <code>./test.sh a b c</code> 这样一个命令，则可以使用下面的参数来获取一些值：</p>
<ul>
<li><code>$0</code><br>
对应 <em>./test.sh</em> 这个值。如果执行的是 <code>./work/test.sh</code> ， 则对应 <em>./work/test.sh</em> 这个值，而不是只返回文件名本身的部分。</li>
<li><code>$1</code><br>
会获取到 a，即 <code>$1</code> 对应传给脚本的第一个参数。</li>
<li><code>$2</code><br>
会获取到 b，即 <code>$2</code> 对应传给脚本的第二个参数。</li>
<li><code>$3</code><br>
会获取到 c，即 <code>$3</code> 对应传给脚本的第三个参数。 <code>$4</code> 、 <code>$5</code> 等参数的含义依此类推。</li>
<li><code>$#</code><br>
会获取到 3，对应传入脚本的参数个数，统计的参数不包括 <code>$0</code> 。</li>
<li><code>$@</code><br>
会获取到 &ldquo;a&rdquo; &ldquo;b&rdquo; &ldquo;c&rdquo;，也就是所有参数的列表，不包括 <code>$0</code> 。</li>
<li><code>$*</code><br>
也会获取到 &ldquo;a&rdquo; &ldquo;b&rdquo; &ldquo;c&rdquo;， 其值和 <code>$@</code> 相同。但 <code>&quot;$*&quot;</code> 和 <code>&quot;$@&quot;</code> 有所不同。<br>
<code>&quot;$*&quot;</code> 把所有参数合并成一个字符串，而 <code>&quot;$@&quot;</code> 会得到一个字符串参数数组。</li>
<li><code>$?</code><br>
可以获取到执行 <code>./test.sh a b c</code> 命令后的返回值。<br>
在执行一个前台命令后，可以立即用 <code>$?</code> 获取到该命令的返回值。<br>
该命令可以是系统自身的命令，可以是 shell 脚本，也可以是自定义的 bash 函数。</li>
</ul>
<p>当执行系统自身的命令时， <code>$?</code> 对应这个命令的返回值。<br>
当执行 shell 脚本时， <code>$?</code> 对应该脚本调用 <code>exit</code> 命令返回的值。如果没有主动调用 <code>exit</code> 命令，默认返回为 0。<br>
当执行自定义的 bash 函数时， <code>$?</code> 对应该函数调用 <code>return</code> 命令返回的值。如果没有主动调用 <code>return</code> 命令，默认返回为 0。</p>
<p>下面举例说明 <code>&quot;$*&quot;</code> 和 <code>&quot;$@&quot;</code> 的差异。假设有一个 <code>testparams.sh</code> 脚本，内容如下：</p>
<details open>
    <summary>bash</summary><pre
        class="chroma codeblock"
      ><code class="language-bash" data-lang="bash"
          ><span style="display:flex;"><span><span style="color:#75715e">#!/bin/bash
</span></span></span><span style="display:flex;"><span><span style="color:#75715e"></span>
</span></span><span style="display:flex;"><span><span style="color:#66d9ef">for</span> arg in <span style="color:#e6db74">&#34;</span>$*<span style="color:#e6db74">&#34;</span>; <span style="color:#66d9ef">do</span>
</span></span><span style="display:flex;"><span>    echo <span style="color:#e6db74">&#34;****:&#34;</span> $arg
</span></span><span style="display:flex;"><span><span style="color:#66d9ef">done</span>
</span></span><span style="display:flex;"><span>echo --------------
</span></span><span style="display:flex;"><span><span style="color:#66d9ef">for</span> arg in <span style="color:#e6db74">&#34;</span>$@<span style="color:#e6db74">&#34;</span>; <span style="color:#66d9ef">do</span>
</span></span><span style="display:flex;"><span>    echo <span style="color:#e6db74">&#34;@@@@:&#34;</span> $arg
</span></span><span style="display:flex;"><span><span style="color:#66d9ef">done</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>&quot;$*&quot;</code> 和 <code>&quot;$@&quot;</code> 扩展后的内容，并打印出来。</p>
<p>执行 <code>./testparams.sh</code> 脚本，结果如下：</p>
<details open>
    <summary>bash</summary><pre
        class="chroma codeblock"
      ><code class="language-bash" data-lang="bash"
          ><span style="display:flex;"><span>$ ./testparams.sh This is a test
</span></span><span style="display:flex;"><span>****: This is a test
</span></span><span style="display:flex;"><span>--------------
</span></span><span style="display:flex;"><span>@@@@: This
</span></span><span style="display:flex;"><span>@@@@: is
</span></span><span style="display:flex;"><span>@@@@: a
</span></span><span style="display:flex;"><span>@@@@: test</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>&quot;$*&quot;</code> 只产生一个字符串，for 循环只遍历一次。<br>
而 <code>&quot;$@&quot;</code> 产生了多个字符串，for 循环遍历多次，是一个字符串参数数组。</p>
<p><strong>注意</strong> ：如果传入的参数多于 9 个，则不能使用 <code>$10</code> 来引用第 10 个参数，而是要用 <code>${10}</code> 来引用。</p>
<p>即，需要用大括号 <code>{}</code> 把大于 9 的数字括起来。<br>
例如， <code>${10}</code> 表示获取第 10 个参数的值，写为 <code>$10</code> 获取不到第 10 个参数的值。<br>
实际上， <code>$10</code> 相当于 <code>${1}0</code> ，也就是先获取 <code>$1</code> 的值，后面再跟上 0。<br>
如果 <code>$1</code> 的值是 &ldquo;first&rdquo;，则 <code>$10</code> 的值是 &ldquo;first0&rdquo;。</p>
<p>在 bash 中，可以使用 <code>$#</code> 来获取传入的命令行或者传入函数的参数个数。<br>
要注意的是， <code>$#</code> 统计的参数个数不包括脚本自身名称或者函数名称。<br>
例如，执行 <code>./a.sh a b</code> ，则 <code>$#</code> 是 2，而不是 3。</p>
<h2 id="pairs">
  <a class="anchor inpage" href="#pairs">##</a>pairs</h2>
<p><code>{}</code>,<code>[]</code>,<code>()</code>,<code>``</code></p>
<h3 id="-花括号">
  <a class="anchor inpage" href="#-%e8%8a%b1%e6%8b%ac%e5%8f%b7">###</a>{} 花括号</h3>
<h4 id="常规用法">
  <a class="anchor inpage" href="#%e5%b8%b8%e8%a7%84%e7%94%a8%e6%b3%95">####</a>常规用法</h4>
<p>大括号拓展。(通配(globbing))将对大括号中的文件名做扩展。在大括号中，不允许有空白，除非这个空白被引用或转义。第一种：对大括号中的以逗号分割的文件列表进行拓展。如 touch {a,b}.txt 结果为a.txt b.txt。第二种：对大括号中以点点（..）分割的顺序文件列表起拓展作用，如：touch {a..d}.txt 结果为a.txt b.txt c.txt d.txt</p>
<details open>
    <summary>TEXT</summary><pre
        class="codeblock"
      ><code class="language-" data-lang=""># ls {ex1,ex2}.sh
ex1.sh  ex2.sh
# ls {ex{1..3},ex4}.sh
ex1.sh  ex2.sh  ex3.sh  ex4.sh
# ls {ex[1-3],ex4}.sh
ex1.sh  ex2.sh  ex3.sh  ex4.sh</code><button onclick="copyCode(this)" class="copybtn">copy</button></pre></details>

  <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运行，即脚本余下部分仍可使用括号内变量。括号内的命令间用分号隔开，最后一个也必须有分号。{}的第一个命令和左括号之间必须要有一个空格。</p>
<h4 id="几种特殊的替换结构">
  <a class="anchor inpage" href="#%e5%87%a0%e7%a7%8d%e7%89%b9%e6%ae%8a%e7%9a%84%e6%9b%bf%e6%8d%a2%e7%bb%93%e6%9e%84">####</a>几种特殊的替换结构</h4>
<details open>
    <summary>TEXT</summary><pre
        class="codeblock"
      ><code class="language-" data-lang="">${var:-string}
${var:&#43;string}
${var:=string}
${var:?string}</code><button onclick="copyCode(this)" class="copybtn">copy</button></pre></details>

  <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>
<p><code>${var:-string}</code>和<code>${var:=string}</code>:若变量var为空，则用在命令行中用string来替换<code>${var:-string}</code>，否则变量var不为空时，则用变量var的值来替换<code>${var:-string}</code>；对于<code>${var:=string}</code>的替换规则和<code>${var:-string}</code>是一样的，所不同之处是<code>${var:=string}</code>若var为空时，用string替换<code>${var:=string}</code>的同时，把string赋给变量var： <code>${var:=string}</code>很常用的一种用法是，判断某个变量是否赋值，没有的话则给它赋上一个默认值。</p>
</li>
<li>
<p><code>${var:+string}</code>的替换规则和上面的相反，即只有当var不是空的时候才替换成string，若var为空时则不替换或者说是替换成变量 var的值，即空值。(因为变量var此时为空，所以这两种说法是等价的)</p>
</li>
<li>
<p><code>${var:?string}</code>替换规则为：若变量var不为空，则用变量var的值来替换<code>${var:?string}</code>；若变量var为空，则把string输出到标准错误中，并从脚本中退出。我们可利用此特性来检查是否设置了变量的值。</p>
</li>
</ol>
<p>在上面这五种替换结构中string不一定是常值的，可用另外一个变量的值或是一种命令的输出。</p>
<details open>
    <summary>TEXT</summary><pre
        class="codeblock"
      ><code class="language-" data-lang="">default_name=&#34;Guest&#34;
unset name  # 确保 name 未定义

# 如果 name 为空，则使用 default_name 的值
echo &#34;Hello, ${name:-$default_name}&#34;  # 输出: Hello, Guest</code><button onclick="copyCode(this)" class="copybtn">copy</button></pre></details>

  <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>四种模式匹配替换结构</strong></p>
<p>模式匹配记忆方法：</p>
<details open>
    <summary>TEXT</summary><pre
        class="codeblock"
      ><code class="language-" data-lang=""># 是去掉左边(在键盘上#在$之左边)
% 是去掉右边(在键盘上%在$之右边)</code><button onclick="copyCode(this)" class="copybtn">copy</button></pre></details>

  <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>#</code>和<code>%</code>中的单一符号是最小匹配，两个相同符号是最大匹配。</p>
<details open>
    <summary>TEXT</summary><pre
        class="codeblock"
      ><code class="language-" data-lang="">${var%pattern}
${var%%pattern
${var#pattern}
${var##pattern}</code><button onclick="copyCode(this)" class="copybtn">copy</button></pre></details>

  <script>
    function copyCode(btn) {
      const code = btn.previousElementSibling.textContent.trim();
      navigator.clipboard.writeText(code).then(() => {
        btn.innerText = "copied";
        setTimeout(() => (btn.innerText = "copy"), 2000);
      });
    }
  </script><ul>
<li>第一种模式：<code>${variable%pattern}</code>，这种模式时，shell在variable中查找，看它是否一给的模式pattern结尾，如果是，就从命令行把variable中的内容去掉右边最短的匹配模式</li>
<li>第二种模式： <code>${variable%%pattern}</code>，这种模式时，shell在variable中查找，看它是否一给的模式pattern结尾，如果是，就从命令行把variable中的内容去掉右边最长的匹配模式</li>
<li>第三种模式：<code>${variable#pattern}</code> 这种模式时，shell在variable中查找，看它是否一给的模式pattern开始，如果是，就从命令行把variable中的内容去掉左边最短的匹配模式</li>
<li>第四种模式： <code>${variable##pattern}</code> 这种模式时，shell在variable中查找，看它是否一给的模式pattern结尾，如果是，就从命令行把variable中的内容去掉右边最长的匹配模式</li>
<li>这四种模式中都不会改变variable的值，其中，只有在pattern中使用了*匹配符号时，%和%%，#和##才有区别。结构中的pattern支持通配符，*表示零个或多个任意字符，?表示仅与一个任意字符匹配，\[...\]表示匹配中括号里面的字符，\[!...\]表示不匹配中括号里面的字符。</li>
</ul>
<details open>
    <summary>TEXT</summary><pre
        class="codeblock"
      ><code class="language-" data-lang=""># var=testcase
# echo $var
testcase
# echo ${var%s*e}
testca
# echo $var
testcase
# echo ${var%%s*e}
te
# echo ${var#?e}
stcase
# echo ${var##?e}
stcase
# echo ${var##*e}

# echo ${var##*s}
e
# echo ${var##test}
case</code><button onclick="copyCode(this)" class="copybtn">copy</button></pre></details>

  <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="字符串提取和替换">
  <a class="anchor inpage" href="#%e5%ad%97%e7%ac%a6%e4%b8%b2%e6%8f%90%e5%8f%96%e5%92%8c%e6%9b%bf%e6%8d%a2">####</a>字符串提取和替换</h4>
<details open>
    <summary>TEXT</summary><pre
        class="codeblock"
      ><code class="language-" data-lang="">${var:num}
${var:num1:num2}
${var/pattern/pattern}
${var//pattern/pattern}</code><button onclick="copyCode(this)" class="copybtn">copy</button></pre></details>

  <script>
    function copyCode(btn) {
      const code = btn.previousElementSibling.textContent.trim();
      navigator.clipboard.writeText(code).then(() => {
        btn.innerText = "copied";
        setTimeout(() => (btn.innerText = "copy"), 2000);
      });
    }
  </script><ul>
<li>第一种模式：<code>${var:num}</code>，这种模式时，shell在var中提取第num个字符到末尾的所有字符。若num为正数，从左边0处开始；若num为负数，从右边开始提取字串，但必须使用在冒号后面加空格或一个数字或整个num加上括号，如<code>${var: -2}</code>、<code>${var:1-3}</code>或<code>${var:(-2)}</code>。</li>
<li>第二种模式：<code>${var:num1:num2}</code>，num1是位置，num2是长度。表示从$var字符串的第$num1个位置开始提取长度为$num2的子串。不能为负数。</li>
<li>第三种模式：<code>${var/pattern/pattern}</code>表示将var字符串的第一个匹配的pattern替换为另一个pattern。</li>
<li>第四种模式：<code>${var//pattern/pattern}</code>表示将var字符串中的所有能匹配的pattern替换为另一个pattern。</li>
</ul>
<details open>
    <summary>TEXT</summary><pre
        class="codeblock"
      ><code class="language-" data-lang="">[root@centos ~]# var=/home/centos
[root@centos ~]# echo $var
/home/centos
[root@centos ~]# echo ${var:5}
/centos
[root@centos ~]# echo ${var: -6}
centos
[root@centos ~]# echo ${var:(-6)}
centos
[root@centos ~]# echo ${var:1:4}
home
[root@centos ~]# echo ${var/o/h}
/hhme/centos
[root@centos ~]# echo ${var//o/h}
/hhme/cenths</code><button onclick="copyCode(this)" class="copybtn">copy</button></pre></details>

  <script>
    function copyCode(btn) {
      const code = btn.previousElementSibling.textContent.trim();
      navigator.clipboard.writeText(code).then(() => {
        btn.innerText = "copied";
        setTimeout(() => (btn.innerText = "copy"), 2000);
      });
    }
  </script><ul>
<li>
<p>${a} 变量a的值, 在不引起歧义的情况下可以省略大括号。</p>
</li>
<li>
<p>$(cmd) 命令替换，和`cmd`效果相同，结果为shell命令cmd的输，过某些Shell版本不支持$()形式的命令替换, 如tcsh。</p>
</li>
<li>
<p>$((expression)) 和`exprexpression`效果相同, 计算数学表达式exp的数值, 其中exp只要符合C语言的运算规则即可, 甚至三目运算符和逻辑表达式都可以计算。</p>
</li>
<li>
<p>单小括号，(cmd1;cmd2;cmd3) 新开一个子shell顺序执行命令cmd1,cmd2,cmd3, 各命令之间用分号隔开, 最后一个命令后可以没有分号。</p>
</li>
<li>
<p>单大括号，{ cmd1;cmd2;cmd3;} 在当前shell顺序执行命令cmd1,cmd2,cmd3, 各命令之间用分号隔开, 最后一个命令后必须有分号, 第一条命令和左括号之间必须用空格隔开。
对 {} 和 () 而言, 括号中的重定向符只影响该条命令， 而括号外的重定向符影响到括号中的所有命令。</p>
</li>
</ul>
<h3 id="heading">
  <a class="anchor inpage" href="#heading">###</a><code>[]</code></h3>
<details open>
    <summary>bash</summary><pre
        class="chroma codeblock"
      ><code class="language-bash" data-lang="bash"
          ><span style="display:flex;"><span>type <span style="color:#f92672">[</span>
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span><span style="color:#f92672">[</span> is a shell builtin</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>This means that &lsquo;[&rsquo; is actually a program, just like ls and other programs, so it must be surrounded by spaces.</p>
<ul>
<li>bash 的内部命令，[和test是等同的。如果我们不用绝对路径指明，通常我们用的都是bash自带的命令。if/test结构中的左中括号是调用test的命令标识，右中括号是关闭条件判断的。这个命令把它的参数作为比较表达式或者作为文件测试，并且根据比较的结果来返回一个退出状态码。if/test结构中并不是必须右中括号，但是新版的Bash中要求必须这样。</li>
<li>Test和[]中可用的比较运算符只有==和!=，两者都是用于字符串比较的，不可用于整数比较，整数比较只能使用-eq，-gt这种形式。无论是字符串比较还是整数比较都不支持大于号小于号。如果实在想用，对于字符串比较可以使用转义形式，如果比较&quot;ab&quot;和&quot;bc&quot;：\[ ab \\< bc \]，结果为真，也就是返回状态为0。\[ \]中的逻辑与和逻辑或使用-a 和-o 表示。</li>
<li>字符范围。用作正则表达式的一部分，描述一个匹配的字符范围。作为test用途的中括号内不能使用正则。</li>
<li>在一个array 结构的上下文中，中括号用来引用数组中每个元素的编号。</li>
</ul>
<h3 id="heading-1">
  <a class="anchor inpage" href="#heading-1">###</a><code>[[]]</code></h3>
<ul>
<li>\[\[是 bash 程序语言的关键字。并不是一个命令，\[\[ \]] 结构比\[ \]结构更加通用。在\[\[和\]]之间所有的字符都不会发生文件名扩展或者单词分割，但是会发生参数扩展和命令替换。</li>
<li>支持字符串的模式匹配，使用=~操作符时甚至支持shell的正则表达式。字符串比较时可以把右边的作为一个模式，而不仅仅是一个字符串，比如\[\[ hello == hell? \]]，结果为真。\[\[ \]] 中匹配字符串或通配符，不需要引号。</li>
<li>使用\[\[... \]]条件判断结构，而不是\[... \]，能够防止脚本中的许多逻辑错误。比如，&amp;&amp;、||、&lt;和&gt; 操作符能够正常存在于\[\[ \]]条件判断结构中，但是如果出现在\[ \]结构中的话，会报错。比如可以直接使用if \[\[ $a!= 1 && $a!= 2 \]], 如果不适用双括号, 则为if \[ $a -ne 1\] &amp;&amp; \[ $a!= 2 \]或者if \[ $a -ne 1 -a $a!= 2 \]。</li>
<li>bash把双中括号中的表达式看作一个单独的元素，并返回一个退出状态码。</li>
</ul>
<details open>
    <summary>bash</summary><pre
        class="chroma codeblock"
      ><code class="language-bash" data-lang="bash"
          ><span style="display:flex;"><span><span style="color:#66d9ef">if</span> <span style="color:#f92672">(</span>$i&lt;5<span style="color:#f92672">)</span>
</span></span><span style="display:flex;"><span><span style="color:#66d9ef">if</span> <span style="color:#f92672">[</span> $i -lt <span style="color:#ae81ff">5</span> <span style="color:#f92672">]</span>
</span></span><span style="display:flex;"><span><span style="color:#66d9ef">if</span> <span style="color:#f92672">[</span> $a -ne <span style="color:#ae81ff">1</span> -a $a !<span style="color:#f92672">=</span> <span style="color:#ae81ff">2</span> <span style="color:#f92672">]</span>
</span></span><span style="display:flex;"><span><span style="color:#66d9ef">if</span> <span style="color:#f92672">[</span> $a -ne 1<span style="color:#f92672">]</span> <span style="color:#f92672">&amp;&amp;</span> <span style="color:#f92672">[</span> $a !<span style="color:#f92672">=</span> <span style="color:#ae81ff">2</span> <span style="color:#f92672">]</span>
</span></span><span style="display:flex;"><span><span style="color:#66d9ef">if</span> <span style="color:#f92672">[[</span> $a !<span style="color:#f92672">=</span> <span style="color:#ae81ff">1</span> <span style="color:#f92672">&amp;&amp;</span> $a !<span style="color:#f92672">=</span> <span style="color:#ae81ff">2</span> <span style="color:#f92672">]]</span>
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span><span style="color:#66d9ef">for</span> i in <span style="color:#66d9ef">$(</span>seq <span style="color:#ae81ff">0</span> 4<span style="color:#66d9ef">)</span>;<span style="color:#66d9ef">do</span> echo $i;<span style="color:#66d9ef">done</span>
</span></span><span style="display:flex;"><span><span style="color:#66d9ef">for</span> i in <span style="color:#ae81ff">\`</span>seq <span style="color:#ae81ff">0</span> 4<span style="color:#ae81ff">\`</span>;<span style="color:#66d9ef">do</span> echo $i;<span style="color:#66d9ef">done</span>
</span></span><span style="display:flex;"><span><span style="color:#66d9ef">for</span> <span style="color:#f92672">((</span>i<span style="color:#f92672">=</span>0;i&lt;5;i++<span style="color:#f92672">))</span>;<span style="color:#66d9ef">do</span> echo $i;<span style="color:#66d9ef">done</span>
</span></span><span style="display:flex;"><span><span style="color:#66d9ef">for</span> i in <span style="color:#f92672">{</span>0..4<span style="color:#f92672">}</span>;<span style="color:#66d9ef">do</span> echo $i;<span style="color:#66d9ef">done</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="-和-">
  <a class="anchor inpage" href="#-%e5%92%8c-">###</a><code>[]</code> 和 <code>[[]]</code></h3>
<p>在 <strong>Bash</strong> 脚本中，<code>[ ]</code>（<code>test</code> 命令）和 <code>[[ ]]</code>（关键字）都用于条件判断，但它们在功能、性能和安全性上有显著区别。以下是详细对比：</p>
<h4 id="基本定义">
  <a class="anchor inpage" href="#%e5%9f%ba%e6%9c%ac%e5%ae%9a%e4%b9%89">####</a>基本定义</h4>
<table>
  <thead>
      <tr>
          <th>语法</th>
          <th>类型</th>
          <th>说明</th>
      </tr>
  </thead>
  <tbody>
      <tr>
          <td><code>[ ]</code></td>
          <td><strong>内置命令</strong></td>
          <td>等价于 <code>test</code> 命令，需严格遵循参数规则（如空格和引号）。</td>
      </tr>
      <tr>
          <td><code>[[ ]]</code></td>
          <td><strong>Shell 关键字</strong></td>
          <td>Bash/ksh/zsh 的扩展语法，更灵活，支持额外功能（如模式匹配、逻辑组合）。</td>
      </tr>
  </tbody>
</table>
<h4 id="核心区别">
  <a class="anchor inpage" href="#%e6%a0%b8%e5%bf%83%e5%8c%ba%e5%88%ab">####</a>核心区别</h4>
<p><strong>(1) 字符串比较</strong></p>
<ul>
<li>
<p><strong><code>[ ]</code></strong>：</p>
<ul>
<li>使用 <code>=</code> 和 <code>!=</code> 时，<strong>必须加引号</strong>，否则可能因空格或特殊字符报错。</li>
<li>示例：
<details open>
    <summary>bash</summary><pre
        class="chroma codeblock"
      ><code class="language-bash" data-lang="bash"
          ><span style="display:flex;"><span><span style="color:#f92672">[</span> <span style="color:#e6db74">&#34;</span>$var<span style="color:#e6db74">&#34;</span> <span style="color:#f92672">=</span> <span style="color:#e6db74">&#34;hello&#34;</span> <span style="color:#f92672">]</span>  <span style="color:#75715e"># 正确</span>
</span></span><span style="display:flex;"><span><span style="color:#f92672">[</span> $var <span style="color:#f92672">=</span> hello <span style="color:#f92672">]</span>      <span style="color:#75715e"># 若 $var 含空格，会报错</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>
</li>
<li>
<p><strong><code>[[ ]]</code></strong>：</p>
<ul>
<li>自动处理变量中的空格，无需引号（但仍建议加引号以防未定义变量）。</li>
<li>支持 <code>==</code> 和 <code>!=</code> 的<strong>通配符匹配</strong>（模式匹配）。</li>
<li>示例：
<details open>
    <summary>bash</summary><pre
        class="chroma codeblock"
      ><code class="language-bash" data-lang="bash"
          ><span style="display:flex;"><span><span style="color:#f92672">[[</span> $var <span style="color:#f92672">==</span> <span style="color:#e6db74">&#34;hello&#34;</span> <span style="color:#f92672">]]</span>    <span style="color:#75715e"># 正确，即使 $var 含空格</span>
</span></span><span style="display:flex;"><span><span style="color:#f92672">[[</span> $var <span style="color:#f92672">==</span> h* <span style="color:#f92672">]]</span>         <span style="color:#75715e"># 支持通配符匹配（如 &#34;hello&#34; 或 &#34;hi&#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></li>
</ul>
</li>
</ul>
<p><strong>(2) 数值比较</strong></p>
<ul>
<li>
<p><strong><code>[ ]</code></strong>：</p>
<ul>
<li>必须用 <code>-eq</code>、<code>-lt</code> 等运算符：
<details open>
    <summary>bash</summary><pre
        class="chroma codeblock"
      ><code class="language-bash" data-lang="bash"
          ><span style="display:flex;"><span><span style="color:#f92672">[</span> <span style="color:#e6db74">&#34;</span>$num<span style="color:#e6db74">&#34;</span> -lt <span style="color:#ae81ff">5</span> <span style="color:#f92672">]</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></li>
</ul>
</li>
<li>
<p><strong><code>[[ ]]</code></strong>：</p>
<ul>
<li>仍建议用 <code>-eq</code>、<code>-lt</code>，但支持 <code>&gt;</code> 和 <code>&lt;</code>（需转义或双括号）：
<details open>
    <summary>bash</summary><pre
        class="chroma codeblock"
      ><code class="language-bash" data-lang="bash"
          ><span style="display:flex;"><span><span style="color:#f92672">[[</span> $num -lt <span style="color:#ae81ff">5</span> <span style="color:#f92672">]]</span>    <span style="color:#75715e"># 标准写法</span>
</span></span><span style="display:flex;"><span><span style="color:#f92672">[[</span> $num &lt; <span style="color:#ae81ff">10</span> <span style="color:#f92672">]]</span>     <span style="color:#75715e"># 字符串比较（字典序）！</span>
</span></span><span style="display:flex;"><span><span style="color:#f92672">((</span> num &lt; <span style="color:#ae81ff">10</span> <span style="color:#f92672">))</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></li>
</ul>
</li>
</ul>
<p><strong>(3) 逻辑运算符</strong></p>
<ul>
<li>
<p><strong><code>[ ]</code></strong>：</p>
<ul>
<li>用 <code>-a</code>（AND）、<code>-o</code>（OR），需严格分隔：
<details open>
    <summary>bash</summary><pre
        class="chroma codeblock"
      ><code class="language-bash" data-lang="bash"
          ><span style="display:flex;"><span><span style="color:#f92672">[</span> <span style="color:#e6db74">&#34;</span>$a<span style="color:#e6db74">&#34;</span> -gt <span style="color:#ae81ff">1</span> -a <span style="color:#e6db74">&#34;</span>$a<span style="color:#e6db74">&#34;</span> -lt <span style="color:#ae81ff">10</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></li>
</ul>
</li>
<li>
<p><strong><code>[[ ]]</code></strong>：</p>
<ul>
<li>用 <code>&amp;&amp;</code> 和 <code>||</code>，更直观：
<details open>
    <summary>bash</summary><pre
        class="chroma codeblock"
      ><code class="language-bash" data-lang="bash"
          ><span style="display:flex;"><span><span style="color:#f92672">[[</span> $a -gt <span style="color:#ae81ff">1</span> <span style="color:#f92672">&amp;&amp;</span> $a -lt <span style="color:#ae81ff">10</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></li>
</ul>
</li>
</ul>
<p><strong>(4) 文件测试</strong></p>
<ul>
<li><strong><code>[ ]</code></strong> 和 <code>[[ ]]</code> 均支持，但 <code>[[ ]]</code> 更安全（如未定义变量不会报错）：
<details open>
    <summary>bash</summary><pre
        class="chroma codeblock"
      ><code class="language-bash" data-lang="bash"
          ><span style="display:flex;"><span><span style="color:#f92672">[</span> -f <span style="color:#e6db74">&#34;</span>$file<span style="color:#e6db74">&#34;</span> <span style="color:#f92672">]</span>      <span style="color:#75715e"># 检查文件是否存在</span>
</span></span><span style="display:flex;"><span><span style="color:#f92672">[[</span> -f $file <span style="color:#f92672">]]</span>      <span style="color:#75715e"># 更健壮（即使 $file 未定义也不会语法错误）</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><strong>(5) 正则匹配（仅 <code>[[ ]]</code>）</strong></p>
<details open>
    <summary>bash</summary><pre
        class="chroma codeblock"
      ><code class="language-bash" data-lang="bash"
          ><span style="display:flex;"><span><span style="color:#f92672">[[</span> <span style="color:#e6db74">&#34;hello&#34;</span> <span style="color:#f92672">=</span>~ ^h <span style="color:#f92672">]]</span>   <span style="color:#75715e"># 正则匹配（返回 true）</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><h4 id="性能与安全性">
  <a class="anchor inpage" href="#%e6%80%a7%e8%83%bd%e4%b8%8e%e5%ae%89%e5%85%a8%e6%80%a7">####</a>性能与安全性</h4>
<table>
  <thead>
      <tr>
          <th>特性</th>
          <th><code>[ ]</code></th>
          <th><code>[[ ]]</code></th>
      </tr>
  </thead>
  <tbody>
      <tr>
          <td><strong>执行速度</strong></td>
          <td>较慢（外部命令或内置命令）</td>
          <td>更快（Bash 关键字）</td>
      </tr>
      <tr>
          <td><strong>安全性</strong></td>
          <td>变量未加引号易报错</td>
          <td>自动处理空格，更健壮</td>
      </tr>
      <tr>
          <td><strong>兼容性</strong></td>
          <td>所有 Shell（sh、dash 等）</td>
          <td>仅 Bash/ksh/zsh</td>
      </tr>
  </tbody>
</table>
<h4 id="何时使用">
  <a class="anchor inpage" href="#%e4%bd%95%e6%97%b6%e4%bd%bf%e7%94%a8">####</a>何时使用？</h4>
<ul>
<li><strong>用 <code>[[ ]]</code></strong>：
<ul>
<li>需要模式匹配、正则表达式、逻辑组合时。</li>
<li>脚本已明确使用 Bash（<code>#!/bin/bash</code>）。</li>
</ul>
</li>
<li><strong>用 <code>[ ]</code></strong>：
<ul>
<li>需兼容 POSIX Shell（如 <code>/bin/sh</code>）。</li>
<li>简单的文件或字符串测试（但务必加引号）。</li>
</ul>
</li>
</ul>
<h4 id="经典示例">
  <a class="anchor inpage" href="#%e7%bb%8f%e5%85%b8%e7%a4%ba%e4%be%8b">####</a>经典示例</h4>
<p><strong>(1) 字符串比较</strong></p>
<details open>
    <summary>bash</summary><pre
        class="chroma codeblock"
      ><code class="language-bash" data-lang="bash"
          ><span style="display:flex;"><span><span style="color:#75715e"># [ ] 必须加引号</span>
</span></span><span style="display:flex;"><span><span style="color:#f92672">[</span> <span style="color:#e6db74">&#34;</span>$name<span style="color:#e6db74">&#34;</span> <span style="color:#f92672">=</span> <span style="color:#e6db74">&#34;Alice&#34;</span> <span style="color:#f92672">]</span> <span style="color:#f92672">&amp;&amp;</span> echo <span style="color:#e6db74">&#34;Hello Alice&#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><span style="color:#f92672">[[</span> $name <span style="color:#f92672">==</span> A* <span style="color:#f92672">]]</span> <span style="color:#f92672">&amp;&amp;</span> echo <span style="color:#e6db74">&#34;Name starts with A&#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><strong>(2) 文件检查</strong></p>
<details open>
    <summary>bash</summary><pre
        class="chroma codeblock"
      ><code class="language-bash" data-lang="bash"
          ><span style="display:flex;"><span><span style="color:#75715e"># [ ] 和 [[ ]] 均可，但后者更安全</span>
</span></span><span style="display:flex;"><span><span style="color:#f92672">[</span> -f <span style="color:#e6db74">&#34;/path/</span>$file<span style="color:#e6db74">&#34;</span> <span style="color:#f92672">]</span> <span style="color:#f92672">&amp;&amp;</span> echo <span style="color:#e6db74">&#34;File exists&#34;</span>
</span></span><span style="display:flex;"><span><span style="color:#f92672">[[</span> -f /path/$file <span style="color:#f92672">]]</span> <span style="color:#f92672">&amp;&amp;</span> echo <span style="color:#e6db74">&#34;File exists&#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><strong>(3) 逻辑组合</strong></p>
<details open>
    <summary>bash</summary><pre
        class="chroma codeblock"
      ><code class="language-bash" data-lang="bash"
          ><span style="display:flex;"><span><span style="color:#75715e"># [ ] 用 -a/-o</span>
</span></span><span style="display:flex;"><span><span style="color:#f92672">[</span> <span style="color:#e6db74">&#34;</span>$age<span style="color:#e6db74">&#34;</span> -gt <span style="color:#ae81ff">18</span> -a <span style="color:#e6db74">&#34;</span>$age<span style="color:#e6db74">&#34;</span> -lt <span style="color:#ae81ff">60</span> <span style="color:#f92672">]</span> <span style="color:#f92672">&amp;&amp;</span> echo <span style="color:#e6db74">&#34;Valid age&#34;</span>
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span><span style="color:#75715e"># [[ ]] 用 &amp;&amp;/||</span>
</span></span><span style="display:flex;"><span><span style="color:#f92672">[[</span> $age -gt <span style="color:#ae81ff">18</span> <span style="color:#f92672">&amp;&amp;</span> $age -lt <span style="color:#ae81ff">60</span> <span style="color:#f92672">]]</span> <span style="color:#f92672">&amp;&amp;</span> echo <span style="color:#e6db74">&#34;Valid age&#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><h4 id="总结">
  <a class="anchor inpage" href="#%e6%80%bb%e7%bb%93">####</a>总结</h4>
<table>
  <thead>
      <tr>
          <th><strong>需求</strong></th>
          <th><strong><code>[ ]</code></strong></th>
          <th><strong><code>[[ ]]</code></strong></th>
      </tr>
  </thead>
  <tbody>
      <tr>
          <td>字符串比较</td>
          <td>需严格加引号</td>
          <td>自动处理空格，支持通配符</td>
      </tr>
      <tr>
          <td>数值比较</td>
          <td>用 <code>-eq</code>、<code>-lt</code></td>
          <td>同 <code>[ ]</code>，但可用 <code>(( ))</code> 替代</td>
      </tr>
      <tr>
          <td>逻辑运算符</td>
          <td><code>-a</code>、<code>-o</code></td>
          <td><code>&amp;&amp;</code>、<code>||</code></td>
      </tr>
      <tr>
          <td>正则匹配</td>
          <td>❌</td>
          <td>✅（<code>=~</code>）</td>
      </tr>
      <tr>
          <td>性能</td>
          <td>较慢</td>
          <td>更快</td>
      </tr>
  </tbody>
</table>
<ul>
<li><strong>优先用 <code>[[ ]]</code></strong>（Bash 脚本中更安全、灵活）。</li>
<li><strong>只有需要兼容 POSIX 时用 <code>[ ]</code></strong>（如 <code>/bin/sh</code> 脚本）。</li>
</ul>
<h3 id="heading-2">
  <a class="anchor inpage" href="#heading-2">###</a><code>()</code></h3>
<ul>
<li><strong>命令组</strong> 。括号中的命令将会新开一个子shell顺序执行，所以括号中的变量不能够被脚本余下的部分使用。括号中多个命令之间用分号隔开，最后一个命令可以没有分号，各命令和括号之间不必有空格。</li>
<li><strong>命令替换</strong> 。等同于<code>cmd</code>，shell扫描一遍命令行，发现了<code>$(cmd)</code>结构，便将<code>$(cmd)</code>中的<code>cmd</code>执行一次，得到其标准输出，再将此输出放到原来命令。有些shell不支持，如tcsh。</li>
<li><strong>用于初始化数组</strong> 。如：<code>array=(a b c d)</code></li>
</ul>
<h3 id="heading-3">
  <a class="anchor inpage" href="#heading-3">###</a><code>(())</code></h3>
<ul>
<li>整数扩展。这种扩展计算是整数型的计算，不支持浮点型。((exp))结构扩展并计算一个算术表达式的值，如果表达式的结果为0，那么返回的退出状态码为1，或者 是&quot;假&quot;，而一个非零值的表达式所返回的退出状态码将为0，或者是&quot;true&quot;。若是逻辑判断，表达式exp为真则为1,假则为0。</li>
<li>只要括号中的运算符、表达式符合C语言运算规则，都可用在$((exp))中，甚至是三目运算符。作不同进位(如二进制、八进制、十六进制)运算时，输出结果全都自动转化成了十进制。如：echo $((16#5f)) 结果为95 (16进位转十进制)</li>
<li>单纯用 (( )) 也可重定义变量值，比如 a=5; ((a++)) 可将 $a 重定义为6</li>
<li>常用于算术运算比较，双括号中的变量可以不使用<code>$</code>符号前缀。括号内支持多个表达式用逗号分开。 只要括号中的表达式符合C语言运算规则,比如可以直接使用<code>for((i=0;i&lt;5;i++))</code>, 如果不使用双括号, 则为<code>for i in $(seq 0 4)</code>或者<code>for i in {0..4}</code>。再如可以直接使用<code>if (($i&lt;5))</code>, 如果不使用双括号, 则为<code>if \[ $i -lt 5 \]</code>。</li>
</ul>
<details open>
    <summary>bash</summary><pre
        class="chroma codeblock"
      ><code class="language-bash" data-lang="bash"
          ><span style="display:flex;"><span>var<span style="color:#f92672">=</span><span style="color:#66d9ef">$((</span>expression<span style="color:#66d9ef">))</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="-back-ticks">
  <a class="anchor inpage" href="#-back-ticks">###</a><code>``</code> back ticks</h3>
<p>var= commands</p>
<p><strong>Example</strong>: Suppose we want to get the output of a list of mountpoints with <code>tmpfs</code> in their name. We can craft a statement like this: <code>df -h | grep tmpfs</code>.</p>
<p>To include it in the bash script, we can enclose it in back ticks.</p>
<details open>
    <summary>bash</summary><pre
        class="chroma codeblock"
      ><code class="language-bash" data-lang="bash"
          ><span style="display:flex;"><span><span style="color:#75715e">#!/bin/bash
</span></span></span><span style="display:flex;"><span><span style="color:#75715e"></span>
</span></span><span style="display:flex;"><span>var<span style="color:#f92672">=</span><span style="color:#ae81ff">\`</span>df -h | grep tmpfs<span style="color:#ae81ff">\`</span>
</span></span><span style="display:flex;"><span>echo $var</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="heading-4">
  <a class="anchor inpage" href="#heading-4">###</a><code>&quot;&quot;</code></h3>
<details open>
    <summary>bash</summary><pre
        class="chroma codeblock"
      ><code class="language-bash" data-lang="bash"
          ><span style="display:flex;"><span>repo<span style="color:#f92672">=</span>~<span style="color:#e6db74">&#34;/projects/repo1&#34;</span>  <span style="color:#75715e"># 或直接写 ~/projects/repo1（不加引号）</span>
</span></span><span style="display:flex;"><span>cd <span style="color:#e6db74">&#34;</span>$repo<span style="color:#e6db74">&#34;</span>               <span style="color:#75715e"># 此时 $repo 已是展开后的绝对路径</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>bash</summary><pre
        class="chroma codeblock"
      ><code class="language-bash" data-lang="bash"
          ><span style="display:flex;"><span><span style="color:#75715e">#!/bin/bash
</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><span style="display:flex;"><span>HOME_DIR<span style="color:#f92672">=</span><span style="color:#66d9ef">$(</span>eval echo <span style="color:#e6db74">&#34;~&#34;</span><span style="color:#66d9ef">)</span>  <span style="color:#75715e"># 或直接写 HOME_DIR=&#34;$HOME&#34;</span>
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span>repos<span style="color:#f92672">=(</span>
</span></span><span style="display:flex;"><span>    <span style="color:#e6db74">&#34;</span>$HOME_DIR<span style="color:#e6db74">/projects/repo1&#34;</span>
</span></span><span style="display:flex;"><span>    <span style="color:#e6db74">&#34;</span>$HOME_DIR<span style="color:#e6db74">/work/repo2&#34;</span>
</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><h3 id="-和--1">
  <a class="anchor inpage" href="#-%e5%92%8c--1">###</a><code>&quot;&quot;</code> 和 <code>''</code></h3>
<p>在 <strong>Bash</strong> 脚本中，双引号 <code>&quot;&quot;</code> 和单引号 <code>''</code> 都用于定义字符串，但它们在 <strong>变量扩展</strong>、<strong>命令替换</strong> 和 <strong>特殊字符处理</strong> 上有本质区别。以下是详细对比：</p>
<table>
  <thead>
      <tr>
          <th>特性</th>
          <th>双引号 <code>&quot;&quot;</code></th>
          <th>单引号 <code>''</code></th>
      </tr>
  </thead>
  <tbody>
      <tr>
          <td><strong>变量扩展</strong></td>
          <td>✅（如 <code>&quot;$var&quot;</code> 会展开）</td>
          <td>❌（如 <code>'$var'</code> 原样输出）</td>
      </tr>
      <tr>
          <td><strong>命令替换</strong></td>
          <td>✅（如 <code>&quot;$(date)&quot;</code> 会执行）</td>
          <td>❌（如 <code>'$(date)'</code> 原样输出）</td>
      </tr>
      <tr>
          <td><strong>转义字符</strong></td>
          <td>仅 <code>\</code>, <code>$</code>, <code>`</code>, <code>&quot;</code> 生效</td>
          <td>所有字符均按字面处理（无转义）</td>
      </tr>
      <tr>
          <td><strong>用途</strong></td>
          <td>需保留变量或命令结果时使用</td>
          <td>需完全按字面输出时使用</td>
      </tr>
  </tbody>
</table>
<details open>
    <summary>bash</summary><pre
        class="chroma codeblock"
      ><code class="language-bash" data-lang="bash"
          ><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>
</span></span><span style="display:flex;"><span>echo <span style="color:#e6db74">&#34;Hello, </span>$name<span style="color:#e6db74">&#34;</span>   <span style="color:#75715e"># 输出: Hello, Alice</span>
</span></span><span style="display:flex;"><span>echo <span style="color:#e6db74">&#39;Hello, $name&#39;</span>   <span style="color:#75715e"># 输出: Hello, $name</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>bash</summary><pre
        class="chroma codeblock"
      ><code class="language-bash" data-lang="bash"
          ><span style="display:flex;"><span>echo <span style="color:#e6db74">&#34;Today is </span><span style="color:#66d9ef">$(</span>date<span style="color:#66d9ef">)</span><span style="color:#e6db74">&#34;</span>  <span style="color:#75715e"># 输出: Today is Mon Jul 1 12:00:00 UTC 2024</span>
</span></span><span style="display:flex;"><span>echo <span style="color:#e6db74">&#39;Today is $(date)&#39;</span>  <span style="color:#75715e"># 输出: Today is $(date)</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>bash</summary><pre
        class="chroma codeblock"
      ><code class="language-bash" data-lang="bash"
          ><span style="display:flex;"><span>echo <span style="color:#e6db74">&#34;Path is \$HOME&#34;</span>    <span style="color:#75715e"># 输出: Path is $HOME（\$ 被转义）</span>
</span></span><span style="display:flex;"><span>echo <span style="color:#e6db74">&#39;Path is \$HOME&#39;</span>    <span style="color:#75715e"># 输出: Path is \$HOME（完全字面）</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>bash</summary><pre
        class="chroma codeblock"
      ><code class="language-bash" data-lang="bash"
          ><span style="display:flex;"><span>echo <span style="color:#e6db74">&#34;She said: &#39;Hello!&#39;&#34;</span>   <span style="color:#75715e"># 输出: She said: &#39;Hello!&#39;</span>
</span></span><span style="display:flex;"><span>echo <span style="color:#e6db74">&#39;He said: &#34;Hi!&#34;&#39;</span>       <span style="color:#75715e"># 输出: He said: &#34;Hi!&#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><ul>
<li>
<p>需要<strong>变量或命令替换</strong>时：</p>
<details open>
    <summary>bash</summary><pre
        class="chroma codeblock"
      ><code class="language-bash" data-lang="bash"
          ><span style="display:flex;"><span>echo <span style="color:#e6db74">&#34;Current user: </span>$USER<span style="color:#e6db74">, time: </span><span style="color:#66d9ef">$(</span>date<span style="color:#66d9ef">)</span><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></li>
<li>
<p>字符串中包含<strong>空格或特殊字符</strong>（需部分转义）：</p>
<details open>
    <summary>bash</summary><pre
        class="chroma codeblock"
      ><code class="language-bash" data-lang="bash"
          ><span style="display:flex;"><span>echo <span style="color:#e6db74">&#34;Use \&#34;quotes\&#34; inside.&#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></li>
<li>
<p>需<strong>完全按字面输出</strong>（如正则表达式、SQL语句）：</p>
<details open>
    <summary>bash</summary><pre
        class="chroma codeblock"
      ><code class="language-bash" data-lang="bash"
          ><span style="display:flex;"><span>grep -E <span style="color:#e6db74">&#39;^[A-Z]&#39;</span> file.txt  <span style="color:#75715e"># 正则表达式</span>
</span></span><span style="display:flex;"><span>sql<span style="color:#f92672">=</span><span style="color:#e6db74">&#39;SELECT * FROM users;&#39;</span> <span style="color:#75715e"># SQL语句</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>
<li>
<p>避免<strong>特殊字符被解析</strong>：</p>
<details open>
    <summary>bash</summary><pre
        class="chroma codeblock"
      ><code class="language-bash" data-lang="bash"
          ><span style="display:flex;"><span>echo <span style="color:#e6db74">&#39;$PATH and $(date)&#39;</span>  <span style="color:#75715e"># 输出: $PATH and $(date)</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><strong>特殊情况处理</strong></p>
<details open>
    <summary>bash</summary><pre
        class="chroma codeblock"
      ><code class="language-bash" data-lang="bash"
          ><span style="display:flex;"><span>alias rm<span style="color:#f92672">=</span><span style="color:#e6db74">&#39;rm -i&#39;</span>          <span style="color:#75715e"># 单引号内定义别名（避免变量提前展开）</span>
</span></span><span style="display:flex;"><span>echo <span style="color:#e6db74">&#34;It&#39;s a sunny day.&#34;</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><details open>
    <summary>bash</summary><pre
        class="chroma codeblock"
      ><code class="language-bash" data-lang="bash"
          ><span style="display:flex;"><span>echo <span style="color:#e6db74">&#34;Line 1\nLine 2&#34;</span>     <span style="color:#75715e"># 输出: Line 1\nLine 2（\n 未被转义为换行）</span>
</span></span><span style="display:flex;"><span>echo -e <span style="color:#e6db74">&#34;Line 1\nLine 2&#34;</span>  <span style="color:#75715e"># 输出两行（-e 启用转义）</span>
</span></span><span style="display:flex;"><span>echo <span style="color:#e6db74">&#39;Line 1\nLine 2&#39;</span>     <span style="color:#75715e"># 输出: Line 1\nLine 2（完全字面）</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><ul>
<li><strong>单引号稍快</strong>：因为无需解析变量或命令替换。</li>
<li>实际脚本中差异可忽略，优先考虑功能需求。</li>
</ul>
<ol>
<li><strong>默认用双引号</strong>：<br>
保护变量中的空格（如 <code>&quot;$file&quot;</code>），避免路径或文件名错误拆分。
<details open>
    <summary>bash</summary><pre
        class="chroma codeblock"
      ><code class="language-bash" data-lang="bash"
          ><span style="display:flex;"><span>cp <span style="color:#e6db74">&#34;</span>$file<span style="color:#e6db74">&#34;</span> <span style="color:#e6db74">&#34;/backup/</span>$file<span style="color:#e6db74">&#34;</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></li>
<li><strong>需要纯文本时用单引号</strong>：<br>
如正则表达式、代码生成、避免意外展开。
<details open>
    <summary>bash</summary><pre
        class="chroma codeblock"
      ><code class="language-bash" data-lang="bash"
          ><span style="display:flex;"><span>sed -e <span style="color:#e6db74">&#39;s/foo/bar/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></li>
</ol>
<h2 id="read-write">
  <a class="anchor inpage" href="#read-write">##</a>read, write</h2>
<h3 id="read">
  <a class="anchor inpage" href="#read">###</a>read</h3>
<h4 id="read-in-console">
  <a class="anchor inpage" href="#read-in-console">####</a>read in console</h4>
<details open>
    <summary>bash</summary><pre
        class="chroma codeblock"
      ><code class="language-bash" data-lang="bash"
          ><span style="display:flex;"><span>echo <span style="color:#e6db74">&#34;input a&#34;</span>
</span></span><span style="display:flex;"><span>read a
</span></span><span style="display:flex;"><span>echo <span style="color:#e6db74">&#34;input b&#34;</span>
</span></span><span style="display:flex;"><span>read b
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span>read -n <span style="color:#ae81ff">3</span> -t <span style="color:#ae81ff">5</span> -s -p <span style="color:#e6db74">&#34;input 3 charater, wait for 5 seconds, silent&#34;</span> c
</span></span><span style="display:flex;"><span>echo <span style="color:#e6db74">&#34;</span>$c<span style="color:#e6db74">&#34;</span>
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span>printf <span style="color:#e6db74">&#34;a=%s,b=%s,sum is %s&#34;</span> $a $b <span style="color:#66d9ef">$((</span>a <span style="color:#f92672">+</span> b<span style="color:#66d9ef">))</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>It is possible to give arguments to the script on execution.</p>
<p><code>$@</code> is a list of the parameters.</p>
<details open>
    <summary>bash</summary><pre
        class="chroma codeblock"
      ><code class="language-bash" data-lang="bash"
          ><span style="display:flex;"><span><span style="color:#75715e">#!/bin/bash
</span></span></span><span style="display:flex;"><span><span style="color:#75715e"></span>
</span></span><span style="display:flex;"><span><span style="color:#66d9ef">for</span> x in $@
</span></span><span style="display:flex;"><span><span style="color:#66d9ef">do</span>
</span></span><span style="display:flex;"><span>    echo <span style="color:#e6db74">&#34;Entered arg is </span>$x<span style="color:#e6db74">&#34;</span>
</span></span><span style="display:flex;"><span><span style="color:#66d9ef">done</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>Run it like this:</p>
<p><code>./script arg1 arg2</code></p>
<h4 id="read-in-file">
  <a class="anchor inpage" href="#read-in-file">####</a>read in file</h4>
<p>Suppose we have a file <code>sample_file.txt</code>, We can read the file line by line and print the output on the screen.</p>
<details open>
    <summary>bash</summary><pre
        class="chroma codeblock"
      ><code class="language-bash" data-lang="bash"
          ><span style="display:flex;"><span><span style="color:#75715e">#!/bin/bash
</span></span></span><span style="display:flex;"><span><span style="color:#75715e"></span>
</span></span><span style="display:flex;"><span>LINE<span style="color:#f92672">=</span><span style="color:#ae81ff">1</span>
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span><span style="color:#66d9ef">while</span> read -r CURRENT_LINE
</span></span><span style="display:flex;"><span>    <span style="color:#66d9ef">do</span>
</span></span><span style="display:flex;"><span>        echo <span style="color:#e6db74">&#34;</span>$LINE<span style="color:#e6db74">: </span>$CURRENT_LINE<span style="color:#e6db74">&#34;</span>
</span></span><span style="display:flex;"><span>    <span style="color:#f92672">((</span>LINE++<span style="color:#f92672">))</span>
</span></span><span style="display:flex;"><span><span style="color:#66d9ef">done</span> &lt; <span style="color:#e6db74">&#34;sample_file.txt&#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="write">
  <a class="anchor inpage" href="#write">###</a>write</h3>
<h2 id="redirection-pipe">
  <a class="anchor inpage" href="#redirection-pipe">##</a>redirection, pipe</h2>
<h3 id="direction">
  <a class="anchor inpage" href="#direction">###</a>direction</h3>
<h4 id="输出重定向">
  <a class="anchor inpage" href="#%e8%be%93%e5%87%ba%e9%87%8d%e5%ae%9a%e5%90%91">####</a>输出重定向</h4>
<table>
  <thead>
      <tr>
          <th>符号</th>
          <th>作用</th>
          <th>示例</th>
      </tr>
  </thead>
  <tbody>
      <tr>
          <td><code>&gt;</code></td>
          <td>覆盖写入文件（标准输出）</td>
          <td><code>ls &gt; file.txt</code></td>
      </tr>
      <tr>
          <td><code>&gt;&gt;</code></td>
          <td>追加到文件（标准输出）</td>
          <td><code>echo &quot;hi&quot; &gt;&gt; file.txt</code></td>
      </tr>
      <tr>
          <td><code>2&gt;</code></td>
          <td>覆盖写入文件（标准错误）</td>
          <td><code>cmd 2&gt; error.log</code></td>
      </tr>
      <tr>
          <td><code>2&gt;&gt;</code></td>
          <td>追加到文件（标准错误）</td>
          <td><code>cmd 2&gt;&gt; error.log</code></td>
      </tr>
      <tr>
          <td><code>&amp;&gt;</code></td>
          <td>覆盖写入文件（标准输出+标准错误）</td>
          <td><code>cmd &amp;&gt; output.log</code></td>
      </tr>
      <tr>
          <td><code>&amp;&gt;&gt;</code></td>
          <td>追加到文件（标准输出+标准错误）</td>
          <td><code>cmd &amp;&gt;&gt; output.log</code></td>
      </tr>
  </tbody>
</table>
<p><strong>文件描述符操作</strong> Bash 用数字<code>n</code>表示文件描述符（File Descriptor, FD）：</p>
<ul>
<li><code>0</code>：标准输入（stdin）</li>
<li><code>1</code>：标准输出（stdout）</li>
<li><code>2</code>：标准错误（stderr）</li>
</ul>
<table>
  <thead>
      <tr>
          <th>符号</th>
          <th>作用</th>
          <th>示例</th>
      </tr>
  </thead>
  <tbody>
      <tr>
          <td><code>n&gt;</code></td>
          <td>覆盖写入到文件描述符 <code>n</code></td>
          <td><code>cmd 3&gt; custom_fd.log</code></td>
      </tr>
      <tr>
          <td><code>n&gt;&gt;</code></td>
          <td>追加到文件描述符 <code>n</code></td>
          <td><code>cmd 3&gt;&gt; custom_fd.log</code></td>
      </tr>
      <tr>
          <td><code>n&gt;&amp;m</code></td>
          <td>将文件描述符 <code>n</code> 重定向到 <code>m</code></td>
          <td><code>cmd 2&gt;&amp;1</code>（错误合并到输出）</td>
      </tr>
      <tr>
          <td><code>n&gt;&amp;-</code></td>
          <td>关闭文件描述符 <code>n</code></td>
          <td><code>exec 3&gt;&amp;-</code></td>
      </tr>
      <tr>
          <td><code>&amp;&gt;file</code> 或 <code>&gt;&amp;file</code></td>
          <td>合并标准输出和错误到文件（兼容性写法）</td>
          <td><code>cmd &amp;&gt; all.log</code></td>
      </tr>
  </tbody>
</table>
<p><strong>示例</strong>：</p>
<details open>
    <summary>bash</summary><pre
        class="chroma codeblock"
      ><code class="language-bash" data-lang="bash"
          ><span style="display:flex;"><span><span style="color:#75715e"># 将标准错误重定向到文件描述符3，再重定向到文件</span>
</span></span><span style="display:flex;"><span>exec 3&gt;&amp;<span style="color:#ae81ff">1</span>  <span style="color:#75715e"># 备份标准输出到3</span>
</span></span><span style="display:flex;"><span>cmd 2&gt;&amp;<span style="color:#ae81ff">1</span> &gt;output.log | tee -a error.log  <span style="color:#75715e"># 错误流单独处理</span>
</span></span><span style="display:flex;"><span>exec 1&gt;&amp;<span style="color:#ae81ff">3</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><p><strong>特殊设备重定向</strong></p>
<table>
  <thead>
      <tr>
          <th>目标文件</th>
          <th>作用</th>
          <th>示例</th>
      </tr>
  </thead>
  <tbody>
      <tr>
          <td><code>/dev/null</code></td>
          <td>丢弃输出（黑洞设备）</td>
          <td><code>cmd &gt; /dev/null 2&gt;&amp;1</code></td>
      </tr>
      <tr>
          <td><code>/dev/stdout</code></td>
          <td>显式指向标准输出</td>
          <td><code>echo &quot;x&quot; &gt; /dev/stdout</code></td>
      </tr>
      <tr>
          <td><code>/dev/stderr</code></td>
          <td>显式指向标准错误</td>
          <td><code>echo &quot;error&quot; &gt; /dev/stderr</code></td>
      </tr>
      <tr>
          <td><code>/dev/fd/n</code></td>
          <td>重定向到文件描述符 <code>n</code></td>
          <td><code>cmd &gt; /dev/fd/3</code></td>
      </tr>
  </tbody>
</table>
<p><strong>示例</strong>：</p>
<details open>
    <summary>bash</summary><pre
        class="chroma codeblock"
      ><code class="language-bash" data-lang="bash"
          ><span style="display:flex;"><span><span style="color:#75715e"># 静默执行命令（忽略所有输出）</span>
</span></span><span style="display:flex;"><span>cmd &gt; /dev/null 2&gt;&amp;<span style="color:#ae81ff">1</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><h4 id="输入重定向">
  <a class="anchor inpage" href="#%e8%be%93%e5%85%a5%e9%87%8d%e5%ae%9a%e5%90%91">####</a>输入重定向</h4>
<table>
  <thead>
      <tr>
          <th>符号</th>
          <th>作用</th>
          <th>示例</th>
      </tr>
  </thead>
  <tbody>
      <tr>
          <td><code>&lt;</code></td>
          <td>从文件读取输入（标准输入）</td>
          <td><code>sort &lt; data.txt</code></td>
      </tr>
      <tr>
          <td><code>&lt;&lt;</code></td>
          <td>Here Document（多行输入）</td>
          <td>见前文</td>
      </tr>
      <tr>
          <td><code>&lt;&lt;&lt;</code></td>
          <td>Here String（字符串输入）</td>
          <td><code>grep &quot;x&quot; &lt;&lt;&lt; &quot;abc&quot;</code></td>
      </tr>
  </tbody>
</table>
<p><strong><code>&lt;</code>：标准输入重定向</strong></p>
<p><strong>作用</strong>：将文件内容作为命令的标准输入。<br>
<strong>语法</strong>：<code>command &lt; file</code><br>
<strong>特点</strong>：</p>
<ul>
<li>从文件中读取数据并传递给命令</li>
<li>文件内容会逐行作为命令的输入</li>
</ul>
<p><strong>示例</strong>：</p>
<details open>
    <summary>bash</summary><pre
        class="chroma codeblock"
      ><code class="language-bash" data-lang="bash"
          ><span style="display:flex;"><span><span style="color:#75715e"># 将 file.txt 的内容作为 wc 命令的输入</span>
</span></span><span style="display:flex;"><span>wc -l &lt; 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><strong>结果</strong>：统计 <code>file.txt</code> 的行数。</p>
<p><strong><code>&lt;&lt;</code>：Here Document（文档内嵌输入）</strong></p>
<p><strong>作用</strong>：将多行文本（称为 &ldquo;Here Document&rdquo;）作为命令的标准输入，直到遇到指定的结束标记。<br>
<strong>语法</strong>：</p>
<details open>
    <summary>bash</summary><pre
        class="chroma codeblock"
      ><code class="language-bash" data-lang="bash"
          ><span style="display:flex;"><span>command <span style="color:#e6db74">&lt;&lt; DELIMITER
</span></span></span><span style="display:flex;"><span><span style="color:#e6db74">多行文本...
</span></span></span><span style="display:flex;"><span><span style="color:#e6db74">DELIMITER</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><strong>特点</strong>：</p>
<ul>
<li>允许在脚本中直接嵌入多行输入</li>
<li>结束标记（<code>DELIMITER</code>）可以是任意字符串（通常用 <code>EOF</code>）</li>
<li>默认会解析变量和命令替换（除非用引号包围 <code>DELIMITER</code>，如 <code>&lt;&lt;'EOF'</code>）</li>
</ul>
<p><strong>示例</strong>：</p>
<details open>
    <summary>bash</summary><pre
        class="chroma codeblock"
      ><code class="language-bash" data-lang="bash"
          ><span style="display:flex;"><span><span style="color:#75715e"># 将多行文本传递给 cat 命令</span>
</span></span><span style="display:flex;"><span>cat <span style="color:#e6db74">&lt;&lt; EOF
</span></span></span><span style="display:flex;"><span><span style="color:#e6db74">第一行
</span></span></span><span style="display:flex;"><span><span style="color:#e6db74">第二行
</span></span></span><span style="display:flex;"><span><span style="color:#e6db74">变量值: $HOME
</span></span></span><span style="display:flex;"><span><span style="color:#e6db74">EOF</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><strong>结果</strong>：</p>
<details open>
    <summary>TEXT</summary><pre
        class="codeblock"
      ><code class="language-" data-lang="">第一行
第二行
变量值: /home/username</code><button onclick="copyCode(this)" class="copybtn">copy</button></pre></details>

  <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><code>&lt;&lt;&lt;</code>：Here String（字符串内嵌输入）</strong>
<strong>作用</strong>：将单个字符串作为命令的标准输入。<br>
<strong>语法</strong>：<code>command &lt;&lt;&lt; &quot;string&quot;</code><br>
<strong>特点</strong>：</p>
<ul>
<li>直接传递字符串（无需文件或多行文本）</li>
<li>字符串会解析变量和命令替换</li>
<li>比 <code>echo &quot;string&quot; | command</code> 更高效（避免管道和子进程）</li>
</ul>
<p><strong>示例</strong>：</p>
<details open>
    <summary>bash</summary><pre
        class="chroma codeblock"
      ><code class="language-bash" data-lang="bash"
          ><span style="display:flex;"><span><span style="color:#75715e"># 将字符串传递给 grep 命令</span>
</span></span><span style="display:flex;"><span>grep <span style="color:#e6db74">&#34;hello&#34;</span> <span style="color:#f92672">&lt;&lt;&lt;</span> <span style="color:#e6db74">&#34;hello world&#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><strong>结果</strong>：输出 <code>hello world</code>（因为匹配成功）。</p>
<p><strong>对比总结</strong></p>
<table>
  <thead>
      <tr>
          <th>操作符</th>
          <th>名称</th>
          <th>输入源</th>
          <th>典型用途</th>
          <th>是否解析变量</th>
      </tr>
  </thead>
  <tbody>
      <tr>
          <td><code>&lt;</code></td>
          <td>输入重定向</td>
          <td>文件</td>
          <td>从文件读取数据</td>
          <td>是</td>
      </tr>
      <tr>
          <td><code>&lt;&lt;</code></td>
          <td>Here Document</td>
          <td>多行文本（脚本内嵌）</td>
          <td>传递多行输入（如生成配置文件）</td>
          <td>是（可禁用）</td>
      </tr>
      <tr>
          <td><code>&lt;&lt;&lt;</code></td>
          <td>Here String</td>
          <td>单个字符串</td>
          <td>快速传递变量或简单字符串</td>
          <td>是</td>
      </tr>
  </tbody>
</table>
<p><strong>关键区别</strong></p>
<ol>
<li>
<p><strong>输入来源不同</strong>：</p>
<ul>
<li><code>&lt;</code> 从文件读取</li>
<li><code>&lt;&lt;</code> 从脚本内嵌的多行文本读取</li>
<li><code>&lt;&lt;&lt;</code> 从单个字符串读取</li>
</ul>
</li>
<li>
<p><strong>性能差异</strong>：</p>
<ul>
<li><code>&lt;&lt;&lt;</code> 比 <code>echo &quot;str&quot; | command</code> 更高效（避免管道）</li>
<li><code>&lt;</code> 适合处理大文件（逐行读取，不占用内存）</li>
</ul>
</li>
<li>
<p><strong>变量解析</strong>：</p>
<ul>
<li><code>&lt;&lt;</code> 和 <code>&lt;&lt;&lt;</code> 默认解析变量，但 <code>&lt;&lt;</code> 可通过 <code>&lt;&lt;'DELIMITER'</code> 禁用解析</li>
<li><code>&lt;</code> 由命令决定是否解析（如 <code>cat</code> 不解析，<code>eval</code> 会解析）</li>
</ul>
</li>
</ol>
<hr>
<p><strong>使用场景示例</strong>
<strong><code>&lt;</code> 的典型用途</strong></p>
<details open>
    <summary>bash</summary><pre
        class="chroma codeblock"
      ><code class="language-bash" data-lang="bash"
          ><span style="display:flex;"><span><span style="color:#75715e"># 从配置文件读取输入</span>
</span></span><span style="display:flex;"><span><span style="color:#66d9ef">while</span> read line; <span style="color:#66d9ef">do</span>
</span></span><span style="display:flex;"><span>    echo <span style="color:#e6db74">&#34;配置行: </span>$line<span style="color:#e6db74">&#34;</span>
</span></span><span style="display:flex;"><span><span style="color:#66d9ef">done</span> &lt; config.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><strong><code>&lt;&lt;</code> 的典型用途</strong></p>
<details open>
    <summary>bash</summary><pre
        class="chroma codeblock"
      ><code class="language-bash" data-lang="bash"
          ><span style="display:flex;"><span><span style="color:#75715e"># 生成多行配置文件</span>
</span></span><span style="display:flex;"><span>cat &gt; app.conf <span style="color:#e6db74">&lt;&lt; EOF
</span></span></span><span style="display:flex;"><span><span style="color:#e6db74">server_ip=192.168.1.1
</span></span></span><span style="display:flex;"><span><span style="color:#e6db74">port=8080
</span></span></span><span style="display:flex;"><span><span style="color:#e6db74">EOF</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><strong><code>&lt;&lt;&lt;</code> 的典型用途</strong></p>
<details open>
    <summary>bash</summary><pre
        class="chroma codeblock"
      ><code class="language-bash" data-lang="bash"
          ><span style="display:flex;"><span><span style="color:#75715e"># 快速检查字符串是否包含子串</span>
</span></span><span style="display:flex;"><span>grep <span style="color:#e6db74">&#34;error&#34;</span> <span style="color:#f92672">&lt;&lt;&lt;</span> <span style="color:#e6db74">&#34;</span>$log_content<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><p><strong>注意事项</strong></p>
<ol>
<li>
<p><strong><code>&lt;&lt;</code> 的结束标记</strong>：</p>
<ul>
<li>结束标记必须单独一行且顶格书写（不能有缩进）：
<details open>
    <summary>bash</summary><pre
        class="chroma codeblock"
      ><code class="language-bash" data-lang="bash"
          ><span style="display:flex;"><span><span style="color:#75715e"># 错误示例（缩进会导致语法错误）</span>
</span></span><span style="display:flex;"><span>cat <span style="color:#e6db74">&lt;&lt; EOF
</span></span></span><span style="display:flex;"><span><span style="color:#e6db74">内容...
</span></span></span><span style="display:flex;"><span><span style="color:#e6db74">  EOF</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></li>
</ul>
</li>
<li>
<p><strong><code>&lt;&lt;&lt;</code> 的字符串引用</strong>：</p>
<ul>
<li>如果字符串包含空格或特殊字符，需用引号包围：
<details open>
    <summary>bash</summary><pre
        class="chroma codeblock"
      ><code class="language-bash" data-lang="bash"
          ><span style="display:flex;"><span><span style="color:#75715e"># 安全写法</span>
</span></span><span style="display:flex;"><span>wc -w <span style="color:#f92672">&lt;&lt;&lt;</span> <span style="color:#e6db74">&#34;hello world&#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></li>
</ul>
</li>
<li>
<p><strong>性能选择</strong>：</p>
<ul>
<li>处理大量数据时优先用 <code>&lt;</code>（文件）或 <code>&lt;&lt;</code>（多行文本）</li>
<li>简单字符串操作用 <code>&lt;&lt;&lt;</code> 更高效</li>
</ul>
</li>
</ol>
<h4 id="重定向组合">
  <a class="anchor inpage" href="#%e9%87%8d%e5%ae%9a%e5%90%91%e7%bb%84%e5%90%88">####</a>重定向组合</h4>
<p><strong>(1) 同时重定向输入和输出</strong></p>
<details open>
    <summary>bash</summary><pre
        class="chroma codeblock"
      ><code class="language-bash" data-lang="bash"
          ><span style="display:flex;"><span><span style="color:#75715e"># 从input.txt读取，结果写入output.txt</span>
</span></span><span style="display:flex;"><span>command &lt; input.txt &gt; output.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><strong>(2) 分离标准输出和错误</strong></p>
<details open>
    <summary>bash</summary><pre
        class="chroma codeblock"
      ><code class="language-bash" data-lang="bash"
          ><span style="display:flex;"><span><span style="color:#75715e"># 标准输出到out.log，错误到err.log</span>
</span></span><span style="display:flex;"><span>command &gt; out.log 2&gt; err.log</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><strong>(3) 合并输出和错误到同一文件</strong></p>
<details open>
    <summary>bash</summary><pre
        class="chroma codeblock"
      ><code class="language-bash" data-lang="bash"
          ><span style="display:flex;"><span><span style="color:#75715e"># 方式1（推荐）</span>
</span></span><span style="display:flex;"><span>command &amp;&gt; combined.log
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span><span style="color:#75715e"># 方式2（传统写法）</span>
</span></span><span style="display:flex;"><span>command &gt; combined.log 2&gt;&amp;<span style="color:#ae81ff">1</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><h4 id="进程替换process-substitution">
  <a class="anchor inpage" href="#%e8%bf%9b%e7%a8%8b%e6%9b%bf%e6%8d%a2process-substitution">####</a>进程替换（Process Substitution）</h4>
<p>用 <code>&gt;(...)</code> 和 <code>&lt;(...)</code> 将命令输出/输入视为临时文件：</p>
<table>
  <thead>
      <tr>
          <th>符号</th>
          <th>作用</th>
          <th>示例</th>
      </tr>
  </thead>
  <tbody>
      <tr>
          <td><code>&lt;(cmd)</code></td>
          <td>将命令输出作为文件输入</td>
          <td><code>diff &lt;(ls dir1) &lt;(ls dir2)</code></td>
      </tr>
      <tr>
          <td><code>&gt;(cmd)</code></td>
          <td>将命令输入作为文件输出</td>
          <td><code>tee &gt;(gzip &gt; out.gz)</code></td>
      </tr>
  </tbody>
</table>
<p><strong>示例</strong>：</p>
<details open>
    <summary>bash</summary><pre
        class="chroma codeblock"
      ><code class="language-bash" data-lang="bash"
          ><span style="display:flex;"><span><span style="color:#75715e"># 比较两个目录的文件列表差异</span>
</span></span><span style="display:flex;"><span>diff &lt;<span style="color:#f92672">(</span>ls /path/to/dir1<span style="color:#f92672">)</span> &lt;<span style="color:#f92672">(</span>ls /path/to/dir2<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>echo <span style="color:#e6db74">&#34;data&#34;</span> | tee &gt;<span style="color:#f92672">(</span>gzip &gt; output.gz<span style="color:#f92672">)</span> &gt; original.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><h4 id="综合示例">
  <a class="anchor inpage" href="#%e7%bb%bc%e5%90%88%e7%a4%ba%e4%be%8b">####</a>综合示例</h4>
<p>** 日志记录脚本**</p>
<details open>
    <summary>bash</summary><pre
        class="chroma codeblock"
      ><code class="language-bash" data-lang="bash"
          ><span style="display:flex;"><span><span style="color:#75715e">#!/bin/bash
</span></span></span><span style="display:flex;"><span><span style="color:#75715e"></span>exec 3&gt;&amp;<span style="color:#ae81ff">1</span>  <span style="color:#75715e"># 备份标准输出到描述符3</span>
</span></span><span style="display:flex;"><span>exec &gt; &gt;<span style="color:#f92672">(</span>tee -a stdout.log<span style="color:#f92672">)</span> 2&gt; &gt;<span style="color:#f92672">(</span>tee -a stderr.log &gt;&amp;2<span style="color:#f92672">)</span>  <span style="color:#75715e"># 分离输出和错误</span>
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span>echo <span style="color:#e6db74">&#34;正常消息&#34;</span>  <span style="color:#75715e"># 写入stdout.log</span>
</span></span><span style="display:flex;"><span>ls /nonexistent  <span style="color:#75715e"># 错误写入stderr.log</span>
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span>exec 1&gt;&amp;<span style="color:#ae81ff">3</span>  <span style="color:#75715e"># 恢复标准输出</span>
</span></span><span style="display:flex;"><span>echo <span style="color:#e6db74">&#34;回到终端显示&#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><strong>复杂重定向</strong></p>
<details open>
    <summary>bash</summary><pre
        class="chroma codeblock"
      ><code class="language-bash" data-lang="bash"
          ><span style="display:flex;"><span><span style="color:#f92672">{</span>
</span></span><span style="display:flex;"><span>    echo <span style="color:#e6db74">&#34;标准输出1&#34;</span>
</span></span><span style="display:flex;"><span>    echo <span style="color:#e6db74">&#34;标准错误1&#34;</span> &gt;&amp;<span style="color:#ae81ff">2</span>
</span></span><span style="display:flex;"><span>    echo <span style="color:#e6db74">&#34;标准输出2&#34;</span>
</span></span><span style="display:flex;"><span>    echo <span style="color:#e6db74">&#34;标准错误2&#34;</span> &gt;&amp;<span style="color:#ae81ff">2</span>
</span></span><span style="display:flex;"><span><span style="color:#f92672">}</span> &gt; &gt;<span style="color:#f92672">(</span>grep <span style="color:#e6db74">&#34;标准输出&#34;</span> &gt; out.txt<span style="color:#f92672">)</span> 2&gt; &gt;<span style="color:#f92672">(</span>grep <span style="color:#e6db74">&#34;标准错误&#34;</span> &gt; err.txt<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><strong>注意事项</strong></p>
<ol>
<li>
<p><strong>顺序敏感</strong>：<br>
<code>2&gt;&amp;1 &gt;file</code> 和 <code>&gt;file 2&gt;&amp;1</code> 完全不同！后者才是合并输出到文件。</p>
<details open>
    <summary>bash</summary><pre
        class="chroma codeblock"
      ><code class="language-bash" data-lang="bash"
          ><span style="display:flex;"><span><span style="color:#75715e"># 错误：错误流不会进入文件</span>
</span></span><span style="display:flex;"><span>cmd 2&gt;&amp;<span style="color:#ae81ff">1</span> &gt; file
</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>cmd &gt; file 2&gt;&amp;<span style="color:#ae81ff">1</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>
<li>
<p><strong>文件描述符范围</strong>：<br>
Bash 默认支持 <code>0-9</code>，更高数值需用 <code>exec</code> 显式分配。</p>
</li>
<li>
<p><strong>管道与重定向优先级</strong>：<br>
管道 <code>|</code> 优先级高于重定向，必要时用 <code>{ }</code> 分组：</p>
<details open>
    <summary>bash</summary><pre
        class="chroma codeblock"
      ><code class="language-bash" data-lang="bash"
          ><span style="display:flex;"><span><span style="color:#f92672">{</span> cmd1 | cmd2; <span style="color:#f92672">}</span> &gt; output.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></li>
<li>
<p><strong>Here Document 的变体</strong>：</p>
<ul>
<li><code>&lt;&lt;-</code>：忽略结束标记前的制表符（Tab）
<details open>
    <summary>bash</summary><pre
        class="chroma codeblock"
      ><code class="language-bash" data-lang="bash"
          ><span style="display:flex;"><span>cat <span style="color:#e6db74">&lt;&lt;- EOF
</span></span></span><span style="display:flex;"><span><span style="color:#e6db74">    Indented text
</span></span></span><span style="display:flex;"><span><span style="color:#e6db74">EOF</span>  <span style="color:#75715e"># 可以用Tab缩进</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>
</li>
</ol>
<h3 id="pipe">
  <a class="anchor inpage" href="#pipe">###</a>pipe</h3>
<h2 id="control">
  <a class="anchor inpage" href="#control">##</a>control</h2>
<h3 id="if">
  <a class="anchor inpage" href="#if">###</a>if</h3>
<ul>
<li><code>if...then...fi</code> statements</li>
<li><code>if...then...else...fi</code> statements</li>
<li><code>if..elif..else..fi</code></li>
<li><code>if..then..else..if..then..fi..fi..</code> (Nested Conditionals)</li>
</ul>
<details open>
    <summary>bash</summary><pre
        class="chroma codeblock"
      ><code class="language-bash" data-lang="bash"
          ><span style="display:flex;"><span><span style="color:#66d9ef">if</span> <span style="color:#f92672">[</span> ... <span style="color:#f92672">]</span>
</span></span><span style="display:flex;"><span><span style="color:#66d9ef">then</span>
</span></span><span style="display:flex;"><span>  <span style="color:#75715e"># if-code</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"># else-code</span>
</span></span><span style="display:flex;"><span><span style="color:#66d9ef">fi</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>or</p>
<details open>
    <summary>bash</summary><pre
        class="chroma codeblock"
      ><code class="language-bash" data-lang="bash"
          ><span style="display:flex;"><span><span style="color:#66d9ef">if</span> <span style="color:#f92672">[</span> ... <span style="color:#f92672">]</span> ; <span style="color:#66d9ef">then</span>
</span></span><span style="display:flex;"><span>  <span style="color:#75715e"># if-code</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"># else-code</span>
</span></span><span style="display:flex;"><span><span style="color:#66d9ef">fi</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>conditions:</p>
<p>examples:</p>
<details open>
    <summary>bash</summary><pre
        class="chroma codeblock"
      ><code class="language-bash" data-lang="bash"
          ><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 style="color:#66d9ef">if</span> <span style="color:#f92672">[</span> <span style="color:#e6db74">&#34;</span>$X<span style="color:#e6db74">&#34;</span> -lt <span style="color:#e6db74">&#34;0&#34;</span> <span style="color:#f92672">]</span>
</span></span><span style="display:flex;"><span><span style="color:#66d9ef">then</span>
</span></span><span style="display:flex;"><span>  echo <span style="color:#e6db74">&#34;X is less than zero&#34;</span>
</span></span><span style="display:flex;"><span><span style="color:#66d9ef">fi</span>
</span></span><span style="display:flex;"><span><span style="color:#66d9ef">if</span> <span style="color:#f92672">[</span> <span style="color:#e6db74">&#34;</span>$X<span style="color:#e6db74">&#34;</span> -gt <span style="color:#e6db74">&#34;0&#34;</span> <span style="color:#f92672">]</span>; <span style="color:#66d9ef">then</span>
</span></span><span style="display:flex;"><span>  echo <span style="color:#e6db74">&#34;X is more than zero&#34;</span>
</span></span><span style="display:flex;"><span><span style="color:#66d9ef">fi</span>
</span></span><span style="display:flex;"><span><span style="color:#f92672">[</span> <span style="color:#e6db74">&#34;</span>$X<span style="color:#e6db74">&#34;</span> -le <span style="color:#e6db74">&#34;0&#34;</span> <span style="color:#f92672">]</span> <span style="color:#f92672">&amp;&amp;</span> <span style="color:#ae81ff">\
</span></span></span><span style="display:flex;"><span><span style="color:#ae81ff"></span>      echo <span style="color:#e6db74">&#34;X is less than or equal to  zero&#34;</span>
</span></span><span style="display:flex;"><span><span style="color:#f92672">[</span> <span style="color:#e6db74">&#34;</span>$X<span style="color:#e6db74">&#34;</span> -ge <span style="color:#e6db74">&#34;0&#34;</span> <span style="color:#f92672">]</span> <span style="color:#f92672">&amp;&amp;</span> <span style="color:#ae81ff">\
</span></span></span><span style="display:flex;"><span><span style="color:#ae81ff"></span>      echo <span style="color:#e6db74">&#34;X is more than or equal to zero&#34;</span>
</span></span><span style="display:flex;"><span><span style="color:#f92672">[</span> <span style="color:#e6db74">&#34;</span>$X<span style="color:#e6db74">&#34;</span> <span style="color:#f92672">=</span> <span style="color:#e6db74">&#34;0&#34;</span> <span style="color:#f92672">]</span> <span style="color:#f92672">&amp;&amp;</span> <span style="color:#ae81ff">\
</span></span></span><span style="display:flex;"><span><span style="color:#ae81ff"></span>      echo <span style="color:#e6db74">&#34;X is the string or number \&#34;0\&#34;&#34;</span>
</span></span><span style="display:flex;"><span><span style="color:#f92672">[</span> <span style="color:#e6db74">&#34;</span>$X<span style="color:#e6db74">&#34;</span> <span style="color:#f92672">=</span> <span style="color:#e6db74">&#34;hello&#34;</span> <span style="color:#f92672">]</span> <span style="color:#f92672">&amp;&amp;</span> <span style="color:#ae81ff">\
</span></span></span><span style="display:flex;"><span><span style="color:#ae81ff"></span>      echo <span style="color:#e6db74">&#34;X matches the string \&#34;hello\&#34;&#34;</span>
</span></span><span style="display:flex;"><span><span style="color:#f92672">[</span> <span style="color:#e6db74">&#34;</span>$X<span style="color:#e6db74">&#34;</span> !<span style="color:#f92672">=</span> <span style="color:#e6db74">&#34;hello&#34;</span> <span style="color:#f92672">]</span> <span style="color:#f92672">&amp;&amp;</span> <span style="color:#ae81ff">\
</span></span></span><span style="display:flex;"><span><span style="color:#ae81ff"></span>      echo <span style="color:#e6db74">&#34;X is not the string \&#34;hello\&#34;&#34;</span>
</span></span><span style="display:flex;"><span><span style="color:#f92672">[</span> -n <span style="color:#e6db74">&#34;</span>$X<span style="color:#e6db74">&#34;</span> <span style="color:#f92672">]</span> <span style="color:#f92672">&amp;&amp;</span> <span style="color:#ae81ff">\
</span></span></span><span style="display:flex;"><span><span style="color:#ae81ff"></span>      echo <span style="color:#e6db74">&#34;X is of nonzero length&#34;</span>
</span></span><span style="display:flex;"><span><span style="color:#f92672">[</span> -f <span style="color:#e6db74">&#34;</span>$X<span style="color:#e6db74">&#34;</span> <span style="color:#f92672">]</span> <span style="color:#f92672">&amp;&amp;</span> <span style="color:#ae81ff">\
</span></span></span><span style="display:flex;"><span><span style="color:#ae81ff"></span>      echo <span style="color:#e6db74">&#34;X is the path of a real file&#34;</span> <span style="color:#f92672">||</span> <span style="color:#ae81ff">\
</span></span></span><span style="display:flex;"><span><span style="color:#ae81ff"></span>      echo <span style="color:#e6db74">&#34;No such file: </span>$X<span style="color:#e6db74">&#34;</span>
</span></span><span style="display:flex;"><span><span style="color:#f92672">[</span> -x <span style="color:#e6db74">&#34;</span>$X<span style="color:#e6db74">&#34;</span> <span style="color:#f92672">]</span> <span style="color:#f92672">&amp;&amp;</span> <span style="color:#ae81ff">\
</span></span></span><span style="display:flex;"><span><span style="color:#ae81ff"></span>      echo <span style="color:#e6db74">&#34;X is the path of an executable file&#34;</span>
</span></span><span style="display:flex;"><span><span style="color:#f92672">[</span> <span style="color:#e6db74">&#34;</span>$X<span style="color:#e6db74">&#34;</span> -nt <span style="color:#e6db74">&#34;/etc/passwd&#34;</span> <span style="color:#f92672">]</span> <span style="color:#f92672">&amp;&amp;</span> <span style="color:#ae81ff">\
</span></span></span><span style="display:flex;"><span><span style="color:#ae81ff"></span>      echo <span style="color:#e6db74">&#34;X is a file which is newer than /etc/passwd&#34;</span>
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span>read a
</span></span><span style="display:flex;"><span>read b
</span></span><span style="display:flex;"><span>read c
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span><span style="color:#66d9ef">if</span> <span style="color:#f92672">[</span> $a <span style="color:#f92672">==</span> $b -a $b <span style="color:#f92672">==</span> $c -a $a <span style="color:#f92672">==</span> $c <span style="color:#f92672">]</span> <span style="color:#75715e"># -a means</span>
</span></span><span style="display:flex;"><span><span style="color:#66d9ef">then</span>
</span></span><span style="display:flex;"><span>echo EQUILATERAL
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span><span style="color:#66d9ef">elif</span> <span style="color:#f92672">[</span> $a <span style="color:#f92672">==</span> $b -o $b <span style="color:#f92672">==</span> $c -o $a <span style="color:#f92672">==</span> $c <span style="color:#f92672">]</span> <span style="color:#75715e"># -o means or</span>
</span></span><span style="display:flex;"><span><span style="color:#66d9ef">then</span>
</span></span><span style="display:flex;"><span>echo ISOSCELES
</span></span><span style="display:flex;"><span><span style="color:#66d9ef">else</span>
</span></span><span style="display:flex;"><span>echo SCALENE
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span><span style="color:#66d9ef">fi</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="loop">
  <a class="anchor inpage" href="#loop">###</a>loop</h3>
<details open>
    <summary>bash</summary><pre
        class="chroma codeblock"
      ><code class="language-bash" data-lang="bash"
          ><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span><span style="color:#66d9ef">for</span> i in <span style="color:#f92672">{</span>1..5<span style="color:#f92672">}</span>
</span></span><span style="display:flex;"><span><span style="color:#66d9ef">do</span>
</span></span><span style="display:flex;"><span>    echo $i
</span></span><span style="display:flex;"><span><span style="color:#66d9ef">done</span>
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span><span style="color:#66d9ef">for</span> X in cyan magenta yellow
</span></span><span style="display:flex;"><span><span style="color:#66d9ef">do</span>
</span></span><span style="display:flex;"><span>    echo $X
</span></span><span style="display:flex;"><span><span style="color:#66d9ef">done</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>bash</summary><pre
        class="chroma codeblock"
      ><code class="language-bash" data-lang="bash"
          ><span style="display:flex;"><span>i<span style="color:#f92672">=</span><span style="color:#ae81ff">1</span>
</span></span><span style="display:flex;"><span><span style="color:#66d9ef">while</span> <span style="color:#f92672">[[</span> $i -le <span style="color:#ae81ff">10</span> <span style="color:#f92672">]]</span> ; <span style="color:#66d9ef">do</span>
</span></span><span style="display:flex;"><span>   echo <span style="color:#e6db74">&#34;</span>$i<span style="color:#e6db74">&#34;</span>
</span></span><span style="display:flex;"><span>  <span style="color:#f92672">((</span> i <span style="color:#f92672">+=</span> <span style="color:#ae81ff">1</span> <span style="color:#f92672">))</span>
</span></span><span style="display:flex;"><span><span style="color:#66d9ef">done</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>bash</summary><pre
        class="chroma codeblock"
      ><code class="language-bash" data-lang="bash"
          ><span style="display:flex;"><span><span style="color:#75715e"># 定义数组（空格分隔元素，可含特殊字符）</span>
</span></span><span style="display:flex;"><span>fruits<span style="color:#f92672">=(</span><span style="color:#e6db74">&#34;Apple&#34;</span> <span style="color:#e6db74">&#34;Banana&#34;</span> <span style="color:#e6db74">&#34;Orange&#34;</span> <span style="color:#e6db74">&#34;Grape&#34;</span> <span style="color:#e6db74">&#34;Watermelon&#34;</span><span style="color:#f92672">)</span>
</span></span><span style="display:flex;"><span><span style="color:#66d9ef">for</span> fruit in <span style="color:#e6db74">&#34;</span><span style="color:#e6db74">${</span>fruits[@]<span style="color:#e6db74">}</span><span style="color:#e6db74">&#34;</span>; <span style="color:#66d9ef">do</span>
</span></span><span style="display:flex;"><span>    echo <span style="color:#e6db74">&#34;Fruit: </span>$fruit<span style="color:#e6db74">&#34;</span>
</span></span><span style="display:flex;"><span><span style="color:#66d9ef">done</span>
</span></span><span style="display:flex;"><span><span style="color:#66d9ef">for</span> i in <span style="color:#e6db74">&#34;</span><span style="color:#e6db74">${</span>!fruits[@]<span style="color:#e6db74">}</span><span style="color:#e6db74">&#34;</span>; <span style="color:#66d9ef">do</span>
</span></span><span style="display:flex;"><span>    echo <span style="color:#e6db74">&#34;Index </span>$i<span style="color:#e6db74">: </span><span style="color:#e6db74">${</span>fruits[i]<span style="color:#e6db74">}</span><span style="color:#e6db74">&#34;</span>
</span></span><span style="display:flex;"><span><span style="color:#66d9ef">done</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>bash</summary><pre
        class="chroma codeblock"
      ><code class="language-bash" data-lang="bash"
          ><span style="display:flex;"><span><span style="color:#75715e"># 定义仓库目录列表（支持绝对路径或相对路径）</span>
</span></span><span style="display:flex;"><span>repos<span style="color:#f92672">=(</span>
</span></span><span style="display:flex;"><span>    <span style="color:#e6db74">&#34;/path/to/repo1&#34;</span>
</span></span><span style="display:flex;"><span>    <span style="color:#e6db74">&#34;/path/to/repo2&#34;</span>
</span></span><span style="display:flex;"><span>    <span style="color:#e6db74">&#34;/path/to/repo3&#34;</span>
</span></span><span style="display:flex;"><span>    <span style="color:#e6db74">&#34;/path/to/repo4&#34;</span>
</span></span><span style="display:flex;"><span><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><span style="color:#66d9ef">for</span> i in <span style="color:#e6db74">&#34;</span><span style="color:#e6db74">${</span>repos[@]<span style="color:#e6db74">}</span><span style="color:#e6db74">&#34;</span>; <span style="color:#66d9ef">do</span>
</span></span><span style="display:flex;"><span>    echo <span style="color:#e6db74">&#34;Updating repo: </span>$i<span style="color:#e6db74">&#34;</span>
</span></span><span style="display:flex;"><span>    cd <span style="color:#e6db74">&#34;</span>$i<span style="color:#e6db74">&#34;</span> <span style="color:#f92672">||</span> <span style="color:#f92672">{</span> echo <span style="color:#e6db74">&#34;Failed to enter </span>$i<span style="color:#e6db74">&#34;</span>; <span style="color:#66d9ef">continue</span>; <span style="color:#f92672">}</span>
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span>    <span style="color:#75715e"># 执行 git pull</span>
</span></span><span style="display:flex;"><span>    git pull origin main  <span style="color:#75715e"># 假设分支是 main，根据实际情况修改</span>
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span>    <span style="color:#75715e"># 检查 git pull 是否成功</span>
</span></span><span style="display:flex;"><span>    <span style="color:#66d9ef">if</span> <span style="color:#f92672">[</span> $? -eq <span style="color:#ae81ff">0</span> <span style="color:#f92672">]</span>; <span style="color:#66d9ef">then</span>
</span></span><span style="display:flex;"><span>        echo <span style="color:#e6db74">&#34;Successfully updated: </span>$i<span style="color:#e6db74">&#34;</span>
</span></span><span style="display:flex;"><span>    <span style="color:#66d9ef">else</span>
</span></span><span style="display:flex;"><span>        echo <span style="color:#e6db74">&#34;Failed to update: </span>$i<span style="color:#e6db74">&#34;</span>
</span></span><span style="display:flex;"><span>    <span style="color:#66d9ef">fi</span>
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span>    echo <span style="color:#e6db74">&#34;----------------------------------&#34;</span>
</span></span><span style="display:flex;"><span><span style="color:#66d9ef">done</span>
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span>echo <span style="color:#e6db74">&#34;All repositories updated!&#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><h2 id="function">
  <a class="anchor inpage" href="#function">##</a>function</h2>
<blockquote class="alert alert-warning">
      <p class="alert-heading"><br></p><p><strong>fork boom!</strong></p>
<details open>
    <summary>TEXT</summary><pre
        class="codeblock"
      ><code class="language-" data-lang="">:(){:|:;};:</code><button onclick="copyCode(this)" class="copybtn">copy</button></pre></details>

  <script>
    function copyCode(btn) {
      const code = btn.previousElementSibling.textContent.trim();
      navigator.clipboard.writeText(code).then(() => {
        btn.innerText = "copied";
        setTimeout(() => (btn.innerText = "copy"), 2000);
      });
    }
  </script></blockquote><h2 id="advance">
  <a class="anchor inpage" href="#advance">##</a>Advance</h2>
<h3 id="get-opts">
  <a class="anchor inpage" href="#get-opts">###</a>get-opts</h3>
<p>example:</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>docs<span style="color:#f92672">=</span><span style="color:#e6db74">&#34;Usage: \
</span></span></span><span style="display:flex;"><span><span style="color:#e6db74">\n\tbash </span>$0<span style="color:#e6db74"> [options] \
</span></span></span><span style="display:flex;"><span><span style="color:#e6db74">\nOptions: \
</span></span></span><span style="display:flex;"><span><span style="color:#e6db74">\n\t-N NAME: your name, required\
</span></span></span><span style="display:flex;"><span><span style="color:#e6db74">\n\t-a AGE: your age, required\
</span></span></span><span style="display:flex;"><span><span style="color:#e6db74">\n\t-v: verbose mode, optional\
</span></span></span><span style="display:flex;"><span><span style="color:#e6db74">\nExample: \
</span></span></span><span style="display:flex;"><span><span style="color:#e6db74">\n\t bash </span>$0<span style="color:#e6db74"> -N balabala -a 24 &#34;</span>
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span>usage<span style="color:#f92672">()</span> <span style="color:#f92672">{</span>
</span></span><span style="display:flex;"><span>    echo -e $docs &gt;&amp;<span style="color:#ae81ff">2</span>
</span></span><span style="display:flex;"><span>    exit <span style="color:#ae81ff">1</span>
</span></span><span style="display:flex;"><span><span style="color:#f92672">}</span>
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span><span style="color:#66d9ef">if</span> <span style="color:#f92672">[</span> $# -eq <span style="color:#ae81ff">0</span> <span style="color:#f92672">]</span> <span style="color:#f92672">||</span> <span style="color:#f92672">[</span> $1 <span style="color:#f92672">==</span> -h <span style="color:#f92672">]</span>; <span style="color:#66d9ef">then</span> usage; <span style="color:#66d9ef">fi</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>verbose<span style="color:#f92672">=</span>n
</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>check<span style="color:#f92672">()</span> <span style="color:#f92672">{</span>
</span></span><span style="display:flex;"><span>    opt<span style="color:#f92672">=</span>$1
</span></span><span style="display:flex;"><span>    arg<span style="color:#f92672">=</span>$2
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span>    <span style="color:#66d9ef">if</span> <span style="color:#f92672">[[</span> $arg <span style="color:#f92672">=</span>~ ^- <span style="color:#f92672">]]</span> <span style="color:#f92672">||</span> <span style="color:#f92672">[</span> ! $arg <span style="color:#f92672">]</span>
</span></span><span style="display:flex;"><span>    <span style="color:#66d9ef">then</span>
</span></span><span style="display:flex;"><span>        echo <span style="color:#e6db74">&#34;ERROR: -</span>$opt<span style="color:#e6db74"> expects an corresponding argument&#34;</span> &gt;&amp;<span style="color:#ae81ff">2</span>
</span></span><span style="display:flex;"><span>        usage
</span></span><span style="display:flex;"><span>    <span style="color:#66d9ef">fi</span>
</span></span><span style="display:flex;"><span><span style="color:#f92672">}</span>
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span><span style="color:#75715e">## 循环解析脚本的所有positional parameters</span>
</span></span><span style="display:flex;"><span><span style="color:#66d9ef">while</span> getopts :vN:a: opt
</span></span><span style="display:flex;"><span><span style="color:#66d9ef">do</span>
</span></span><span style="display:flex;"><span>    <span style="color:#66d9ef">case</span> $opt in
</span></span><span style="display:flex;"><span>    v<span style="color:#f92672">)</span>
</span></span><span style="display:flex;"><span>        verbose<span style="color:#f92672">=</span>y
</span></span><span style="display:flex;"><span>        ;;
</span></span><span style="display:flex;"><span>    N<span style="color:#f92672">)</span>
</span></span><span style="display:flex;"><span>        check N $OPTARG
</span></span><span style="display:flex;"><span>        name<span style="color:#f92672">=</span>$OPTARG
</span></span><span style="display:flex;"><span>        ;;
</span></span><span style="display:flex;"><span>    a<span style="color:#f92672">)</span>
</span></span><span style="display:flex;"><span>        check a $OPTARG
</span></span><span style="display:flex;"><span>        age<span style="color:#f92672">=</span>$OPTARG
</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>        echo <span style="color:#e6db74">&#34;ERROR: -</span>$OPTARG<span style="color:#e6db74"> expects an corresponding argument&#34;</span> &gt;&amp;<span style="color:#ae81ff">2</span>
</span></span><span style="display:flex;"><span>        usage
</span></span><span style="display:flex;"><span>        ;;
</span></span><span style="display:flex;"><span>    <span style="color:#ae81ff">\?</span><span style="color:#f92672">)</span> <span style="color:#75715e"># shell里&#39;?&#39;具有匹配一位任意字符的作用，因此需要转义为普通字符</span>
</span></span><span style="display:flex;"><span>        echo <span style="color:#e6db74">&#34;ERROR: unkown option -</span>$OPTARG<span style="color:#e6db74">&#34;</span> &gt;&amp;<span style="color:#ae81ff">2</span>
</span></span><span style="display:flex;"><span>        usage
</span></span><span style="display:flex;"><span>        ;;
</span></span><span style="display:flex;"><span>    <span style="color:#66d9ef">esac</span>
</span></span><span style="display:flex;"><span><span style="color:#66d9ef">done</span>
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span><span style="color:#75715e">## 如果用户没有提供-N选项</span>
</span></span><span style="display:flex;"><span><span style="color:#66d9ef">if</span> <span style="color:#f92672">[</span> ! $name <span style="color:#f92672">]</span>
</span></span><span style="display:flex;"><span><span style="color:#66d9ef">then</span>
</span></span><span style="display:flex;"><span>    echo ERROR: option -N is required &gt;&amp;<span style="color:#ae81ff">2</span>
</span></span><span style="display:flex;"><span>    usage
</span></span><span style="display:flex;"><span><span style="color:#66d9ef">fi</span>
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span><span style="color:#75715e">## 如果用户没有提供-a选项</span>
</span></span><span style="display:flex;"><span><span style="color:#66d9ef">if</span> <span style="color:#f92672">[</span> ! $age <span style="color:#f92672">]</span>
</span></span><span style="display:flex;"><span><span style="color:#66d9ef">then</span>
</span></span><span style="display:flex;"><span>    echo ERROR: option -a is required &gt;&amp;<span style="color:#ae81ff">2</span>
</span></span><span style="display:flex;"><span>    usage
</span></span><span style="display:flex;"><span><span style="color:#66d9ef">fi</span>
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span><span style="color:#66d9ef">if</span> <span style="color:#f92672">[</span> $verbose <span style="color:#f92672">==</span> n <span style="color:#f92672">]</span>
</span></span><span style="display:flex;"><span><span style="color:#66d9ef">then</span>
</span></span><span style="display:flex;"><span>    echo <span style="color:#e6db74">&#34;Merry Christmas! </span>$name<span style="color:#e6db74">&#34;</span>
</span></span><span style="display:flex;"><span><span style="color:#66d9ef">else</span>
</span></span><span style="display:flex;"><span>    echo <span style="color:#e6db74">&#34;Hello, your name is </span>$name<span style="color:#e6db74">, you are </span>$age<span style="color:#e6db74"> years old!&#34;</span>
</span></span><span style="display:flex;"><span>    echo <span style="color:#e6db74">&#34;Merry Christmas!!&#34;</span>
</span></span><span style="display:flex;"><span><span style="color:#66d9ef">fi</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>:vN:a:</code>中，第一个<code>:</code> 表示静默错误模式（silent error mode）。如果没有这个<code>:</code>，当遇到无效选项时，getopts 会打印错误消息。<br>
选项后的 <code>:</code>（如 N:）表示该选项需要一个参数。<br>
如果没有 <code>:</code>，则表示该选项不需要参数。</p>
<h3 id="cron">
  <a class="anchor inpage" href="#cron">###</a>cron</h3>
<p>Cron is a job scheduling utility present in Unix like systems. You can schedule jobs to execute daily, weekly, monthly or in a specific time of the day. Automation in Linux heavily relies on cron jobs.</p>
<p>Below is the syntax to schedule crons:</p>
<details open>
    <summary>bash</summary><pre
        class="chroma codeblock"
      ><code class="language-bash" data-lang="bash"
          ><span style="display:flex;"><span><span style="color:#75715e"># Cron job example</span>
</span></span><span style="display:flex;"><span>* * * * * sh /path/to/script.sh</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>Here, <code>*</code> represents minute(s) hour(s) day(s) month(s) weekday(s), respectively.</p>
<p>Below are some examples of scheduling cron jobs.</p>
<table>
  <thead>
      <tr>
          <th>SCHEDULE</th>
          <th>SCHEDULED VALUE</th>
      </tr>
  </thead>
  <tbody>
      <tr>
          <td>5 0 * 8 *</td>
          <td>At 00:05 in August.</td>
      </tr>
      <tr>
          <td>5 4 * * 6</td>
          <td>At 04:05 on Saturday.</td>
      </tr>
      <tr>
          <td>0 22 * * 1-5</td>
          <td>At 22:00 on every day-of-week from Monday through Friday.</td>
      </tr>
  </tbody>
</table>
<p><code>crontab -l</code> lists the already scheduled scripts for a particular user.</p>
]]></content:encoded></item><item><title>从键盘到字符</title><link>https://hiraethecho.github.io/docs/linux/keysym/</link><pubDate>Tue, 17 Dec 2024 00:00:00 +0000</pubDate><author>wyz2016zxc@outlook.com(Hiraeth)</author><guid>https://hiraethecho.github.io/docs/linux/keysym/</guid><description>linux下从键盘收到信号后到屏幕上显示字符的过程</description><content:encoded><![CDATA[<h1 id="从键盘到字符">
  <a class="anchor inpage" href="#%e4%bb%8e%e9%94%ae%e7%9b%98%e5%88%b0%e5%ad%97%e7%ac%a6">#</a>从键盘到字符</h1>
<h2 id="前置知识">
  <a class="anchor inpage" href="#%e5%89%8d%e7%bd%ae%e7%9f%a5%e8%af%86">##</a>前置知识</h2>
<p>参考
</p>
<ul>
<li>硬件，即键盘本身，发出扫描码（scancode），发送给内核；</li>
<li>内核并将其转换为键码（keycode）。键码是操作系统用来识别按键的数字表示。</li>
<li>受到键码后，X服务器或Wayland合成器将其转换为键符（keysym）。键符是一个更高级别的表示，表示按键的实际字符或功能。</li>
</ul>
<p>在xorg下，有
来使用keycode</p>
<h2 id="识别">
  <a class="anchor inpage" href="#%e8%af%86%e5%88%ab">##</a>识别</h2>
<p>xorg下管理接入的输入设备，例如 find id of touchpad:</p>
<details open>
    <summary>TEXT</summary><pre
        class="codeblock"
      ><code class="language-" data-lang="">xinput list | grep -i &#34;Touchpad&#34; | awk &#39;{print $6}&#39; | sed &#39;s/[^0-9]//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>似乎需要添加文件 <code>/usr/share/X11/xorg.conf.d/30-touchpad.conf</code></p>
<details open>
    <summary>conf</summary><pre
        class="codeblock"
      ><code class="language-conf" data-lang="conf">Section &#34;InputClass&#34;
        Identifier &#34;MyTouchpad&#34;
        MatchIsTouchpad &#34;on&#34;
        Driver &#34;libinput&#34;
        Option &#34;Tapping&#34; &#34;on&#34;
EndSection</code><button onclick="copyCode(this)" class="copybtn">copy</button></pre></details>

  <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>touchpad</code>：</p>
<details open>
    <summary>xinput</summary><pre
        class="codeblock"
      ><code class="language-xinput" data-lang="xinput">
⎡ Virtual core pointer                    	id=2	[master pointer  (3)]
⎜   ↳ Virtual core XTEST pointer              	id=4	[slave  pointer  (2)]
⎜   ↳ GXTP7863:00 27C6:01E0 Mouse             	id=11	[slave  pointer  (2)]
⎜   ↳ GXTP7863:00 27C6:01E0 Touchpad          	id=12	[slave  pointer  (2)]
⎜   ↳ HS6209 2.4G Wireless Receiver Keyboard  	id=9	[slave  pointer  (2)]
⎜   ↳ HS6209 2.4G Wireless Receiver Mouse     	id=10	[slave  pointer  (2)]
⎣ Virtual core keyboard                   	id=3	[master keyboard (2)]
    ↳ Virtual core XTEST keyboard             	id=5	[slave  keyboard (3)]
    ↳ Video Bus                               	id=6	[slave  keyboard (3)]
    ↳ Power Button                            	id=7	[slave  keyboard (3)]
    ↳ Huawei WMI hotkeys                      	id=13	[slave  keyboard (3)]
    ↳ AT Translated Set 2 keyboard            	id=14	[slave  keyboard (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>否则只会识别两个设备，没有 <code>Mouse</code> <code>Touchpad</code></p>
<details open>
    <summary>sh</summary><pre
        class="chroma codeblock"
      ><code class="language-sh" data-lang="sh"
          ><span style="display:flex;"><span>$ xinput list
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span>⎡ Virtual core pointer                    	id<span style="color:#f92672">=</span>2	<span style="color:#f92672">[</span>master pointer  <span style="color:#f92672">(</span>3<span style="color:#f92672">)]</span>
</span></span><span style="display:flex;"><span>⎜   ↳ Virtual core XTEST pointer              	id<span style="color:#f92672">=</span>4	<span style="color:#f92672">[</span>slave  pointer  <span style="color:#f92672">(</span>2<span style="color:#f92672">)]</span>
</span></span><span style="display:flex;"><span>⎜   ↳ GXTP7863:00 27C6:01E0                   	id<span style="color:#f92672">=</span>10	<span style="color:#f92672">[</span>slave  pointer  <span style="color:#f92672">(</span>2<span style="color:#f92672">)]</span>
</span></span><span style="display:flex;"><span>⎜   ↳ GXTP7863:00 27C6:01E0                   	id<span style="color:#f92672">=</span>11	<span style="color:#f92672">[</span>slave  pointer  <span style="color:#f92672">(</span>2<span style="color:#f92672">)]</span>
</span></span><span style="display:flex;"><span>⎣ Virtual core keyboard                   	id<span style="color:#f92672">=</span>3	<span style="color:#f92672">[</span>master keyboard <span style="color:#f92672">(</span>2<span style="color:#f92672">)]</span>
</span></span><span style="display:flex;"><span>    ↳ Virtual core XTEST keyboard             	id<span style="color:#f92672">=</span>5	<span style="color:#f92672">[</span>slave  keyboard <span style="color:#f92672">(</span>3<span style="color:#f92672">)]</span>
</span></span><span style="display:flex;"><span>    ↳ Video Bus                               	id<span style="color:#f92672">=</span>6	<span style="color:#f92672">[</span>slave  keyboard <span style="color:#f92672">(</span>3<span style="color:#f92672">)]</span>
</span></span><span style="display:flex;"><span>    ↳ Power Button                            	id<span style="color:#f92672">=</span>7	<span style="color:#f92672">[</span>slave  keyboard <span style="color:#f92672">(</span>3<span style="color:#f92672">)]</span>
</span></span><span style="display:flex;"><span>    ↳ Huawei WMI hotkeys                      	id<span style="color:#f92672">=</span>12	<span style="color:#f92672">[</span>slave  keyboard <span style="color:#f92672">(</span>3<span style="color:#f92672">)]</span>
</span></span><span style="display:flex;"><span>    ↳ AT Translated Set <span style="color:#ae81ff">2</span> keyboard            	id<span style="color:#f92672">=</span>13	<span style="color:#f92672">[</span>slave  keyboard <span style="color:#f92672">(</span>3<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>xev</code>: find keycode;</p>
<h2 id="修改">
  <a class="anchor inpage" href="#%e4%bf%ae%e6%94%b9">##</a>修改</h2>
<h3 id="xorg">
  <a class="anchor inpage" href="#xorg">###</a>xorg</h3>
<p>支持的修改可以参考 <code>/usr/share/X11/xkb/rules/base.lst</code></p>
<details open>
    <summary>TEXT</summary><pre
        class="codeblock"
      ><code class="language-" data-lang="">  caps                 Caps Lock behavior
  caps:internal        Caps Lock uses internal capitalization; Shift &#34;pauses&#34; Caps Lock
  caps:internal_nocancel Caps Lock uses internal capitalization; Shift does not affect Caps Lock
  caps:shift           Caps Lock acts as Shift with locking; Shift &#34;pauses&#34; Caps Lock
  caps:shift_nocancel  Caps Lock acts as Shift with locking; Shift does not affect Caps Lock
  caps:capslock        Caps Lock toggles normal capitalization of alphabetic characters
  caps:shiftlock       Caps Lock toggles Shift Lock (affects all keys)
  caps:swapescape      Swap Esc and Caps Lock
  caps:escape          Make Caps Lock an additional Esc
  caps:escape_shifted_capslock Make Caps Lock an additional Esc, but Shift &#43; Caps Lock is the regular Caps Lock
  caps:backspace       Make Caps Lock an additional Backspace
  caps:return          Make Caps Lock an additional Return key
  caps:super           Make Caps Lock an additional Super
  caps:hyper           Make Caps Lock an additional Hyper
  caps:menu            Make Caps Lock an additional Menu key
  caps:numlock         Make Caps Lock an additional Num Lock
  caps:ctrl_shifted_capslock Make Caps Lock an additional Ctrl and Shift &#43; Caps Lock the regular Caps Lock
  caps:ctrl_modifier   Make Caps Lock act as an additional Ctrl modifier, but keep identifying as Caps Lock
  caps:digits_row      Caps Lock gives digits on the digits row (Azerty layouts)
  caps:digits_row_independent_lock Shift &#43; Caps locks the digits on the digits row, Caps Lock alone behaves as usual (Azerty layouts)
  caps:none            Caps Lock is disabled

  ctrl                 Ctrl position
  ctrl:nocaps          Caps Lock as Ctrl
  ctrl:lctrl_meta      Left Ctrl as Meta
  ctrl:swapcaps        Swap Ctrl and Caps Lock
  ctrl:grouptoggle_capscontrol Caps Lock as Ctrl,  Left Control switches to another layout
  ctrl:hyper_capscontrol Caps Lock as Ctrl, Ctrl as Hyper
  ctrl:ac_ctrl         To the left of &#34;A&#34;
  ctrl:aa_ctrl         At the bottom left
  ctrl:rctrl_ralt      Right Ctrl as Right Alt
  ctrl:ralt_rctrl      Right Alt as Right Control
  ctrl:menu_rctrl      Menu as Right Ctrl
  ctrl:swap_lalt_lctl  Swap Left Alt with Left Ctrl
  ctrl:swap_ralt_rctl  Swap Right Alt with Right Ctrl
  ctrl:swap_lwin_lctl  Swap Left Win with Left Ctrl
  ctrl:swap_rwin_rctl  Swap Right Win with Right Ctrl
  ctrl:swap_lalt_lctl_lwin Left Alt as Ctrl, Left Ctrl as Win, Left Win as Left Alt</code><button onclick="copyCode(this)" class="copybtn">copy</button></pre></details>

  <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="xmodmap">
  <a class="anchor inpage" href="#xmodmap">####</a>xmodmap</h4>
<details open>
    <summary>man</summary><pre
        class="chroma codeblock"
      ><code class="language-man" data-lang="man"
          ><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span>XMODMAP(1)                  General Commands Manual                  XMODMAP(1)
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span>NAME
</span></span><span style="display:flex;"><span>       xmodmap - utility for modifying keymaps and pointer button mappings in X
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span>SYNOPSIS
</span></span><span style="display:flex;"><span>       xmodmap [-options ...] [filename]
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span>DESCRIPTION
</span></span><span style="display:flex;"><span>       The  xmodmap  program  is used to edit and display the keyboard modifier
</span></span><span style="display:flex;"><span>       map and keymap table that are used by  client  applications  to  convert
</span></span><span style="display:flex;"><span>       event  keycodes into keysyms.  It is usually run from the user&#39;s session
</span></span><span style="display:flex;"><span>       startup script to configure the keyboard according to personal tastes.
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span>OPTIONS
</span></span><span style="display:flex;"><span>       The following options may be used with xmodmap:
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span>       -display display
</span></span><span style="display:flex;"><span>               This option specifies the host and display to use.
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span>       -help   This option indicates that a brief description  of  the  command
</span></span><span style="display:flex;"><span>               line  arguments should be printed on the standard error channel.
</span></span><span style="display:flex;"><span>               This will be done whenever an unhandled  argument  is  given  to
</span></span><span style="display:flex;"><span>               xmodmap.
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span>       -grammar
</span></span><span style="display:flex;"><span>               This option indicates that a help message describing the expres‐
</span></span><span style="display:flex;"><span>               sion  grammar  used  in  files and with -e expressions should be
</span></span><span style="display:flex;"><span>               printed on the standard error.
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span>       -version
</span></span><span style="display:flex;"><span>               This option indicates that xmodmap should print its version  in‐
</span></span><span style="display:flex;"><span>               formation and exit.
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span>       -verbose
</span></span><span style="display:flex;"><span>               This option indicates that xmodmap should print logging informa‐
</span></span><span style="display:flex;"><span>               tion as it parses its input.
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span>       -quiet  This option turns off the verbose logging.  This is the default.
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span>       -n      This  option  indicates  that xmodmap should not change the map‐
</span></span><span style="display:flex;"><span>               pings, but should display what it would do,  like  make(1)  does
</span></span><span style="display:flex;"><span>               when given this option.
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span>       -e expression
</span></span><span style="display:flex;"><span>               This  option specifies an expression to be executed.  Any number
</span></span><span style="display:flex;"><span>               of expressions may be specified from the command line.
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span>       -pm     This option indicates that the current modifier  map  should  be
</span></span><span style="display:flex;"><span>               printed  on  the  standard output.   This is the default mode of
</span></span><span style="display:flex;"><span>               operation if no other mode options are specified.
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span>       -pk     This option indicates that the current keymap  table  should  be
</span></span><span style="display:flex;"><span>               printed on the standard output.
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span>       -pke    This  option  indicates  that the current keymap table should be
</span></span><span style="display:flex;"><span>               printed on the standard output in the form of  expressions  that
</span></span><span style="display:flex;"><span>               can be fed back to xmodmap.
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span>       -pp     This  option  indicates  that  the current pointer map should be
</span></span><span style="display:flex;"><span>               printed on the standard output.
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span>       -       A lone dash means that the standard input should be used as  the
</span></span><span style="display:flex;"><span>               input file.
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span>       The  filename specifies a file containing xmodmap expressions to be exe‐
</span></span><span style="display:flex;"><span>       cuted.  This file is usually kept in the user&#39;s home  directory  with  a
</span></span><span style="display:flex;"><span>       name like .xmodmaprc.
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span>EXPRESSION GRAMMAR
</span></span><span style="display:flex;"><span>       The  xmodmap program reads a list of expressions and parses them all be‐
</span></span><span style="display:flex;"><span>       fore attempting to execute any of them.  This makes it possible to refer
</span></span><span style="display:flex;"><span>       to keysyms that are being redefined in a natural way without  having  to
</span></span><span style="display:flex;"><span>       worry as much about name conflicts.
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span>       The   list   of   keysym   names   may  be  found  in  the  header  file
</span></span><span style="display:flex;"><span>       &lt;X11/keysymdef.h&gt; (without the XK_ prefix).   Keysyms  matching  Unicode
</span></span><span style="display:flex;"><span>       characters  may  be  specified  as  &#34;U0020&#34;  to  &#34;U007E&#34;  and &#34;U00A0&#34; to
</span></span><span style="display:flex;"><span>       &#34;U10FFFF&#34; for all possible Unicode characters.
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span>       keycode NUMBER = KEYSYMNAME ...
</span></span><span style="display:flex;"><span>               The list of keysyms is assigned to the indicated keycode  (which
</span></span><span style="display:flex;"><span>               may  be specified in decimal, hex or octal and can be determined
</span></span><span style="display:flex;"><span>               by running the xev program).  Up to eight  keysyms  may  be  at‐
</span></span><span style="display:flex;"><span>               tached to a key, however the last four are not used in any major
</span></span><span style="display:flex;"><span>               X server implementation.  The first keysym is used when no modi‐
</span></span><span style="display:flex;"><span>               fier  key  is  pressed  in conjunction with this key, the second
</span></span><span style="display:flex;"><span>               with Shift, the third when the Mode_switch key is used with this
</span></span><span style="display:flex;"><span>               key and the fourth when both the Mode_switch and Shift keys  are
</span></span><span style="display:flex;"><span>               used.
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span>       keycode any = KEYSYMNAME ...
</span></span><span style="display:flex;"><span>               If no existing key has the specified list of keysyms assigned to
</span></span><span style="display:flex;"><span>               it,  a spare key on the keyboard is selected and the keysyms are
</span></span><span style="display:flex;"><span>               assigned to it.  The list of keysyms may be specified  in  deci‐
</span></span><span style="display:flex;"><span>               mal, hex or octal.
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span>       keysym KEYSYMNAME = KEYSYMNAME ...
</span></span><span style="display:flex;"><span>               The KEYSYMNAME on the left hand side is translated into matching
</span></span><span style="display:flex;"><span>               keycodes  used  to  perform the corresponding set of keycode ex‐
</span></span><span style="display:flex;"><span>               pressions.  Note that if the same keysym is  bound  to  multiple
</span></span><span style="display:flex;"><span>               keys, the expression is executed for each matching keycode.
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span>       clear MODIFIERNAME
</span></span><span style="display:flex;"><span>               This removes all entries in the modifier map for the given modi‐
</span></span><span style="display:flex;"><span>               fier,  where  valid  name are: Shift, Lock, Control, Mod1, Mod2,
</span></span><span style="display:flex;"><span>               Mod3, Mod4, and Mod5 (case does not matter  in  modifier  names,
</span></span><span style="display:flex;"><span>               although  it  does  matter  for  all other names).  For example,
</span></span><span style="display:flex;"><span>               ‘‘clear Lock&#39;&#39; will remove all any keys that were bound  to  the
</span></span><span style="display:flex;"><span>               shift lock modifier.
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span>       add MODIFIERNAME = KEYSYMNAME ...
</span></span><span style="display:flex;"><span>               This adds all keys containing the given keysyms to the indicated
</span></span><span style="display:flex;"><span>               modifier  map.   The  keysym names are evaluated after all input
</span></span><span style="display:flex;"><span>               expressions are read to make it easy  to  write  expressions  to
</span></span><span style="display:flex;"><span>               swap keys (see the EXAMPLES section).
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span>       remove MODIFIERNAME = KEYSYMNAME ...
</span></span><span style="display:flex;"><span>               This  removes all keys containing the given keysyms from the in‐
</span></span><span style="display:flex;"><span>               dicated modifier map.  Unlike add, the keysym names  are  evalu‐
</span></span><span style="display:flex;"><span>               ated  as  the  line  is read in.  This allows you to remove keys
</span></span><span style="display:flex;"><span>               from a modifier without having to worry  about  whether  or  not
</span></span><span style="display:flex;"><span>               they have been reassigned.
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span>       pointer = default
</span></span><span style="display:flex;"><span>               This sets the pointer map back to its default settings (button 1
</span></span><span style="display:flex;"><span>               generates a code of 1, button 2 generates a 2, etc.).
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span>       pointer = NUMBER ...
</span></span><span style="display:flex;"><span>               This sets the pointer map to contain the indicated button codes.
</span></span><span style="display:flex;"><span>               The  list always starts with the first physical button.  Setting
</span></span><span style="display:flex;"><span>               a button code to 0 disables events from that button.
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span>       Lines that begin with an exclamation point (!) are taken as comments.
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span>       If you want to change the binding of a modifier key, you must  also  re‐
</span></span><span style="display:flex;"><span>       move it from the appropriate modifier map.
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span>EXAMPLES
</span></span><span style="display:flex;"><span>       Many  pointers  are designed such that the first button is pressed using
</span></span><span style="display:flex;"><span>       the index finger of the right hand.  People  who  are  left-handed  fre‐
</span></span><span style="display:flex;"><span>       quently  find  that  it  is more comfortable to reverse the button codes
</span></span><span style="display:flex;"><span>       that get generated so that the primary button is pressed using the index
</span></span><span style="display:flex;"><span>       finger of the left hand.  This could be done on a 3  button  pointer  as
</span></span><span style="display:flex;"><span>       follows:
</span></span><span style="display:flex;"><span>       %  xmodmap -e &#34;pointer = 3 2 1&#34;
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span>       Many  applications  support  the notion of Meta keys (similar to Control
</span></span><span style="display:flex;"><span>       keys except that Meta is held down instead of Control).   However,  some
</span></span><span style="display:flex;"><span>       servers  do  not  have a Meta keysym in the default keymap table, so one
</span></span><span style="display:flex;"><span>       needs to be added by hand.  The following command will  attach  Meta  to
</span></span><span style="display:flex;"><span>       the  Multi-language  key (sometimes labeled Compose Character).  It also
</span></span><span style="display:flex;"><span>       takes advantage of the fact that applications that need a Meta key  sim‐
</span></span><span style="display:flex;"><span>       ply  need  to  get the keycode and don&#39;t require the keysym to be in the
</span></span><span style="display:flex;"><span>       first column of the keymap table.  This means that applications that are
</span></span><span style="display:flex;"><span>       looking for a Multi_key (including the default modifier map)  won&#39;t  no‐
</span></span><span style="display:flex;"><span>       tice any change.
</span></span><span style="display:flex;"><span>       %  xmodmap -e &#34;keysym Multi_key = Multi_key Meta_L&#34;
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span>       Similarly, some keyboards have an Alt key but no Meta key.  In that case
</span></span><span style="display:flex;"><span>       the following may be useful:
</span></span><span style="display:flex;"><span>       %  xmodmap -e &#34;keysym Alt_L = Meta_L Alt_L&#34;
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span>       One  of  the  more simple, yet convenient, uses of xmodmap is to set the
</span></span><span style="display:flex;"><span>       keyboard&#39;s &#34;rubout&#34; key to generate  an  alternate  keysym.   This  fre‐
</span></span><span style="display:flex;"><span>       quently involves exchanging Backspace with Delete to be more comfortable
</span></span><span style="display:flex;"><span>       to the user.  If the ttyModes resource in xterm is set as well, all ter‐
</span></span><span style="display:flex;"><span>       minal emulator windows will use the same key for erasing characters:
</span></span><span style="display:flex;"><span>       %  xmodmap -e &#34;keysym BackSpace = Delete&#34;
</span></span><span style="display:flex;"><span>       %  echo &#34;XTerm*ttyModes:  erase ^?&#34; | xrdb -merge
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span>       Some  keyboards do not automatically generate less than and greater than
</span></span><span style="display:flex;"><span>       characters when the comma and period keys  are  shifted.   This  can  be
</span></span><span style="display:flex;"><span>       remedied with xmodmap by resetting the bindings for the comma and period
</span></span><span style="display:flex;"><span>       with the following scripts:
</span></span><span style="display:flex;"><span>       !
</span></span><span style="display:flex;"><span>       ! make shift-, be &lt; and shift-. be &gt;
</span></span><span style="display:flex;"><span>       !
</span></span><span style="display:flex;"><span>       keysym comma = comma less
</span></span><span style="display:flex;"><span>       keysym period = period greater
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span>       One of the more irritating differences between keyboards is the location
</span></span><span style="display:flex;"><span>       of  the  Control  and CapsLock keys.  A common use of xmodmap is to swap
</span></span><span style="display:flex;"><span>       these two keys as follows:
</span></span><span style="display:flex;"><span>       !
</span></span><span style="display:flex;"><span>       ! Swap Caps_Lock and Control_L
</span></span><span style="display:flex;"><span>       !
</span></span><span style="display:flex;"><span>       remove Lock = Caps_Lock
</span></span><span style="display:flex;"><span>       remove Control = Control_L
</span></span><span style="display:flex;"><span>       keysym Control_L = Caps_Lock
</span></span><span style="display:flex;"><span>       keysym Caps_Lock = Control_L
</span></span><span style="display:flex;"><span>       add Lock = Caps_Lock
</span></span><span style="display:flex;"><span>       add Control = Control_L
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span>       This example can be run again to swap the keys back  to  their  previous
</span></span><span style="display:flex;"><span>       assignments.
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span>       The  keycode command is useful for assigning the same keysym to multiple
</span></span><span style="display:flex;"><span>       keycodes.  Although unportable, it  also  makes  it  possible  to  write
</span></span><span style="display:flex;"><span>       scripts  that  can  reset  the keyboard to a known state.  The following
</span></span><span style="display:flex;"><span>       script sets the backspace key  to  generate  Delete  (as  shown  above),
</span></span><span style="display:flex;"><span>       flushes  all  existing  caps  lock bindings, makes the CapsLock key be a
</span></span><span style="display:flex;"><span>       control key, make F5 generate Escape, and makes Break/Reset be  a  shift
</span></span><span style="display:flex;"><span>       lock.
</span></span><span style="display:flex;"><span>       !
</span></span><span style="display:flex;"><span>       ! On the HP, the following keycodes have key caps as listed:
</span></span><span style="display:flex;"><span>       !
</span></span><span style="display:flex;"><span>       !     101  Backspace
</span></span><span style="display:flex;"><span>       !      55  Caps
</span></span><span style="display:flex;"><span>       !      14  Ctrl
</span></span><span style="display:flex;"><span>       !      15  Break/Reset
</span></span><span style="display:flex;"><span>       !      86  Stop
</span></span><span style="display:flex;"><span>       !      89  F5
</span></span><span style="display:flex;"><span>       !
</span></span><span style="display:flex;"><span>       keycode 101 = Delete
</span></span><span style="display:flex;"><span>       keycode 55 = Control_R
</span></span><span style="display:flex;"><span>       clear Lock
</span></span><span style="display:flex;"><span>       add Control = Control_R
</span></span><span style="display:flex;"><span>       keycode 89 = Escape
</span></span><span style="display:flex;"><span>       keycode 15 = Caps_Lock
</span></span><span style="display:flex;"><span>       add Lock = Caps_Lock
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span>ENVIRONMENT
</span></span><span style="display:flex;"><span>       DISPLAY to get default host and display number.
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span>X Version 11                     xmodmap 1.0.11                      XMODMAP(1)</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>xmodmap 修改键码到键符的映射 (<code>xkeycaps</code> gui);</p>
<p>usage of <code>xmodmap</code>:</p>
<p>modifier for X Window. mod1: left Alt, mod2: Num_Lock，mod3: no，mod4: Left Super (windows)，mod5: Shift</p>
<details open>
    <summary>sh</summary><pre
        class="chroma codeblock"
      ><code class="language-sh" data-lang="sh"
          ><span style="display:flex;"><span>$ xmodmap -pm
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span>xmodmap:  up to <span style="color:#ae81ff">4</span> keys per modifier, <span style="color:#f92672">(</span>keycodes in parentheses<span style="color:#f92672">)</span>:
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span>shift       Shift_L <span style="color:#f92672">(</span>0x32<span style="color:#f92672">)</span>,  Shift_R <span style="color:#f92672">(</span>0x3e<span style="color:#f92672">)</span>
</span></span><span style="display:flex;"><span>lock        Caps_Lock <span style="color:#f92672">(</span>0x42<span style="color:#f92672">)</span>
</span></span><span style="display:flex;"><span>control     Control_L <span style="color:#f92672">(</span>0x25<span style="color:#f92672">)</span>,  Control_R <span style="color:#f92672">(</span>0x69<span style="color:#f92672">)</span>
</span></span><span style="display:flex;"><span>mod1        Alt_L <span style="color:#f92672">(</span>0x40<span style="color:#f92672">)</span>,  Alt_R <span style="color:#f92672">(</span>0x6c<span style="color:#f92672">)</span>,  Alt_L <span style="color:#f92672">(</span>0xcc<span style="color:#f92672">)</span>,  Meta_L <span style="color:#f92672">(</span>0xcd<span style="color:#f92672">)</span>
</span></span><span style="display:flex;"><span>mod2        Num_Lock <span style="color:#f92672">(</span>0x4d<span style="color:#f92672">)</span>
</span></span><span style="display:flex;"><span>mod3        ISO_Level5_Shift <span style="color:#f92672">(</span>0xcb<span style="color:#f92672">)</span>,  Hyper_L <span style="color:#f92672">(</span>0xcf<span style="color:#f92672">)</span>
</span></span><span style="display:flex;"><span>mod4        Super_L <span style="color:#f92672">(</span>0x85<span style="color:#f92672">)</span>,  Super_R <span style="color:#f92672">(</span>0x86<span style="color:#f92672">)</span>,  Super_L <span style="color:#f92672">(</span>0xce<span style="color:#f92672">)</span>
</span></span><span style="display:flex;"><span>mod5        ISO_Level3_Shift <span style="color:#f92672">(</span>0x5c<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>Keycode is what the kernal get, and keysym is what it gives. Each keysym column in the table corresponds to a particular combination of modifier keys:</p>
<ol>
<li>Key</li>
<li>Shift+Key</li>
<li>Mode_switch+Key</li>
<li>Mode_switch+Shift+Key</li>
<li>ISO_Level3_Shift+Key</li>
<li>ISO_Level3_Shift+Shift+Key</li>
</ol>
<p>check current keycode map:</p>
<details open>
    <summary>TEXT</summary><pre
        class="codeblock"
      ><code class="language-" data-lang="">$ xmodmap -pke

keycode   8 =
keycode   9 = Escape NoSymbol Escape
keycode  10 = 1 exclam 1 exclam
keycode  11 = 2 at 2 at
keycode  12 = 3 numbersign 3 numbersign
keycode  13 = 4 dollar 4 dollar
keycode  14 = 5 percent 5 percent
keycode  15 = 6 asciicircum 6 asciicircum
keycode  16 = 7 ampersand 7 ampersand
keycode  17 = 8 asterisk 8 asterisk
keycode  18 = 9 parenleft 9 parenleft
keycode  19 = 0 parenright 0 parenright
...
keycode  34 = bracketleft braceleft bracketleft braceleft
keycode  35 = bracketright braceright bracketright braceright
keycode  36 = Return NoSymbol Return
keycode  37 = Control_L NoSymbol Control_L
keycode  38 = a A a A
keycode  39 = s S s S
keycode  40 = d D d D
keycode  41 = f F f F
keycode  42 = g G g G
keycode  43 = h H h H
keycode  67 = F1 F1 F1 F1 F1 F1 XF86Switch_VT_1
keycode  68 = F2 F2 F2 F2 F2 F2 XF86Switch_VT_2
...</code><button onclick="copyCode(this)" class="copybtn">copy</button></pre></details>

  <script>
    function copyCode(btn) {
      const code = btn.previousElementSibling.textContent.trim();
      navigator.clipboard.writeText(code).then(() => {
        btn.innerText = "copied";
        setTimeout(() => (btn.innerText = "copy"), 2000);
      });
    }
  </script><blockquote class="alert alert-warning">
      <p class="alert-heading">WARNING</p><p>xmodmap设置会被setxkbmap重置，它不仅将字母数字键改变为映射表中的值，还将所有其他键重置为启动时的默认值。
由于Xorg的限制，xmodmap设置不会自动应用到热插拔设备上。如果在应用了自定义映射表后，系统中添加了一个新的键盘，则必须重新应用自定义映射表</p></blockquote><h4 id="setxkbmap">
  <a class="anchor inpage" href="#setxkbmap">####</a>setxkbmap</h4>
<p><code>setxkbmap</code>: set keyboard layout;</p>
<details open>
    <summary>man</summary><pre
        class="chroma codeblock"
      ><code class="language-man" data-lang="man"
          ><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span>SETXKBMAP(1)                General Commands Manual                SETXKBMAP(1)
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span>NAME
</span></span><span style="display:flex;"><span>       setxkbmap - set the keyboard using the X Keyboard Extension
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span>SYNOPSIS
</span></span><span style="display:flex;"><span>       setxkbmap [ args ] [ layout [ variant [ option ...  ] ] ]
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span>DESCRIPTION
</span></span><span style="display:flex;"><span>       The  setxkbmap command maps the keyboard to use the layout determined by
</span></span><span style="display:flex;"><span>       the options specified on the command line.
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span>       An XKB keymap is constructed from a number of components which are  com‐
</span></span><span style="display:flex;"><span>       piled only as needed.  The source for all of the components can be found
</span></span><span style="display:flex;"><span>       in /usr/share/X11/xkb.
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span>OPTIONS
</span></span><span style="display:flex;"><span>       -compat name
</span></span><span style="display:flex;"><span>               Specifies  the  name  of the compatibility map component used to
</span></span><span style="display:flex;"><span>               construct a keyboard layout.
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span>       -config file
</span></span><span style="display:flex;"><span>               Specifies the name of an XKB configuration file which  describes
</span></span><span style="display:flex;"><span>               the keyboard to be used.
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span>       -device device
</span></span><span style="display:flex;"><span>               Specifies  the  numeric  device id of the input device to be up‐
</span></span><span style="display:flex;"><span>               dated with the new keyboard layout. If not specified,  the  core
</span></span><span style="display:flex;"><span>               keyboard device of the X server is updated.
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span>       -display display
</span></span><span style="display:flex;"><span>               Specifies  the  display to be updated with the new keyboard lay‐
</span></span><span style="display:flex;"><span>               out.
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span>       -geometry name
</span></span><span style="display:flex;"><span>               Specifies the name of the geometry component used to construct a
</span></span><span style="display:flex;"><span>               keyboard layout.
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span>       -help   Prints a message describing the valid input to setxkbmap.
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span>       -I directory
</span></span><span style="display:flex;"><span>               Adds a directory to the list of directories to be used to search
</span></span><span style="display:flex;"><span>               for specified layout or rules files.
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span>       -keycodes name
</span></span><span style="display:flex;"><span>               Specifies the name of the keycodes component used to construct a
</span></span><span style="display:flex;"><span>               keyboard layout.
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span>       -keymap name
</span></span><span style="display:flex;"><span>               Specifies the name of the keymap description used to construct a
</span></span><span style="display:flex;"><span>               keyboard layout.
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span>       -layout name
</span></span><span style="display:flex;"><span>               Specifies the name of the layout used to  determine  the  compo‐
</span></span><span style="display:flex;"><span>               nents which make up the keyboard description. The -layout option
</span></span><span style="display:flex;"><span>               may  only  be  used once. Multiple layouts can be specified as a
</span></span><span style="display:flex;"><span>               comma-separated list.
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span>       -model name
</span></span><span style="display:flex;"><span>               Specifies the name of the keyboard model used to  determine  the
</span></span><span style="display:flex;"><span>               components  which  make  up  the keyboard description.  Only one
</span></span><span style="display:flex;"><span>               model may be specified on the command line.
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span>       -option name
</span></span><span style="display:flex;"><span>               Specifies the name of an  option  to  determine  the  components
</span></span><span style="display:flex;"><span>               which make up the keyboard description;  multiple options may be
</span></span><span style="display:flex;"><span>               specified,  one  per  -option flag. Note that setxkbmap adds op‐
</span></span><span style="display:flex;"><span>               tions specified in the command line to the options that were set
</span></span><span style="display:flex;"><span>               before (as saved in root window properties). If you want to  re‐
</span></span><span style="display:flex;"><span>               place  all  previously  specified  options, use the -option flag
</span></span><span style="display:flex;"><span>               with an empty argument first.
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span>       -print  With this option setxkbmap just prints component names in a for‐
</span></span><span style="display:flex;"><span>               mat acceptable by xkbcomp (an XKB keymap  compiler)  and  exits.
</span></span><span style="display:flex;"><span>               The option can be used for tests instead of a verbose option and
</span></span><span style="display:flex;"><span>               in  cases  when one needs to run both the setxkbmap and the xkb‐
</span></span><span style="display:flex;"><span>               comp in chain (see below).
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span>       -query  With this option setxkbmap just prints the current rules, model,
</span></span><span style="display:flex;"><span>               layout, variant, and options, then exits.
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span>       -rules file
</span></span><span style="display:flex;"><span>               Specifies the name of the rules file used  to  resolve  the  re‐
</span></span><span style="display:flex;"><span>               quested layout and model to a set of component names.
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span>       -symbols name
</span></span><span style="display:flex;"><span>               Specifies  the name of the symbols component used to construct a
</span></span><span style="display:flex;"><span>               keyboard layout.
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span>       -synch  Force synchronization for X requests.
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span>       -types name
</span></span><span style="display:flex;"><span>               Specifies the name of the types component used  to  construct  a
</span></span><span style="display:flex;"><span>               keyboard layout.
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span>       -variant name
</span></span><span style="display:flex;"><span>               Specifies which variant of the keyboard layout should be used to
</span></span><span style="display:flex;"><span>               determine the components which make up the keyboard description.
</span></span><span style="display:flex;"><span>               The -variant option may only be used once. Multiple variants can
</span></span><span style="display:flex;"><span>               be  specified as a comma-separated list and will be matched with
</span></span><span style="display:flex;"><span>               the layouts specified with -layout.
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span>       -verbose|-v [level]
</span></span><span style="display:flex;"><span>               Specifies level of verbosity in output messages.   Valid  levels
</span></span><span style="display:flex;"><span>               range  from 0 (least verbose) to 10 (most verbose).  The default
</span></span><span style="display:flex;"><span>               verbosity level is 5.  If no level  is  specified,  each  -v  or
</span></span><span style="display:flex;"><span>               -verbose flag raises the level by 1.
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span>       -version
</span></span><span style="display:flex;"><span>               Prints the program&#39;s version number.
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span>USING WITH xkbcomp
</span></span><span style="display:flex;"><span>       If you have an Xserver and a client shell running on different computers
</span></span><span style="display:flex;"><span>       and  some  XKB  configuration files on those machines are different, you
</span></span><span style="display:flex;"><span>       can get problems specifying a keyboard map by model, layout, and options
</span></span><span style="display:flex;"><span>       names.  This is because setxkbmap converts its arguments to names of XKB
</span></span><span style="display:flex;"><span>       configuration files according to files that are on the client-side  com‐
</span></span><span style="display:flex;"><span>       puter,  then  sends  these file names to the server where xkbcomp has to
</span></span><span style="display:flex;"><span>       compose a complete keyboard map using files which the server has.   Thus
</span></span><span style="display:flex;"><span>       if the sets of files differ in some way, the names that setxkbmap gener‐
</span></span><span style="display:flex;"><span>       ates can be unacceptable on the server side.  You can solve this problem
</span></span><span style="display:flex;"><span>       by  running  the xkbcomp on the client side too.  With the -print option
</span></span><span style="display:flex;"><span>       setxkbmap just prints the file names in an  appropriate  format  to  its
</span></span><span style="display:flex;"><span>       stdout  and this output can be piped directly to the xkbcomp input.  For
</span></span><span style="display:flex;"><span>       example, the command
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span>       setxkbmap us -print | xkbcomp - $DISPLAY
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span>       makes both steps run on the same (client) machine and loads  a  keyboard
</span></span><span style="display:flex;"><span>       map into the server.
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span>XWAYLAND
</span></span><span style="display:flex;"><span>       Xwayland  is  an  X  server  that  uses a Wayland Compositor as backend.
</span></span><span style="display:flex;"><span>       Xwayland acts as translation layer between the X protocol and  the  Way‐
</span></span><span style="display:flex;"><span>       land protocol but does not manage the keymaps - these are handled by the
</span></span><span style="display:flex;"><span>       Wayland Compositor.
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span>       Changing  the  keymap  with  setxkbmap is not supported by Xwayland.  In
</span></span><span style="display:flex;"><span>       most instances, using setxkbmap on Xwayland is indicative of a bug in  a
</span></span><span style="display:flex;"><span>       shell script and setxkbmap will print a warning. Use the Wayland Compos‐
</span></span><span style="display:flex;"><span>       itor&#39;s native XKB configuration methods instead.
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span>SEE ALSO
</span></span><span style="display:flex;"><span>       xkbcomp(1), xkeyboard-config(7)
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span>FILES
</span></span><span style="display:flex;"><span>       /usr/share/X11/xkb
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span>X Version 11                    setxkbmap 1.3.4                    SETXKBMAP(1)</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>simple examples</p>
<details open>
    <summary>sh</summary><pre
        class="chroma codeblock"
      ><code class="language-sh" data-lang="sh"
          ><span style="display:flex;"><span>setxkbmap -option ctrl:swapcaps <span style="color:#75715e"># swap ctrl and caps</span>
</span></span><span style="display:flex;"><span>setxkbmap -option ctrl:nocaps</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><h4 id="xcape">
  <a class="anchor inpage" href="#xcape">####</a>xcape</h4>
<p><code>xcape</code>: use a modifier as another key.</p>
<details open>
    <summary>man</summary><pre
        class="chroma codeblock"
      ><code class="language-man" data-lang="man"
          ><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span>XCAPE(1)                          xcape Manual                         XCAPE(1)
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span>NAME
</span></span><span style="display:flex;"><span>       xcape - use a modifier key as another key
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span>SYNOPSIS
</span></span><span style="display:flex;"><span>       xcape [-d] [-t timeout] [-e map-expression]
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span>DESCRIPTION
</span></span><span style="display:flex;"><span>       xcape allows a modifier key to be used as another key when it is pressed
</span></span><span style="display:flex;"><span>       and released on its own. The default behaviour is to generate the Escape
</span></span><span style="display:flex;"><span>       key in place of Control_L (Left Control).
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span>OPTIONS
</span></span><span style="display:flex;"><span>       -d     Debug mode.  Will run as a foreground process.
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span>       -t timeout
</span></span><span style="display:flex;"><span>              Give  a  timeout  in milliseconds.  If you hold a key longer than
</span></span><span style="display:flex;"><span>              timeout a key event will not be generated.
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span>       -e map-expression
</span></span><span style="display:flex;"><span>              Use map-expression as the expression(s).
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span>EXPRESSION SYNTAX
</span></span><span style="display:flex;"><span>       Expression syntax is ´ModKey=Key[|OtherKey]´.  Multiple expressions  can
</span></span><span style="display:flex;"><span>       be passed, delimited by semi-colons (;).
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span>       A  list  of  keysyms  can  be found in the header file &lt;X11/keysymdef.h&gt;
</span></span><span style="display:flex;"><span>       (without the XK_ prefix).
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span>       Note that shifted keys must be specified as a shift key followed by  the
</span></span><span style="display:flex;"><span>       key  to be pressed rather than the actual name of the character. For ex‐
</span></span><span style="display:flex;"><span>       ample to generate &#34;{&#34; the expression ´ModKey=Shift_L|bracketleft´  could
</span></span><span style="display:flex;"><span>       be used (assuming that you have a key with ´{´ above ´[´).
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span>       You  can also specify ModKey in decimal (prefix #), octal (#0), or hexa‐
</span></span><span style="display:flex;"><span>       decimal (#0x). It will be interpreted as a keycode unless no correspond‐
</span></span><span style="display:flex;"><span>       ing key name is found.
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span>EXAMPLES
</span></span><span style="display:flex;"><span>       Make Left Shift generate Escape when pressed and released on  it&#39;s  own,
</span></span><span style="display:flex;"><span>       and  Left  Control generate Ctrl-O combination when pressed and released
</span></span><span style="display:flex;"><span>       on it&#39;s own:
</span></span><span style="display:flex;"><span>              xcape -e &#39;Shift_L=Escape;Control_L=Control_L|O&#39;
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span>       In conjugation with xmodmap it is possible to make an ordinary  key  act
</span></span><span style="display:flex;"><span>       as an extra modifier. First map the key to the modifier with xmodmap and
</span></span><span style="display:flex;"><span>       then the modifier back to the key with xcape. As an example, we can make
</span></span><span style="display:flex;"><span>       the  space bar work as an additional ctrl key when held with the follow‐
</span></span><span style="display:flex;"><span>       ing sequence of commands:
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span>       First, map an unused modifier&#39;s keysym to  the  spacebar&#39;s  keycode  and
</span></span><span style="display:flex;"><span>       make it a control modifier. It needs to be an existing key so that emacs
</span></span><span style="display:flex;"><span>       won&#39;t spazz out when you press it. Hyper_L is a good candidate.
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span>              spare_modifier=&#34;Hyper_L&#34;
</span></span><span style="display:flex;"><span>              xmodmap -e &#34;keycode 65 = $spare_modifier&#34;
</span></span><span style="display:flex;"><span>              xmodmap -e &#34;remove mod4 = $spare_modifier&#34;
</span></span><span style="display:flex;"><span>              # hyper_l is mod4 by default
</span></span><span style="display:flex;"><span>              xmodmap -e &#34;add Control = $spare_modifier&#34;
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span>       Next,  map  space  to  an unused keycode (to keep it around for xcape to
</span></span><span style="display:flex;"><span>       use).
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span>              xmodmap -e &#34;keycode any = space&#34;
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span>       Finally use xcape to cause the  space  bar  to  generate  a  space  when
</span></span><span style="display:flex;"><span>       tapped.
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span>              xcape -e &#34;$spare_modifier=space&#34;</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>example</p>
<details open>
    <summary>sh</summary><pre
        class="chroma codeblock"
      ><code class="language-sh" data-lang="sh"
          ><span style="display:flex;"><span>xcape -e <span style="color:#e6db74">&#39;Alt_L=Escape&#39;</span> <span style="color:#75715e"># Escape when tap, ALt when hold</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><h4 id="example">
  <a class="anchor inpage" href="#example">####</a>example</h4>
<p>for example, <kbd>caps</kbd> as <kbd>escape</kbd> and <kbd>ctrl</kbd></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"># I usually use following</span>
</span></span><span style="display:flex;"><span>setxkbmap -option <span style="color:#e6db74">&#39;caps:ctrl_modifier&#39;</span> <span style="color:#75715e"># caps become ctrl</span>
</span></span><span style="display:flex;"><span>xcape -e <span style="color:#e6db74">&#39;Caps_Lock=Escape&#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="wayland">
  <a class="anchor inpage" href="#wayland">###</a>wayland</h3>
<p>似乎暂时只有KDE Gnome的环境里还有改的方法</p>
<h3 id="console">
  <a class="anchor inpage" href="#console">###</a>console</h3>
<p>
</p>
<h3 id="keyd">
  <a class="anchor inpage" href="#keyd">###</a>keyd</h3>
<p>
， inspired by via</p>
<p>这个厉害，tty, X11, wayland都能用，而且能实现很强的配置效果。</p>
<details open>
    <summary>tldr</summary><pre
        class="codeblock"
      ><code class="language-tldr" data-lang="tldr">
  Remap keys.
  More information: &lt;https://manned.org/keyd&gt;.

  Start and enable the `keyd` service:

      systemctl enable keyd --now

  Display keypress information:

      sudo keyd monitor

  Reset bindings and reload the configuration files in `/etc/keyd`:

      sudo keyd reload

  List all valid key names:

      keyd list-keys

  Create a temporary binding:

      sudo keyd bind &#34;pressed_key = output_key&#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>Other software:</p>
<ul>
<li>interception-tools with plugins
<ul>
<li>dual-function-keys (like Mod-Tap feature of zmk and qmk)</li>
<li>caps2esc</li>
<li>space2meta</li>
</ul>
</li>
</ul>
<h2 id="ref">
  <a class="anchor inpage" href="#ref">##</a>ref</h2>
<p>
</p>
]]></content:encoded></item><item><title>My Neovim Config</title><link>https://hiraethecho.github.io/docs/software/nvim-config/</link><pubDate>Mon, 18 Nov 2024 00:00:00 +0000</pubDate><author>wyz2016zxc@outlook.com(Hiraeth)</author><guid>https://hiraethecho.github.io/docs/software/nvim-config/</guid><description>&lt;h1 id="my-neovim"&gt;
&lt;a class="anchor inpage" href="#my-neovim"&gt;#&lt;/a&gt;My neovim&lt;/h1&gt;
&lt;p&gt;My
on github.&lt;/p&gt;
&lt;p&gt;There is a
of my config, for fun.&lt;/p&gt;
&lt;p&gt;I&amp;rsquo;m using nvim as a code editor, mainly for latex and markdown.&lt;/p&gt;
&lt;h2 id="usage"&gt;
&lt;a class="anchor inpage" href="#usage"&gt;##&lt;/a&gt;Usage&lt;/h2&gt;
&lt;h3 id="latex"&gt;
&lt;a class="anchor inpage" href="#latex"&gt;###&lt;/a&gt;latex&lt;/h3&gt;
&lt;p&gt;using vimtex to detect math environment, and texlab lsp to complie.&lt;/p&gt;
&lt;p&gt;&lt;del&gt;cmp&lt;/del&gt; blink.cmp and &lt;del&gt;ultisnips&lt;/del&gt; luasnip to enhance editing.&lt;/p&gt;
&lt;p&gt;check
.&lt;/p&gt;
&lt;h3 id="markdown"&gt;
&lt;a class="anchor inpage" href="#markdown"&gt;###&lt;/a&gt;markdown&lt;/h3&gt;
&lt;p&gt;mkdnflow to enhance.&lt;/p&gt;
&lt;p&gt;&lt;del&gt;&lt;kbd&gt;leader&lt;/kbd&gt;&lt;kbd&gt;m&lt;/kbd&gt;&lt;kbd&gt;p&lt;/kbd&gt; to open markdown-preview&lt;/del&gt; This is not necessary. Just render it in the terminal.&lt;/p&gt;
&lt;h2 id="detail-configure"&gt;
&lt;a class="anchor inpage" href="#detail-configure"&gt;##&lt;/a&gt;Detail Configure&lt;/h2&gt;
&lt;h3 id="options"&gt;
&lt;a class="anchor inpage" href="#options"&gt;###&lt;/a&gt;options&lt;/h3&gt;
&lt;p&gt;in /lua/config/options.lua&lt;/p&gt;</description><content:encoded><![CDATA[<h1 id="my-neovim">
  <a class="anchor inpage" href="#my-neovim">#</a>My neovim</h1>
<p>My 
 on github.</p>
<p>There is a 
 of my config, for fun.</p>
<p>I&rsquo;m using nvim as a code editor, mainly for latex and markdown.</p>
<h2 id="usage">
  <a class="anchor inpage" href="#usage">##</a>Usage</h2>
<h3 id="latex">
  <a class="anchor inpage" href="#latex">###</a>latex</h3>
<p>using vimtex to detect math environment, and texlab lsp to complie.</p>
<p><del>cmp</del> blink.cmp and <del>ultisnips</del> luasnip to enhance editing.</p>
<p>check 
.</p>
<h3 id="markdown">
  <a class="anchor inpage" href="#markdown">###</a>markdown</h3>
<p>mkdnflow to enhance.</p>
<p><del><kbd>leader</kbd><kbd>m</kbd><kbd>p</kbd> to open markdown-preview</del> This is not necessary. Just render it in the terminal.</p>
<h2 id="detail-configure">
  <a class="anchor inpage" href="#detail-configure">##</a>Detail Configure</h2>
<h3 id="options">
  <a class="anchor inpage" href="#options">###</a>options</h3>
<p>in /lua/config/options.lua</p>
<h3 id="lsp">
  <a class="anchor inpage" href="#lsp">###</a>lsp</h3>
<p>Config lsp by native nvim. Steal serval functions from nvim-lspconfig.</p>
<h3 id="plugins">
  <a class="anchor inpage" href="#plugins">###</a>plugins</h3>
<p>I am using lazy.nvim as my plugins manager. Plugins are divided in serval
classes, and following are some of mostly used plugins:</p>
<ul>
<li>edit: enhance for editing
<ul>
<li><del>
,</del></li>
<li>
</li>
<li>
,</li>
<li>
, gJ and gK to split or joint</li>
<li>treej</li>
<li>
, 中文输入自动切换</li>
<li>
,</li>
<li><del>
</del> zen mode, focus on editing 
</li>
<li>
, like a temporary git</li>
<li>
, translate words</li>
<li>
, jump anywhere</li>
<li><del>
,</del></li>
<li><del>
, commute ultisnips with cmp</del></li>
<li><del>
, lsp source</del></li>
<li><del>
, source from other buffers</del></li>
<li><del>
, path source</del></li>
<li>
</li>
<li>
, snippets</li>
<li>
, copilot source</li>
</ul>
</li>
<li>editor: enhance for latex and markdown
<ul>
<li>
, for latex</li>
<li>
, preview md in browser</li>
<li>
</li>
<li><del>
,</del> render md in nvim</li>
<li>
, help edit list, table etc in nvim</li>
</ul>
</li>
<li>git: using git in nvim
<ul>
<li>
, show git status at left, jump by hunks</li>
<li>
, show diff with history files</li>
<li>neogit</li>
</ul>
</li>
<li>lsp:
<ul>
<li><del>
, Configure lsp</del></li>
<li><del>
, install lsp</del></li>
<li><del>
, jump by definitions, references etc</del></li>
<li>
, jump by symbols etc</li>
</ul>
</li>
<li>file explorer:
<ul>
<li><del>
, file tree</del></li>
<li>
, yazi (tui file manager) in float terminal</li>
<li>snacks.picker.explorer, part of 
</li>
<li>
</li>
</ul>
</li>
<li>fuzzy finder
<ul>
<li><del>
,</del></li>
<li>snacks.picker, part of 
</li>
</ul>
</li>
<li>ui:
<ul>
<li>
, my theme</li>
<li>
, show color like <code>#123dfe</code></li>
<li>
, modeline, bufferline etc</li>
<li>
, show indent line etc</li>
</ul>
</li>
<li>enhance native functions:
<ul>
<li>
, plugin manager</li>
<li>
, <code>:</code> cmd and <code>/</code> search</li>
<li>
, show leader key sequence</li>
<li>
, search and replace</li>
<li>
, show start up time</li>
<li>
, sudo write files</li>
</ul>
</li>
</ul>
<h2 id="miscellanea">
  <a class="anchor inpage" href="#miscellanea">##</a>miscellanea</h2>
]]></content:encoded></item><item><title>安装后的建议配置</title><link>https://hiraethecho.github.io/docs/linux/archpostinstall/</link><pubDate>Mon, 18 Nov 2024 00:00:00 +0000</pubDate><author>wyz2016zxc@outlook.com(Hiraeth)</author><guid>https://hiraethecho.github.io/docs/linux/archpostinstall/</guid><description>archlinux安装后的建议配置，新建用户，软件等</description><content:encoded><![CDATA[<h1 id="安装后的建议配置">
  <a class="anchor inpage" href="#%e5%ae%89%e8%a3%85%e5%90%8e%e7%9a%84%e5%bb%ba%e8%ae%ae%e9%85%8d%e7%bd%ae">#</a>安装后的建议配置</h1>
<blockquote class="alert alert-important">
      <p class="alert-heading">IMPORTANT</p><p></p></blockquote><h2 id="add-user">
  <a class="anchor inpage" href="#add-user">##</a>add user</h2>
<p>添加用户并设置密码</p>
<details open>
    <summary>sh</summary><pre
        class="chroma codeblock"
      ><code class="language-sh" data-lang="sh"
          ><span style="display:flex;"><span>useradd -m USERNAME
</span></span><span style="display:flex;"><span>passwd USERNAME</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>可以将用户家目录设置成btrfs的子卷，这样可以更好的管理快照。</p>
<details open>
    <summary>TEXT</summary><pre
        class="codeblock"
      ><code class="language-" data-lang="">useradd -m --btrfs-subvolume-home USERNAME</code><button onclick="copyCode(this)" class="copybtn">copy</button></pre></details>

  <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>添加用户到wheel组：</p>
<details open>
    <summary>TEXT</summary><pre
        class="codeblock"
      ><code class="language-" data-lang="">usermod -aG wheel USERNAME</code><button onclick="copyCode(this)" class="copybtn">copy</button></pre></details>

  <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="">useradd -m -G wheel USERNAME</code><button onclick="copyCode(this)" class="copybtn">copy</button></pre></details>

  <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>wheel</code>组的用户可以使用<code>sudo</code>，需要编辑<code>/etc/sudoers</code>文件，可以使用<code>visudo</code>命令，如果环境变量没有指定默认编辑器，会提示选择，选择一个之后会进入文件编辑界面。或者使用</p>
<details open>
    <summary>TEXT</summary><pre
        class="codeblock"
      ><code class="language-" data-lang="">EDITOR=nvim visudo</code><button onclick="copyCode(this)" class="copybtn">copy</button></pre></details>

  <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=""># %wheel ALL=(ALL:ALL)</code><button onclick="copyCode(this)" class="copybtn">copy</button></pre></details>

  <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="package-managerment">
  <a class="anchor inpage" href="#package-managerment">##</a>Package managerment</h2>
<p>换源：</p>
<details open>
    <summary>TEXT</summary><pre
        class="codeblock"
      ><code class="language-" data-lang=""># /etc/pacman.d/mirrorlist
Server = https://mirrors.tuna.tsinghua.edu.cn/archlinux/$repo/os/$arch</code><button onclick="copyCode(this)" class="copybtn">copy</button></pre></details>

  <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>archlinuxcn</code>仓库。在 <code>/etc/pacman.conf</code>中添加</p>
<details open>
    <summary>text</summary><pre
        class="chroma codeblock"
      ><code class="language-text" data-lang="text"
          ><span style="display:flex;"><span>[archlinuxcn]
</span></span><span style="display:flex;"><span>Server = https://mirrors.tuna.tsinghua.edu.cn/archlinuxcn/$arch</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>更新keyring</p>
<details open>
    <summary>TEXT</summary><pre
        class="codeblock"
      ><code class="language-" data-lang="">pacman -Sy archlinux-keyring
pacman -Sy archlinuxcn-keyring</code><button onclick="copyCode(this)" class="copybtn">copy</button></pre></details>

  <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="">pacman -Syyu</code><button onclick="copyCode(this)" class="copybtn">copy</button></pre></details>

  <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>archlinuxcn</code>中有aur-helper，比如</p>
<details open>
    <summary>TEXT</summary><pre
        class="codeblock"
      ><code class="language-" data-lang="">pacman -S paru</code><button onclick="copyCode(this)" class="copybtn">copy</button></pre></details>

  <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>clean pacman:</p>
<details open>
    <summary>sh</summary><pre
        class="chroma codeblock"
      ><code class="language-sh" data-lang="sh"
          ><span style="display:flex;"><span>paccache -r <span style="color:#75715e"># 清理缓存,仅包含最近的三个版本</span>
</span></span><span style="display:flex;"><span>paccache -rk1 <span style="color:#75715e"># 清理缓存,仅包含最近的1个版本</span>
</span></span><span style="display:flex;"><span>pacman -Sc <span style="color:#75715e"># 清理未安装软件包</span>
</span></span><span style="display:flex;"><span>pacman -Scc <span style="color:#75715e"># 清理缓存中所有内容</span>
</span></span><span style="display:flex;"><span>sudo pacman -Rcsn <span style="color:#66d9ef">$(</span>pacman -Qdtq -<span style="color:#66d9ef">)</span>
</span></span><span style="display:flex;"><span>journalctl --vacuum-size<span style="color:#f92672">=</span>50M <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><h2 id="基础功能">
  <a class="anchor inpage" href="#%e5%9f%ba%e7%a1%80%e5%8a%9f%e8%83%bd">##</a>基础功能</h2>
<h3 id="网络">
  <a class="anchor inpage" href="#%e7%bd%91%e7%bb%9c">###</a>网络</h3>
<p>启动服务，<code>iwd</code>是连接网络的，自带域名解析。需要</p>
<details open>
    <summary>TEXT</summary><pre
        class="codeblock"
      ><code class="language-" data-lang=""># /etc/iwd/main.conf
[General]
EnableNetworkConfiguration=true</code><button onclick="copyCode(this)" class="copybtn">copy</button></pre></details>

  <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>dhcpcd</code>解析</p>
<details open>
    <summary>TEXT</summary><pre
        class="codeblock"
      ><code class="language-" data-lang="">systemctl enable dhcpcd</code><button onclick="copyCode(this)" class="copybtn">copy</button></pre></details>

  <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>tui: <code>impala</code></p>
<p>或者用<code>networkmanager</code></p>
<p>Using iwd as backend of NetworkManager, <code>/etc/NetworkManager/NetworkManager.conf</code></p>
<details open>
    <summary>TEXT</summary><pre
        class="codeblock"
      ><code class="language-" data-lang="">[device]
wifi.backend=iwd</code><button onclick="copyCode(this)" class="copybtn">copy</button></pre></details>

  <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>then</p>
<details open>
    <summary>sh</summary><pre
        class="chroma codeblock"
      ><code class="language-sh" data-lang="sh"
          ><span style="display:flex;"><span>systemctl mask wpa_supplicant
</span></span><span style="display:flex;"><span>systemctl enable iwd</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="sound">
  <a class="anchor inpage" href="#sound">###</a>sound</h3>
<ul>
<li>ALSA: is a set of built-in Linux kernel modules.</li>
<li>PulseAudio: is a general purpose sound server intended to run as a middleware between your applications and your hardware devices, either using ALSA or OSS.</li>
<li>pamixer: cli mixer of PulseAudio</li>
<li>pavucontrol: gui of PulseAudio</li>
</ul>
<details open>
    <summary>TEXT</summary><pre
        class="codeblock"
      ><code class="language-" data-lang="">sudo pacman -S alsa-ultis pulseaudio pavucontrol
pulseaudio --check
pulseaudio -D</code><button onclick="copyCode(this)" class="copybtn">copy</button></pre></details>

  <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="light">
  <a class="anchor inpage" href="#light">###</a>light</h3>
<p><code>video</code>组的用户可以控制亮度</p>
<details open>
    <summary>sh</summary><pre
        class="chroma codeblock"
      ><code class="language-sh" data-lang="sh"
          ><span style="display:flex;"><span>sudo pacman -S acpilight
</span></span><span style="display:flex;"><span>sudo gpasswd video -a _username_ <span style="color:#75715e"># 或者</span>
</span></span><span style="display:flex;"><span>sudo usermod -aG video _username_</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="bluetooth">
  <a class="anchor inpage" href="#bluetooth">###</a>bluetooth</h3>
<p>蓝牙耳机需要<code>pulseaudio-bluetooth</code>和<code>bluez-utils</code>。</p>
<details open>
    <summary>TEXT</summary><pre
        class="codeblock"
      ><code class="language-" data-lang="">sudo systemctl enable bluetooth.service --now</code><button onclick="copyCode(this)" class="copybtn">copy</button></pre></details>

  <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>tui: <code>bluetui</code></p>
<h3 id="input">
  <a class="anchor inpage" href="#input">###</a>input</h3>
<p>在<code>X11</code>中需要安装<code>xf86-input-libinput</code>等</p>
<p>To find id of touchpad</p>
<details open>
    <summary>TEXT</summary><pre
        class="codeblock"
      ><code class="language-" data-lang="">xinput list | grep -i &#34;Touchpad&#34; | awk &#39;{print $6}&#39; | sed &#39;s/[^0-9]//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>keys:</p>
<details open>
    <summary>sh</summary><pre
        class="chroma codeblock"
      ><code class="language-sh" data-lang="sh"
          ><span style="display:flex;"><span>setxkbmap -option ctrl:nocaps &amp;
</span></span><span style="display:flex;"><span>xcape -e <span style="color:#e6db74">&#39;Control_L=Return&#39;</span> &amp;
</span></span><span style="display:flex;"><span>xcape -e <span style="color:#e6db74">&#39;Alt_L=Escape&#39;</span> &amp;</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="battery">
  <a class="anchor inpage" href="#battery">###</a>battery</h3>
<details open>
    <summary>TEXT</summary><pre
        class="codeblock"
      ><code class="language-" data-lang="">upower -e

/org/freedesktop/UPower/devices/line_power_ACAD
/org/freedesktop/UPower/devices/battery_BAT1
/org/freedesktop/UPower/devices/DisplayDevice</code><button onclick="copyCode(this)" class="copybtn">copy</button></pre></details>

  <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>check battery <code>sudo upower -i /org/freedesktop/UPower/devices/battery_BAT1 </code></p>
<h3 id="driver">
  <a class="anchor inpage" href="#driver">###</a>driver</h3>
<p>for amd integrated, open source driver:</p>
<details open>
    <summary>TEXT</summary><pre
        class="codeblock"
      ><code class="language-" data-lang="">sudo pacman -S mesa lib32-mesa xf86-video-amdgpu vulkan-radeon lib32-vulkan-radeon</code><button onclick="copyCode(this)" class="copybtn">copy</button></pre></details>

  <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="desktop-environment">
  <a class="anchor inpage" href="#desktop-environment">##</a>Desktop Environment</h2>
<p>
</p>
<h3 id="成品桌面环境">
  <a class="anchor inpage" href="#%e6%88%90%e5%93%81%e6%a1%8c%e9%9d%a2%e7%8e%af%e5%a2%83">###</a>成品桌面环境</h3>
<ul>
<li>
</li>
<li>
</li>
<li>
</li>
<li>
</li>
</ul>
<h3 id="components">
  <a class="anchor inpage" href="#components">###</a>components</h3>
<p>At least one need</p>
<ul>
<li>window manager or 
</li>
<li>
</li>
</ul>
<p>Usually also need:</p>
<ul>
<li>
</li>
<li>
).</li>
<li>
</li>
<li>
</li>
<li>
</li>
<li>
</li>
<li>
</li>
</ul>
<p>Other components usually provided by desktop environments are:</p>
<ul>
<li>
</li>
<li>
</li>
<li>
</li>
<li>
</li>
<li>
</li>
<li>
</li>
<li>
</li>
<li>
</li>
<li>
</li>
<li>
</li>
<li>
</li>
</ul>
<h3 id="utils">
  <a class="anchor inpage" href="#utils">###</a>utils</h3>
<p><code>filedialog</code> 是其他应用需要选择文件时的弹窗。通常需要一些<code>xdg-desktop-portal</code>，不同的包有不同的
。</p>
<h3 id="x11">
  <a class="anchor inpage" href="#x11">###</a>X11</h3>
<p><code>Xlibre</code> <code>wayback</code></p>
<h3 id="wayland">
  <a class="anchor inpage" href="#wayland">###</a>wayland</h3>
<p>gnome, kde</p>
<p>niri, hyprland, sway, river, wayfire,</p>
<h2 id="applications">
  <a class="anchor inpage" href="#applications">##</a>Applications</h2>
<h3 id="shell-and-terminal">
  <a class="anchor inpage" href="#shell-and-terminal">###</a>shell and terminal</h3>
<h3 id="steam">
  <a class="anchor inpage" href="#steam">###</a>steam:</h3>
<details open>
    <summary>TEXT</summary><pre
        class="codeblock"
      ><code class="language-" data-lang="">id -u
id -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>mount:</p>
<details open>
    <summary>TEXT</summary><pre
        class="codeblock"
      ><code class="language-" data-lang="">sudo mkdir /media/gamedisk</code><button onclick="copyCode(this)" class="copybtn">copy</button></pre></details>

  <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=""># /etc/fstab
UUID=38CE9483CE943AD8 /media/gamedisk lowntfs-3g uid=1000,gid=1000,rw,user,exec,umask=000 0 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><p>debug:</p>
<details open>
    <summary>TEXT</summary><pre
        class="codeblock"
      ><code class="language-" data-lang="">mkdir -p ~/.steam/steam/steamapps/compatdata
ln -s ~/.steam/steam/steamapps/compatdata /media/gamedisk/Steam/steamapps/</code><button onclick="copyCode(this)" class="copybtn">copy</button></pre></details>

  <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="wechat">
  <a class="anchor inpage" href="#wechat">###</a>wechat</h3>
<p>微信使用fcitx输入法会有一些问题，似乎是不能正常读取环境变量。修改<code>/usr/share/applications/wechat.desktop</code>来设定变量。有可能在更新后被覆盖，或许可以放在<code>~/.local/share/applications/wechat.desktop</code>中。</p>
<details open>
    <summary>TEXT</summary><pre
        class="codeblock"
      ><code class="language-" data-lang="">[Desktop Entry]
Name=wechat
Name[zh_CN]=微信
Exec=env XMODIFIERS=&#34;@im=fcitx&#34; GTK_IM_MODULE=&#34;fcitx&#34; QT_IM_MODULE=&#34;fcitx&#34; /usr/bin/wechat %U
StartupNotify=true
Terminal=false
Icon=/opt/wechat/icons/wechat.png
Type=Application
Categories=Utility;
Comment=Wechat Desktop
Comment[zh_CN]=微信桌面版</code><button onclick="copyCode(this)" class="copybtn">copy</button></pre></details>

  <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>折腾的linux+X11+dwm</title><link>https://hiraethecho.github.io/docs/project/dwm/</link><pubDate>Mon, 29 Jul 2024 00:00:00 +0000</pubDate><author>wyz2016zxc@outlook.com(Hiraeth)</author><guid>https://hiraethecho.github.io/docs/project/dwm/</guid><description>关于linux C dwm等</description><content:encoded><![CDATA[<h1 id="近期折腾的archlinux">
  <a class="anchor inpage" href="#%e8%bf%91%e6%9c%9f%e6%8a%98%e8%85%be%e7%9a%84archlinux">#</a>近期折腾的archlinux</h1>
<p>也算是一些业余学习吧。先叠个甲，业余学习所以可能有错误，只是个人理解。</p>
<h2 id="linux">
  <a class="anchor inpage" href="#linux">##</a>linux</h2>
<p>linux内核的功能是调用硬件，为程序分配使用<br>
GNU is not unix. 在斯托曼的组织下，为了取代unix开发了一系列自由软件，但是没有内核，用了linus的内核。<br>
shell是包裹在内核外面的外壳，用来和内核沟通。并且有POSIX的shell标准，来规范shell的语言。常见的shell有<code>bash</code> <code>zsh</code>等。而另一个常见的<code>fish</code>不符合POSIX.<br>
Terminal是使用shell的界面。最基础的terminal就是tty，是过去计算机的一个物理部件（console控制台是另一个过去的物理部件，直接控制机器。tty是<em>远程</em>的控制方式。）常见的terminal有alacritty、kitty和各大桌面环境配套的。</p>
<p>linux的哲学之一在于，每一个程序只做一件事，并努力做到最好。像word这样的windows应用，常被认为是臃肿的，“每个人只用到了全部功能的1%
”。但这是因为“每个人用的都是不同的1%”。然而在linux的世界里，为了自己需要的那1%，通常只需要安装对应的那1%。当然，困难之处在于在广大社区中找到对应的程序，并且使自己所需要的各种程序和谐共存互相协调。</p>
<p>GNU/linux有各种发行版，虽然个人感到主要区别在包管理器和预装软件。包管理器的其中一个功能就是尽量保证各个程序可以互相协调，自动解决程序的依赖等问题。至于预装软件可能是发行版制作者的个人倾向。<br>
BTW，I use arch.</p>
<p>Arch发行版是一个Geek风格的linux发行版，目的在于用户尽可能自由配置自己的linux（当然似乎比不上Gentoo甚至lfs）。它有两个特点，其一是滚动更新，即没有稳定版本，总可以获得最新的软件版本。好处是获得最新功能，第一时间获得已知bug的修复；坏处是，也可以第一时间获得bug，以及面临软件之间版本不兼容的问题（这也是linux哲学的负面影响）。第二个特点是AUR，既用户仓库。每个发行版的包管理器通常有对应的软件源，而arch除了官方软件源外还有用户仓库，即每个用户都可以把应用按照规范打包供他人使用。优点在于AUR里什么都有，缺点在于很多应用无人负责或没有充分维护。</p>
<h2 id="图形化界面x11">
  <a class="anchor inpage" href="#%e5%9b%be%e5%bd%a2%e5%8c%96%e7%95%8c%e9%9d%a2x11">##</a>图形化界面X11</h2>
<p>为了在tty外情景使用linux，需要图形化界面。</p>
<p>X11是linux的一个图形化界面的协议，每个图形化程序并不是靠它自己显示画面，而是通过协议用Xorg来创建图形的。除此之外还有混成器（例如picom）来提供一些画面特效等。wayland是另一套图形化方案，本身替代了Xorg和混成器的功能。</p>
<p>linux下的桌面环境（Desktop Environment），如KDE GNOME Xfce等，提供了一整套日常使用的基本功能，例如窗口管理，应用启动器，托盘，设置，蓝牙，网络等。但事实上如果追求极简，那么仅仅使用窗口管理器（Windows Manager）也是可行的。</p>
<p>Windows Manager，通俗的解释，就是显示应用程序的窗口，并且拖动、调整大小、最大化等功能的部分，不包括壁纸、声音网络蓝牙键盘触摸板等设置、应用启动器和托盘。<br>
常见的独立窗口管理器包括i3，openbox，awesome等。而我选择的是dwm，属于suckless系列，用C语言编写，代码仅2000余行，更改配置需要修改源码重新编译，添加功能是通过.diff文件打补丁实现。</p>
<h2 id="dwm和c">
  <a class="anchor inpage" href="#dwm%e5%92%8cc">##</a>dwm和C</h2>
<p>这几周时间一直在加强的我dwm，被迫学习了C语言的使用，以及基于lazygit的自娱自乐式历史管理。</p>
<p>C语言是面向过程的，以函数为中心的。但实际写dwm代码的时候，则主要用“面向对象”的思路在写。对象里的函数和变量是用指针或者全局变量，实现地很曲折。</p>
<p>C语言算是很底层的编程语言了，指针可能是其最重要的特性。指针直接指向变量的存储地址，非常有趣。在函数调用时，传参传指针进去，可以直接在物理存贮的意义上理解程序是如何使用和修改变量的值的。另外还有位运算，也很有趣。</p>
<p>C语言同时还是非常省内存（这里应该指的是内存吗？）的语言，每次写一个新变量都小心翼翼地。遥想大一学C语言的时候，还要注意变量要在代码块之前先声明，开个动态数组都麻烦的一匹，用完还要free掉。后来看见其他语言随便新建变量，太难接受了。不过这种节省也导致一些逆天的feature.例如一个结构体</p>
<details open>
    <summary>C</summary><pre
        class="chroma codeblock"
      ><code class="language-C" data-lang="C"
          ><span style="display:flex;"><span><span style="color:#66d9ef">typedef</span> <span style="color:#66d9ef">struct</span> {
</span></span><span style="display:flex;"><span>    <span style="color:#66d9ef">int</span> i;
</span></span><span style="display:flex;"><span>    <span style="color:#66d9ef">float</span> f;
</span></span><span style="display:flex;"><span>} Arg1;</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>那么一个Arg就会有两个成员。但是还有一种操作</p>
<details open>
    <summary>C</summary><pre
        class="chroma codeblock"
      ><code class="language-C" data-lang="C"
          ><span style="display:flex;"><span><span style="color:#66d9ef">typedef</span> <span style="color:#66d9ef">union</span> {
</span></span><span style="display:flex;"><span>    <span style="color:#66d9ef">int</span> i;
</span></span><span style="display:flex;"><span>    <span style="color:#66d9ef">float</span> f;
</span></span><span style="display:flex;"><span>    <span style="color:#66d9ef">void</span> <span style="color:#f92672">*</span>v;
</span></span><span style="display:flex;"><span>} Arg2;</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>union</code>的意思是，<code>Arg2</code>只能有一个类型。当创建一个<code>Arg1 a1</code>时，会给 <code>a1.i</code>和<code>a1.f</code>都分配地址。但是<code>Arg2 a2</code>就只有一个地址，当用了<code>a2.i=1</code>之后就不能再赋值<code>a2.f</code>了。这样如果不同函数的输入一个是<code>int</code>另一个是<code>float</code>，那就可以都写成<code>Arg2</code>，十分优雅。但是需要复杂功能是就很难用。<br>
除此之外，这个<code>void *v</code>也是个奇妙的用法，只要用上强制类型转换<code>Client *c=(Client *)v</code>就可以很灵活的使用各种类型的变量了。</p>
<h2 id="">
  <a class="anchor inpage" href="#">##</a></h2>
<p>最后，可以在我的
找到我的dotfiles和dwm。还没有整理，也没文档，以后有时间心情再说吧。</p>
<h2 id="tabbed-scratchpad">
  <a class="anchor inpage" href="#tabbed-scratchpad">##</a>tabbed scratchpad</h2>
<p><code>st -c class -n name</code> with <code>precmd () {print -Pn &quot;\e]0;%~\a&quot;}</code> in <code>.zshrc</code></p>
<details open>
    <summary>TEXT</summary><pre
        class="codeblock"
      ><code class="language-" data-lang="">_NET_WM_ICON_NAME(UTF8_STRING) = &#34;~&#34;
WM_ICON_NAME(UTF8_STRING) = &#34;~&#34;
WM_CLASS(STRING) = &#34;name&#34;, &#34;class&#34;
_NET_WM_NAME(UTF8_STRING) = &#34;~&#34;
WM_NAME(UTF8_STRING) = &#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>tabbed -n &quot;scratchpad&quot; -c -r 2 st -w '' -g 150x40 -c class -n name</code> with <code>precmd () {print -Pn &quot;\e]0;%~\a&quot;}</code> in <code>.zshrc</code></p>
<details open>
    <summary>TEXT</summary><pre
        class="codeblock"
      ><code class="language-" data-lang="">WM_NAME(UTF8_STRING) = &#34;~&#34;
_NET_WM_NAME(UTF8_STRING) = &#34;~&#34;
WM_CLASS(STRING) = &#34;scratchpad&#34;, &#34;tabbed&#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><strong>summary</strong>: In <code>WM_CLASS(STRING)=&quot;name&quot;,&quot;class&quot;</code>, <code>&quot;name&quot;</code> is for <code>st -n name</code> and <code>tabbed -n name</code>, and is also <code>instance</code> in <code>rules</code>; <code>class</code> is for <code>st -c class</code>, and class of <code>tabbed</code> is always <code>tabbed</code>.</p>
<p>origin <code>manage()</code>:</p>
<details open>
    <summary>TEXT</summary><pre
        class="codeblock"
      ><code class="language-" data-lang="">  selmon-&gt;tagset[selmon-&gt;seltags] &amp;= ~scratchtag;
  if (!strcmp(c-&gt;name, scratchpadname)) {
    c-&gt;mon-&gt;tagset[c-&gt;mon-&gt;seltags] |= c-&gt;tags = scratchtag;
    c-&gt;isfloating = True;
  }</code><button onclick="copyCode(this)" class="copybtn">copy</button></pre></details>

  <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>we can modify to</p>
<details open>
    <summary>TEXT</summary><pre
        class="codeblock"
      ><code class="language-" data-lang="">void manage(Window w, XWindowAttributes *wa) {
  Client *c, *t = NULL;
&#43; XClassHint ch = {NULL, NULL};
&#43; const char *class, *instance;
    ...
&#43; XGetClassHint(dpy, c-&gt;win, &amp;ch);
&#43;  instance = ch.res_name ? ch.res_name : broken;
  selmon-&gt;tagset[selmon-&gt;seltags] &amp;= ~scratchtag;
~ if (!strcmp(instance, scratchpadname)) {
    c-&gt;mon-&gt;tagset[c-&gt;mon-&gt;seltags] |= c-&gt;tags = scratchtag;
    c-&gt;isfloating = True;
  }
}</code><button onclick="copyCode(this)" class="copybtn">copy</button></pre></details>

  <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>btw, <code>apply_rules</code>:</p>
<details open>
    <summary>TEXT</summary><pre
        class="codeblock"
      ><code class="language-" data-lang="">  XGetClassHint(dpy, c-&gt;win, &amp;ch);
  class = ch.res_class ? ch.res_class : broken;
  instance = ch.res_name ? ch.res_name : broken;

  for (i = 0; i &lt; LENGTH(rules); i&#43;&#43;) {
    r = &amp;rules[i];
    if ((!r-&gt;title || strstr(c-&gt;name, r-&gt;title)) &amp;&amp;
        (!r-&gt;class || strstr(class, r-&gt;class)) &amp;&amp;
        (!r-&gt;instance || strstr(instance, r-&gt;instance))) {
      c-&gt;isfloating = r-&gt;isfloating;
      c-&gt;tags |= r-&gt;tags;
      c-&gt;opacity = r-&gt;opacity;
      c-&gt;unfocusopacity = r-&gt;unfocusopacity;
      for (m = mons; m &amp;&amp; m-&gt;num != r-&gt;monitor; m = m-&gt;next) ;
      if (m)
        c-&gt;mon = m;
    }
  }</code><button onclick="copyCode(this)" class="copybtn">copy</button></pre></details>

  <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>zotero</title><link>https://hiraethecho.github.io/docs/software/zotero/</link><pubDate>Mon, 13 Nov 2023 00:00:00 +0000</pubDate><author>wyz2016zxc@outlook.com(Hiraeth)</author><guid>https://hiraethecho.github.io/docs/software/zotero/</guid><description>&lt;h1 id="zotero"&gt;
&lt;a class="anchor inpage" href="#zotero"&gt;#&lt;/a&gt;Zotero&lt;/h1&gt;
&lt;h2 id="install-and-basic-setting"&gt;
&lt;a class="anchor inpage" href="#install-and-basic-setting"&gt;##&lt;/a&gt;Install and basic setting&lt;/h2&gt;
&lt;h2 id="plugins"&gt;
&lt;a class="anchor inpage" href="#plugins"&gt;##&lt;/a&gt;Plugins&lt;/h2&gt;
&lt;p&gt;&lt;strong&gt;zotero 7:&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;常用：&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Zotero attanger&lt;/li&gt;
&lt;li&gt;Del item with Attachment&lt;/li&gt;
&lt;li&gt;Ethereal Reference&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;好用：&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;zotero better notes&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;没必要但可以：&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Ethereal Style&lt;/li&gt;
&lt;li&gt;Attachment Scanner&lt;/li&gt;
&lt;li&gt;arXiv Workflow for zotero&lt;/li&gt;
&lt;li&gt;Zoplicate&lt;/li&gt;
&lt;li&gt;Linter for zotero&lt;/li&gt;
&lt;/ul&gt;
&lt;h2 id="sync"&gt;
&lt;a class="anchor inpage" href="#sync"&gt;##&lt;/a&gt;Sync&lt;/h2&gt;
&lt;p&gt;using &lt;del&gt;zotmoov&lt;/del&gt; attanger to move files&lt;/p&gt;
&lt;p&gt;zotero 7 to rename:&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;{{ title case=&amp;#34;snake&amp;#34; }}{{ creators case=&amp;#34;snake&amp;#34; prefix=&amp;#34;_&amp;#34; max=&amp;#34;1&amp;#34;}}{{ year prefix=&amp;#34;_&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;p&gt;use any cloud drive to sync. I&amp;rsquo;m using koofr.&lt;/p&gt;</description><content:encoded><![CDATA[<h1 id="zotero">
  <a class="anchor inpage" href="#zotero">#</a>Zotero</h1>
<h2 id="install-and-basic-setting">
  <a class="anchor inpage" href="#install-and-basic-setting">##</a>Install and basic setting</h2>
<h2 id="plugins">
  <a class="anchor inpage" href="#plugins">##</a>Plugins</h2>
<p><strong>zotero 7:</strong></p>
<p>常用：</p>
<ul>
<li>Zotero attanger</li>
<li>Del item with Attachment</li>
<li>Ethereal Reference</li>
</ul>
<p>好用：</p>
<ul>
<li>zotero better notes</li>
</ul>
<p>没必要但可以：</p>
<ul>
<li>Ethereal Style</li>
<li>Attachment Scanner</li>
<li>arXiv Workflow for zotero</li>
<li>Zoplicate</li>
<li>Linter for zotero</li>
</ul>
<h2 id="sync">
  <a class="anchor inpage" href="#sync">##</a>Sync</h2>
<p>using <del>zotmoov</del> attanger to move files</p>
<p>zotero 7 to rename:</p>
<details open>
    <summary>TEXT</summary><pre
        class="codeblock"
      ><code class="language-" data-lang="">{{ title case=&#34;snake&#34; }}{{ creators case=&#34;snake&#34; prefix=&#34;_&#34; max=&#34;1&#34;}}{{ year prefix=&#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>use any cloud drive to sync. I&rsquo;m using koofr.</p>
<h2 id="zotero-better-notes">
  <a class="anchor inpage" href="#zotero-better-notes">##</a>zotero better notes</h2>
<p>用来
</p>
<p><strong>templates:</strong> you can copy these:</p>
<details open>
    <summary>quickinsert</summary><pre
        class="codeblock"
      ><code class="language-quickinsert" data-lang="quickinsert"># This template is specifically for importing/sharing, using better
# notes &#39;import from clipboard&#39;: copy the content and
# goto Zotero menu bar, click Tools-&gt;New Template from Clipboard.
# Do not copy-paste this to better notes template editor directly.
name: &#34;[QuickInsertV2]&#34;
zoteroVersion: &#34;7.0.9.SOURCE.fadbf3d2d&#34;
pluginVersion: &#34;2.0.18&#34;
savedAt: &#34;2024-11-07T07:59:45.835Z&#34;
content: |-
  // @use-markdown
  &lt;a href=&#34;${link}&#34;&gt;${linkText}&lt;/a&gt; [md](/wiki/math/zotero/${subNoteItem.getNoteTitle ? subNoteItem.getNoteTitle().replace(/[/\\?%*:|&#34;&lt;&gt; ]/g, &#34;-&#34;) &#43; &#34;-&#34;:&#34;&#34;}${subNoteItem.key})</code><button onclick="copyCode(this)" class="copybtn">copy</button></pre></details>

  <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>quickimport</summary><pre
        class="codeblock"
      ><code class="language-quickimport" data-lang="quickimport"># This template is specifically for importing/sharing, using better
# notes &#39;import from clipboard&#39;: copy the content and
# goto Zotero menu bar, click Tools-&gt;New Template from Clipboard.
# Do not copy-paste this to better notes template editor directly.
name: &#34;[QuickImportV2]&#34;
zoteroVersion: &#34;7.0.9.SOURCE.fadbf3d2d&#34;
pluginVersion: &#34;2.0.18&#34;
savedAt: &#34;2024-11-07T05:54:37.696Z&#34;
content: |-
  &lt;blockquote&gt;
  ${{
    return await Zotero.BetterNotes.api.convert.link2html(link, {noteItem, dryRun: _env.dryRun});
  }}$
  &lt;/blockquote&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>quicknote</summary><pre
        class="codeblock"
      ><code class="language-quicknote" data-lang="quicknote"># This template is specifically for importing/sharing, using better
# notes &#39;import from clipboard&#39;: copy the content and
# goto Zotero menu bar, click Tools-&gt;New Template from Clipboard.
# Do not copy-paste this to better notes template editor directly.
name: &#34;[QuickNoteV5]&#34;
zoteroVersion: &#34;7.0.9.SOURCE.fadbf3d2d&#34;
pluginVersion: &#34;2.0.18&#34;
savedAt: &#34;2024-11-07T05:54:55.255Z&#34;
content: |-
  ${{
    let res = &#34;&#34;;
    if (annotationItem.annotationComment) {
      res &#43;= await Zotero.BetterNotes.api.convert.md2html(
        annotationItem.annotationComment
      );
    } else {
  	res &#43;= &#34;No comment&#34;;
    }
    return res;
  }}$

  // @use-markdown
  ***
  ${{
  	let res = &#34;&#34;;
    res &#43;= await Zotero.BetterNotes.api.convert.annotations2html([annotationItem], {noteItem, ignoreComment: true});
    return res;
  }}$</code><button onclick="copyCode(this)" class="copybtn">copy</button></pre></details>

  <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>exportmdfilename</summary><pre
        class="codeblock"
      ><code class="language-exportmdfilename" data-lang="exportmdfilename"># This template is specifically for importing/sharing, using better
# notes &#39;import from clipboard&#39;: copy the content and
# goto Zotero menu bar, click Tools-&gt;New Template from Clipboard.
# Do not copy-paste this to better notes template editor directly.
name: &#34;[ExportMDFileNameV2]&#34;
zoteroVersion: &#34;7.0.9.SOURCE.fadbf3d2d&#34;
pluginVersion: &#34;2.0.18&#34;
savedAt: &#34;2024-11-07T05:55:24.890Z&#34;
content: |-
  ${(noteItem.getNoteTitle ? noteItem.getNoteTitle().replace(/[/\\?%*:|&#34;&lt;&gt; ]/g, &#34;-&#34;) &#43; &#34;-&#34; : &#34;&#34;)}${noteItem.key}.md</code><button onclick="copyCode(this)" class="copybtn">copy</button></pre></details>

  <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>exportmdfileheader</summary><pre
        class="codeblock"
      ><code class="language-exportmdfileheader" data-lang="exportmdfileheader"># This template is specifically for importing/sharing, using better
# notes &#39;import from clipboard&#39;: copy the content and
# goto Zotero menu bar, click Tools-&gt;New Template from Clipboard.
# Do not copy-paste this to better notes template editor directly.
name: &#34;[ExportMDFileHeaderV2]&#34;
zoteroVersion: &#34;7.0.9.SOURCE.fadbf3d2d&#34;
pluginVersion: &#34;2.0.18&#34;
savedAt: &#34;2024-11-07T05:55:34.047Z&#34;
content: |-
  ${{
    let header = {};
    header.tags = noteItem.getTags().map((_t) =&gt; _t.tag);
    header.parent = noteItem.parentItem
      ? noteItem.parentItem.getField(&#34;title&#34;)
      : &#34;&#34;;
    header.collections = (
      await Zotero.Collections.getCollectionsContainingItems([
        (noteItem.parentItem || noteItem).id,
      ])
    ).map((c) =&gt; c.name);
    return JSON.stringify(header);
  }}$</code><button onclick="copyCode(this)" class="copybtn">copy</button></pre></details>

  <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>exportmdfilecontent</summary><pre
        class="codeblock"
      ><code class="language-exportmdfilecontent" data-lang="exportmdfilecontent"># This template is specifically for importing/sharing, using better
# notes &#39;import from clipboard&#39;: copy the content and
# goto Zotero menu bar, click Tools-&gt;New Template from Clipboard.
# Do not copy-paste this to better notes template editor directly.
name: &#34;[ExportMDFileContent]&#34;
zoteroVersion: &#34;7.0.9.SOURCE.fadbf3d2d&#34;
pluginVersion: &#34;2.0.18&#34;
savedAt: &#34;2024-11-07T05:56:22.434Z&#34;
content: |-
  ${{
    let start = mdContent;
    let rmspan = start.replace(/&lt;\/?span.*?&gt;/g,&#39;&#39;);
    let pdflink = rmspan.replace(/(&lt;a .*?open.*?&gt;)“(.*?)”/g,&#39;$2 $1(pdf)&lt;/a&gt;&#39;);
    let dir2zotero = pdflink.replace(/&lt;a href.*?zhref=&#34;(.*?)&#34; ztype.*?&gt;/g,&#39;&lt;a href=&#34;$1&#34;&gt;&#39;);
    return dir2zotero;
  }}$</code><button onclick="copyCode(this)" class="copybtn">copy</button></pre></details>

  <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>annotation will be exported as</p>
<details open>
    <summary>TEXT</summary><pre
        class="codeblock"
      ><code class="language-" data-lang="">&lt;span class=&#34;highlight&#34; data-annotation=&#34;&lt;data-annotation&gt;&#34; ztype=&#34;zhighlight&#34;&gt;&lt;a href=&#34;zotero://open/library/items/G4BKVA2X?page=2&amp;#x26;annotation=LZLEYYRJ&#34;&gt;“&lt;content&gt;”&lt;/a&gt;&lt;/span&gt; &lt;span class=&#34;citation&#34; data-citation=&#34;&lt;citation&gt;&#34; ztype=&#34;zcitation&#34;&gt;(&lt;span class=&#34;citation-item&#34;&gt;&lt;a href=&#34;zotero://select/library/items/GLXUZZJT&#34;&gt;&lt;/a&gt;&lt;/span&gt;)&lt;/span&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>the color of annotation is coded as <code>%23&lt;rgb&gt;</code> in <code>&lt;data-annotation&gt;</code>, for
example blue (#2ea8e5) annotation is <code>%232ea8e5</code></p>
]]></content:encoded></item><item><title>obsidian使用与插件</title><link>https://hiraethecho.github.io/docs/software/obsidian/</link><pubDate>Sat, 11 Nov 2023 00:00:00 +0000</pubDate><author>wyz2016zxc@outlook.com(Hiraeth)</author><guid>https://hiraethecho.github.io/docs/software/obsidian/</guid><description>&lt;h1 id="obsidian"&gt;
&lt;a class="anchor inpage" href="#obsidian"&gt;#&lt;/a&gt;obsidian&lt;/h1&gt;
&lt;h2 id="plugins"&gt;
&lt;a class="anchor inpage" href="#plugins"&gt;##&lt;/a&gt;plugins&lt;/h2&gt;
&lt;p&gt;常用：&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;remotely save (using webdav to synchronize files)&lt;/li&gt;
&lt;li&gt;obsidian web clipper 浏览器插件&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;好用：&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;git&lt;/li&gt;
&lt;li&gt;digital garden&lt;/li&gt;
&lt;li&gt;share as gist&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;没必要：&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;gistr: 和&lt;code&gt;share as gist&lt;/code&gt;比不能添加description&lt;/li&gt;
&lt;li&gt;find orphaned files and broken links&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;about vim:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;vim toggle&lt;/li&gt;
&lt;li&gt;vim input method switch&lt;/li&gt;
&lt;li&gt;vimrc&lt;/li&gt;
&lt;li&gt;edit in neovim&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;展示：&lt;/p&gt;</description><content:encoded><![CDATA[<h1 id="obsidian">
  <a class="anchor inpage" href="#obsidian">#</a>obsidian</h1>
<h2 id="plugins">
  <a class="anchor inpage" href="#plugins">##</a>plugins</h2>
<p>常用：</p>
<ul>
<li>remotely save (using webdav to synchronize files)</li>
<li>obsidian web clipper 浏览器插件</li>
</ul>
<p>好用：</p>
<ul>
<li>git</li>
<li>digital garden</li>
<li>share as gist</li>
</ul>
<p>没必要：</p>
<ul>
<li>gistr: 和<code>share as gist</code>比不能添加description</li>
<li>find orphaned files and broken links</li>
</ul>
<p>about vim:</p>
<ul>
<li>vim toggle</li>
<li>vim input method switch</li>
<li>vimrc</li>
<li>edit in neovim</li>
</ul>
<p>展示：</p>
<ul>
<li>
</li>
<li>dataview (display files by metadata)</li>
<li>kanban (plan things, especially something with many stages)不习惯</li>
</ul>
<h2 id="theme">
  <a class="anchor inpage" href="#theme">##</a>theme</h2>
<ul>
<li>nord</li>
<li>minimal</li>
</ul>
<h2 id="sync">
  <a class="anchor inpage" href="#sync">##</a>sync</h2>
<p>因为
，所以重点是同步obsidian仓库。云端是github和webdav（koofr），在两台电脑（都是win/linux双系统）和手机、ipad，总计6个仓库同步。要注意的是</p>
<ul>
<li>手机和ipad很难用git</li>
<li>设置需要忽略的文件</li>
<li>考虑用插件还是外部命令</li>
<li>各种方式下的冲突文件处理</li>
</ul>
<h2 id="editor">
  <a class="anchor inpage" href="#editor">##</a>editor</h2>
<p>虽然用obsidian管理markdown文件，但编辑器可以用其他的。比如
.</p>
]]></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>双系统安装archlinux</title><link>https://hiraethecho.github.io/docs/linux/archinstall/</link><pubDate>Mon, 09 Oct 2023 00:00:00 +0000</pubDate><author>wyz2016zxc@outlook.com(Hiraeth)</author><guid>https://hiraethecho.github.io/docs/linux/archinstall/</guid><description>双系统安装archlinux，btrfs分区、grub启动项</description><content:encoded><![CDATA[<h1 id="basic-installation-of-arch-linux">
  <a class="anchor inpage" href="#basic-installation-of-arch-linux">#</a>Basic installation of arch linux</h1>
<blockquote class="alert alert-important">
      <p class="alert-heading">有能力者建议看</p><p></p></blockquote><p>双系统安装archlinux，使用btrfs文件系统。重装系统的参考。</p>
<blockquote class="alert alert-tip">
      <p class="alert-heading">windows部分</p><p>由于windows安装和更新可能会改动efi分区，建议先安装windows，然后再安装archlinux。<br>
如果需要干净的windows，可以参考
。</p></blockquote><h2 id="启动盘">
  <a class="anchor inpage" href="#%e5%90%af%e5%8a%a8%e7%9b%98">##</a>启动盘</h2>
<p>下载archlinux的iso文件。找一个U盘，用 <code>ventoy</code>安装，然后把iso放进去。</p>
<p>可以先在win下用 <kbd>win</kbd>+<kbd>x</kbd>、<kbd>k</kbd> 打开磁盘管理，然后手动分区，用win的GUI代替之后的命令行分区。可以使用<code>diskgenuis</code>软件做更多操作。</p>
<p>插上U盘，重起电脑，在开机时按 <kbd>F11</kbd> <kbd>F12</kbd> <kbd>F2</kbd> 之类能进入选择启动位置的界面，选择从U盘启动。之后应该会启动U盘里的<code>ventoy</code>，选择arch的iso。这样就进入<code>arch live</code> 的系统，这个系统是用来安装arch的。</p>
<h2 id="处理磁盘">
  <a class="anchor inpage" href="#%e5%a4%84%e7%90%86%e7%a3%81%e7%9b%98">##</a>处理磁盘</h2>
<blockquote class="alert alert-tip">
      <p class="alert-heading">TIP</p><p>此时进入的是<code>arch live</code>环境，其实这个时候已经可以拔掉U盘了。在这个环境中做的修改不会保存。</p></blockquote><p>接下来要预处理实际电脑上的磁盘，也就是系统安装位置。</p>
<h3 id="network-and-time">
  <a class="anchor inpage" href="#network-and-time">###</a>network and time</h3>
<p>首先是把<code>arch live</code>系统联网，设置时间，配置软件源。使用 <code>iwctl</code> 连接网络。</p>
<details open>
    <summary>sh</summary><pre
        class="chroma codeblock"
      ><code class="language-sh" data-lang="sh"
          ><span style="display:flex;"><span>iwctl <span style="color:#75715e"># 进入iwctl</span>
</span></span><span style="display:flex;"><span><span style="color:#f92672">[</span>iwd<span style="color:#f92672">]</span> help <span style="color:#75715e"># 查看使用方法</span>
</span></span><span style="display:flex;"><span><span style="color:#f92672">[</span>iwd<span style="color:#f92672">]</span> station wlan0 connect **SSID** <span style="color:#75715e"># example</span>
</span></span><span style="display:flex;"><span><span style="color:#f92672">[</span>iwd<span style="color:#f92672">]</span> exit <span style="color:#75715e"># 退出iwctl</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>sh</summary><pre
        class="chroma codeblock"
      ><code class="language-sh" data-lang="sh"
          ><span style="display:flex;"><span>timedatectl set-ntp true
</span></span><span style="display:flex;"><span>timedatectl status</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/pacman.d/mirrorlist</code>中添加pacman的源，推荐清华源。否则可能下载速度慢。</p>
<details open>
    <summary>text</summary><pre
        class="chroma codeblock"
      ><code class="language-text" data-lang="text"
          ><span style="display:flex;"><span>Server = https://mirrors.tuna.tsinghua.edu.cn/archlinux/$repo/os/$arch</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="分区">
  <a class="anchor inpage" href="#%e5%88%86%e5%8c%ba">###</a>分区</h3>
<blockquote class="alert alert-warning">
      <p class="alert-heading">WARNING</p><p>这一步是操作实际电脑的磁盘，会删除数据。请小心操作。
将预留空间格式化为btrfs文件系统，并分区。</p></blockquote><p>首先查看分区：</p>
<details open>
    <summary>sh</summary><pre
        class="chroma codeblock"
      ><code class="language-sh" data-lang="sh"
          ><span style="display:flex;"><span>fdisk -l</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>nvme0n1p5</code>为例作为linux分区。</p>
<details open>
    <summary>sh</summary><pre
        class="chroma codeblock"
      ><code class="language-sh" data-lang="sh"
          ><span style="display:flex;"><span>mkfs.btrfs  -L btrfs-arch /dev/nvme0n1p5 <span style="color:#75715e"># -L means label, can be omitted</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>sh</summary><pre
        class="chroma codeblock"
      ><code class="language-sh" data-lang="sh"
          ><span style="display:flex;"><span>mount -o /dev/nvme0n1p3 /mnt <span style="color:#75715e"># 这条命令将分区挂载到btrfs的顶级子卷，即 / 子卷， id=5</span>
</span></span><span style="display:flex;"><span><span style="color:#75715e"># 通常这些子卷</span>
</span></span><span style="display:flex;"><span>btrfs subvolume create /mnt/@   <span style="color:#75715e"># 创建顶级子卷下的 @ 子卷，将作为新linux的 / 目录</span>
</span></span><span style="display:flex;"><span>btrfs subvolume create /mnt/@home <span style="color:#75715e"># 创建顶级子卷下的 /@home 子卷，将作为新linux的 用户家目录，即 /home</span>
</span></span><span style="display:flex;"><span><span style="color:#75715e"># 以下可选</span>
</span></span><span style="display:flex;"><span>btrfs subvolume create /mnt/@log
</span></span><span style="display:flex;"><span>btrfs subvolume create /mnt/@cache
</span></span><span style="display:flex;"><span>btrfs subvolume create /mnt/@opt
</span></span><span style="display:flex;"><span>btrfs subvolume create /mnt/@tmp
</span></span><span style="display:flex;"><span>btrfs subvolume create /mnt/@root</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>sh</summary><pre
        class="chroma codeblock"
      ><code class="language-sh" data-lang="sh"
          ><span style="display:flex;"><span>btrfs subvolume list /mnt
</span></span><span style="display:flex;"><span>ID <span style="color:#ae81ff">256</span> gen <span style="color:#ae81ff">405</span> parent <span style="color:#ae81ff">5</span> top level <span style="color:#ae81ff">5</span> path @
</span></span><span style="display:flex;"><span>ID <span style="color:#ae81ff">257</span> gen <span style="color:#ae81ff">409</span> parent <span style="color:#ae81ff">5</span> top level <span style="color:#ae81ff">5</span> path @home</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><blockquote class="alert alert-note">
      <p class="alert-heading">NOTE</p><p>ID 是子卷的 id，gen 是子卷的代数，parent 是父卷的 id，top level 是顶级子卷的 id，path 是子卷的路径<br>
应该还有其他子卷的输出，这里没有列出。</p></blockquote><p>接下来先取消挂载顶级子卷，再挂载子卷到对应的目录：</p>
<details open>
    <summary>sh</summary><pre
        class="chroma codeblock"
      ><code class="language-sh" data-lang="sh"
          ><span style="display:flex;"><span>umount /mnt
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span>mount -o noatime,nodiratime,compress<span style="color:#f92672">=</span>zstd,subvol<span style="color:#f92672">=</span>@ /dev/nvme0n1p5 /mnt <span style="color:#75715e">#挂载 @ 子卷到新系统的 / 目录</span>
</span></span><span style="display:flex;"><span>mkdir -p /mnt/<span style="color:#f92672">{</span>boot/efi,home,var/<span style="color:#f92672">{</span>log,cache<span style="color:#f92672">}}</span> <span style="color:#75715e">#创建新系统的 /boot/efi、/home、/var/log、/var/cache</span>
</span></span><span style="display:flex;"><span>mount -o noatime,nodiratime,compress<span style="color:#f92672">=</span>zstd,subvol<span style="color:#f92672">=</span>@home -m /dev/nvme0n1p5 /mnt/home <span style="color:#75715e"># -m 创建挂载的文件夹</span>
</span></span><span style="display:flex;"><span><span style="color:#75715e"># 如果创建了对应子卷，那么</span>
</span></span><span style="display:flex;"><span>mount -o noatime,nodiratime,compress<span style="color:#f92672">=</span>zstd,subvol<span style="color:#f92672">=</span>@log -m /dev/nvme0n1p5 /mnt/var/log
</span></span><span style="display:flex;"><span>mount -o noatime,nodiratime,compress<span style="color:#f92672">=</span>zstd,subvol<span style="color:#f92672">=</span>@cache -m /dev/nvme0n1p5 /mnt/var/cache
</span></span><span style="display:flex;"><span>mount -o noatime,nodiratime,compress<span style="color:#f92672">=</span>zstd,subvol<span style="color:#f92672">=</span>@tmp -m /dev/nvme0n1p5 /mnt/tmp
</span></span><span style="display:flex;"><span>mount -o noatime,nodiratime,compress<span style="color:#f92672">=</span>zstd,subvol<span style="color:#f92672">=</span>@opt -m /dev/nvme0n1p5 /mnt/opt
</span></span><span style="display:flex;"><span>mount -o noatime,nodiratime,compress<span style="color:#f92672">=</span>zstd,subvol<span style="color:#f92672">=</span>@root -m /dev/nvme0n1p5 /mnt/root</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>sh</summary><pre
        class="chroma codeblock"
      ><code class="language-sh" data-lang="sh"
          ><span style="display:flex;"><span>findmnt -nt btrfs</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>挂载efi分区。因为单硬盘安装双系统，所以使用windows系统原有的efi分区。</p>
<details open>
    <summary>sh</summary><pre
        class="chroma codeblock"
      ><code class="language-sh" data-lang="sh"
          ><span style="display:flex;"><span>mount /dev/nvme0n1p1 /mnt/boot/efi</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><blockquote class="alert alert-tip">
      <p class="alert-heading">TIP</p><p>win初始的efi分区大小可能不够 <code>/boot</code> ，所以可以只挂载 <code>/boot/efi</code>。也可以创建<code>/efi</code><br>
在win下可以用 <code>diskgenuis</code> 查看efi分区。</p></blockquote><blockquote class="alert alert-note">
      <p class="alert-heading">update 2025-07-27</p><p>ESP分区的挂载，现在推荐直接挂载到<code>/efi</code>而不是<code>/boot/efi</code></p>
<details open>
    <summary>sh</summary><pre
        class="chroma codeblock"
      ><code class="language-sh" data-lang="sh"
          ><span style="display:flex;"><span>mount /dev/nvme0n1p1 /mnt/efi</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>btrfs</code>格式的<code>/boot</code>会导致一些奇怪的报错，比如稀疏文件的问题等，以及<code>grub</code>无法设置为从上次启动的选项启动。所以也可以单开一个分区来挂载<code>/boot</code>.
参见
</p></blockquote><details open>
    <summary>shell</summary><pre
        class="chroma codeblock"
      ><code class="language-shell" data-lang="shell"
          ><span style="display:flex;"><span>mkdir -p /mnt/efi
</span></span><span style="display:flex;"><span>mount /dev/nvme0n1p1 /mnt/boot/efi</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="">chattr &#43;C /mnt/tmp
chattr &#43;C /mnt/var/cache
chattr &#43;C /mnt/var/log</code><button onclick="copyCode(this)" class="copybtn">copy</button></pre></details>

  <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="#%e5%ae%89%e8%a3%85%e7%b3%bb%e7%bb%9f">##</a>安装系统</h2>
<p>这一步是实际安装系统到电脑上。
install and genfstab 安装系统并生成分区表</p>
<p>安装系统到新分区，这里使用 <code>pacstrap</code> 命令，安装一些必要组件和后续使用的基础软件，包括linux内核、linux固件、btrfs-progs管理btrfs文件系统、dhcpcd、iwd、networkmanager管理网络、neovim编辑器、git、sudo、grub、os-prober (查找硬盘上其他系统，在grub界面启动windows系统)、efibootmgr</p>
<details open>
    <summary>sh</summary><pre
        class="chroma codeblock"
      ><code class="language-sh" data-lang="sh"
          ><span style="display:flex;"><span>pacstrap -K -M /mnt base base-devel linux linux-headers btrfs-progs iwd neovim git
</span></span><span style="display:flex;"><span>sudo grub os-prober efibootmgr amd-ucode dhcpcd</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><blockquote class="alert alert-note">
      <p class="alert-heading">NOTE</p><p>根据cpu安装 <code>amd-ucode</code> 或 <code>intel-ucode</code></p></blockquote><p>接下来生成分区表，记录这个磁盘分区是如何使用的。</p>
<details open>
    <summary>TEXT</summary><pre
        class="codeblock"
      ><code class="language-" data-lang="">genfstab -U /mnt &gt;&gt; /mnt/etc/fstab</code><button onclick="copyCode(this)" class="copybtn">copy</button></pre></details>

  <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="配置grub启动">
  <a class="anchor inpage" href="#%e9%85%8d%e7%bd%aegrub%e5%90%af%e5%8a%a8">##</a>配置grub启动</h2>
<p>配置grub，使得电脑启动时能找到这个系统。这一步需要进入新安装的系统中：</p>
<details open>
    <summary>TEXT</summary><pre
        class="codeblock"
      ><code class="language-" data-lang="">arch-chroot /mnt</code><button onclick="copyCode(this)" class="copybtn">copy</button></pre></details>

  <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>这个命令之后就进入了刚刚安装的archlinux系统，之后的命令都是在这个系统中执行的。</p>
<blockquote class="alert alert-note">
      <p class="alert-heading">NOTE</p><p>对于双系统安装，要让grub发现其他系统。在<code>/etc/default/grub</code>中取消注释</p>
<details open>
    <summary>TEXT</summary><pre
        class="codeblock"
      ><code class="language-" data-lang=""># GRUB_DISABLE_OS_PROBER=false</code><button onclick="copyCode(this)" class="copybtn">copy</button></pre></details>

  <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>对于btrfs，似乎需要一些操作才能使<code>os-prober</code>起效。<br>
在<code>/etc/mkinitcpio.conf</code> 添加 btrfs 到 MODULES=(&hellip;)行 找到 HOOKS=(&hellip;)行，更换fsck为btrfs 最终你看到的/etc/mkinitcpio.conf文件格式为</p>
<details open>
    <summary>text</summary><pre
        class="chroma codeblock"
      ><code class="language-text" data-lang="text"
          ><span style="display:flex;"><span>...
</span></span><span style="display:flex;"><span>MODULES=(btrfs)
</span></span><span style="display:flex;"><span>HOOKS=(base udev autodetect modconf block filesystems keyboard btrfs)
</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>然后重新生成 initramfs</p>
<details open>
    <summary>sh</summary><pre
        class="chroma codeblock"
      ><code class="language-sh" data-lang="sh"
          ><span style="display:flex;"><span>mkinitcpio -P</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></blockquote><p>安装启动器<code>grub</code>到efi分区，并生成grub文件：</p>
<details open>
    <summary>sh</summary><pre
        class="chroma codeblock"
      ><code class="language-sh" data-lang="sh"
          ><span style="display:flex;"><span>grub-install --target<span style="color:#f92672">=</span>x86_64-efi --efi-directory<span style="color:#f92672">=</span>/boot/efi --bootloader-id<span style="color:#f92672">=</span>arch --recheck</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="">grub-mkconfig -o /boot/grub/grub.cfg</code><button onclick="copyCode(this)" class="copybtn">copy</button></pre></details>

  <script>
    function copyCode(btn) {
      const code = btn.previousElementSibling.textContent.trim();
      navigator.clipboard.writeText(code).then(() => {
        btn.innerText = "copied";
        setTimeout(() => (btn.innerText = "copy"), 2000);
      });
    }
  </script><blockquote class="alert alert-tip">
      <p class="alert-heading">TIP</p><p>可以先对grub做一些配置，也可以后续执行。<br>
去掉 quiet 参数，调整 loglevel 值为 5 ，加入 nowatchdog 参数</p>
<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;s|GRUB_CMDLINE_LINUX_DEFAULT.*|GRUB_CMDLINE_LINUX_DEFAULT=\&#34;loglevel=5 nowatchdog\&#34;|&#34;</span> /etc/default/grub</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></blockquote><p>理论上现在可以重启电脑，选择从硬盘启动，就可以看到grub界面，选择archlinux启动。但最好先做一些基本配置。</p>
<h2 id="基本配置">
  <a class="anchor inpage" href="#%e5%9f%ba%e6%9c%ac%e9%85%8d%e7%bd%ae">##</a>基本配置</h2>
<p>首先设置root密码</p>
<details open>
    <summary>TEXT</summary><pre
        class="codeblock"
      ><code class="language-" data-lang="">passwd root</code><button onclick="copyCode(this)" class="copybtn">copy</button></pre></details>

  <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>
<p>配置locale、hostname、网络等</p>
<details open>
    <summary>sh</summary><pre
        class="chroma codeblock"
      ><code class="language-sh" data-lang="sh"
          ><span style="display:flex;"><span>ln -sf /usr/share/zoneinfo/Region/City /etc/localtime <span style="color:#75715e">#替换Region/City为你所在区域，例如Asia/Shanghai</span>
</span></span><span style="display:flex;"><span>hwclock --systohc <span style="color:#75715e"># 同步硬件时钟</span>
</span></span><span style="display:flex;"><span>timedatectl set-ntp true
</span></span><span style="display:flex;"><span>timedatectl set-local-rtc true <span style="color:#75715e">#同步双系统时间</span>
</span></span><span style="display:flex;"><span>echo <span style="color:#e6db74">&#34;en_US.UTF-8 UTF-8&#34;</span> &gt;&gt; /etc/locale.gen
</span></span><span style="display:flex;"><span>locale-gen
</span></span><span style="display:flex;"><span>echo <span style="color:#e6db74">&#34;LANG=en_US.UTF-8&#34;</span> &gt; /etc/locale.conf <span style="color:#75715e">#或者编辑文件，取消注释</span>
</span></span><span style="display:flex;"><span>systemctl enable NetworkManager.service <span style="color:#75715e"># 启动网络服务</span>
</span></span><span style="display:flex;"><span>hostnamectl set-hostname &lt;yourhostname&gt; <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><p>时间格式也可以设置</p>
<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;LC_TIME=C.UTF-8&#34;</span> &gt;&gt; /etc/locale.conf <span style="color:#75715e"># &gt;&gt; 表示追加。</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>hosts:</p>
<details open>
    <summary>TEXT</summary><pre
        class="codeblock"
      ><code class="language-" data-lang=""># /etc/hosts
127.0.0.1   localhost
::1         localhost
127.0.1.1   &lt;yourhostname&gt;.localdomain    &lt;yourhostname&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="quit-and-reboot">
  <a class="anchor inpage" href="#quit-and-reboot">##</a>quit and reboot</h2>
<p>退出新系统，取消挂载，重启</p>
<details open>
    <summary>TEXT</summary><pre
        class="codeblock"
      ><code class="language-" data-lang="">exit #退出chroot
umount /mnt/boot/efi
umount /mnt/home
umount /mnt
reboot</code><button onclick="copyCode(this)" class="copybtn">copy</button></pre></details>

  <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>
]]></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><item><title>归档</title><link>https://hiraethecho.github.io/docs/archive/</link><pubDate>Mon, 01 Jan 0001 00:00:00 +0000</pubDate><author>wyz2016zxc@outlook.com(Hiraeth)</author><guid>https://hiraethecho.github.io/docs/archive/</guid><description/><content:encoded></content:encoded></item><item><title>收集一些工具</title><link>https://hiraethecho.github.io/docs/software/softwares/</link><pubDate>Mon, 01 Jan 0001 00:00:00 +0000</pubDate><author>wyz2016zxc@outlook.com(Hiraeth)</author><guid>https://hiraethecho.github.io/docs/software/softwares/</guid><description>各种地方看到的有趣的工具，还没或不想写详细使用的文档</description><content:encoded><![CDATA[<h1 id="applications-tools-softwares">
  <a class="anchor inpage" href="#applications-tools-softwares">#</a>Applications Tools Softwares</h1>
<h2 id="shell-and-terminal">
  <a class="anchor inpage" href="#shell-and-terminal">##</a>shell and terminal</h2>
<ul>
<li>
<p>zsh</p>
</li>
<li>
<p>starship</p>
</li>
<li>
<p>st</p>
<ul>
<li>tabbed</li>
</ul>
</li>
<li>
<p>foot</p>
</li>
<li>
<p>kitty</p>
</li>
<li>
<p>mtm</p>
</li>
<li>
<p>tmux</p>
</li>
<li>
<p>tuios</p>
</li>
</ul>
<h2 id="wm">
  <a class="anchor inpage" href="#wm">##</a>wm</h2>
<ul>
<li>X
<ul>
<li>dwm</li>
<li>xorg-xeye: help to find xwayland app while running wayland</li>
<li>xev wev: key stroke under X and wayland</li>
</ul>
</li>
<li>wayland
<ul>
<li>
</li>
<li>river</li>
<li>hyprland</li>
<li>mangowc</li>
</ul>
</li>
<li>tty
<ul>
<li>dvtm</li>
</ul>
</li>
</ul>
<p><strong>other</strong>:</p>
<ul>
<li>
</li>
<li>
</li>
</ul>
<p>Related tools</p>
<p>
 is a nested X server that runs as an X application.</p>
<p>If you wish to run a nested X window, you will need to specify a new display:</p>
<details open>
    <summary>TEXT</summary><pre
        class="codeblock"
      ><code class="language-" data-lang="">$ Xephyr -br -ac -noreset -screen 800x600 :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>This will launch a new Xephyr window with a DISPLAY of &ldquo;:1&rdquo;. In order to launch an application in that window, you would need to specify that display:</p>
<details open>
    <summary>TEXT</summary><pre
        class="codeblock"
      ><code class="language-" data-lang="">$ DISPLAY=:1 xterm</code><button onclick="copyCode(this)" class="copybtn">copy</button></pre></details>

  <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>If you want to launch a specific WM, 
 for example, you would type:</p>
<details open>
    <summary>TEXT</summary><pre
        class="codeblock"
      ><code class="language-" data-lang="">$ DISPLAY=:1 spectrwm</code><button onclick="copyCode(this)" class="copybtn">copy</button></pre></details>

  <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>You can also launch Xephyr with your 
 using startx:</p>
<details open>
    <summary>TEXT</summary><pre
        class="codeblock"
      ><code class="language-" data-lang="">$ startx -- /usr/bin/Xephyr :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>Grabbing and un-grabbing user input: Pressing <code>Ctrl+Shift</code> should lock/unlock your mouse pointer and your keystrokes inside Xephyr window exclusively if possible.<br>
If using KDE, create a window rule to ignore global shortcuts. Then you can use <code>Alt+Tab</code> inside Xephyr.</p>
<p>Tips and tricks: Other examples for situations where Xephyr can be useful are:</p>
<ol>
<li>A testing environment for an X application, or feature, in which the tester would like to keep working in their usual X environment, yet defending the other applications from failures of the application under test.</li>
<li>
 emphasize 3 settings in the sshd server configuration file for 
 (over ssh). 2 of these, out of 3, are the default settings. When the ssh client can not influence the ssh server administrator to set the 3rd one, <code>X11Forwarding</code>, to yes, 
 uses Xephyr as a work around to be installed in the ssh client machine.</li>
</ol>
<p>
</p>
<h2 id="de">
  <a class="anchor inpage" href="#de">##</a>DE</h2>
<ul>
<li><strong>launcher</strong>
<ul>
<li>rofi</li>
<li>dmenu</li>
</ul>
</li>
<li><strong>utils</strong>
<ul>
<li>dms</li>
<li>noctalia</li>
<li>iwd, impala</li>
<li>pipewire, wiremix</li>
<li>bluez, bluetui</li>
<li>power-profiles-daemon</li>
</ul>
</li>
<li>pcmanfm, Thunar, yazi</li>
<li>fcitx5</li>
<li>waterfox, brave</li>
</ul>
<p><strong>Editor</strong></p>
<ul>
<li>neovim
<ul>
<li>cbfmt format code blocks inside markdown</li>
</ul>
</li>
<li>latex:
<ul>
<li>languagetool,</li>
<li>hunspell-en_us,</li>
<li>texstudio</li>
</ul>
</li>
<li>word: abiword</li>
<li>pdf: sioyek, zathura, pdfbooklet</li>
<li>markdown: obsidian</li>
</ul>
<p><strong>media</strong>:</p>
<ul>
<li>python-eye3: edit meta data for mp3</li>
<li>mpd
<ul>
<li>frontend for mpd:</li>
<li>cli:mpc</li>
<li><code>easytag</code> to edit metadata of a audio file.</li>
<li>tui:
<ul>
<li>ncmpc</li>
<li>ncmpcpp</li>
<li>mmtc (no, weird config)</li>
<li>rmpc</li>
</ul>
</li>
</ul>
</li>
<li>mpv
<ul>
<li>mpvpaper: wallpaper by mpv in wayland</li>
</ul>
</li>
<li>
 a bilibili downloader</li>
<li>
 wired</li>
<li>ffmpeg</li>
<li>
 A tui video editor. Use <code>mpv</code> to play and <code>ffmpeg</code> to edit.</li>
<li>pic
<ul>
<li>feh</li>
<li>flameshot</li>
<li>picgo</li>
</ul>
</li>
</ul>
<h2 id="system-and-kernal">
  <a class="anchor inpage" href="#system-and-kernal">##</a>system and kernal</h2>
<ul>
<li>
<p>stacer: trash cleaner, monitor</p>
</li>
<li>
<p>btop: usage monitor</p>
</li>
<li>
<p>btrfs-assistant</p>
</li>
<li>
<p>timeshift</p>
</li>
<li>
<p>snapper</p>
</li>
<li>
<p>disk usage 感觉还是dua好用，图示其实用处不大</p>
<ul>
<li>dua: du 的替代品，我一般用<code>dua -i</code>交互式查看</li>
<li>bonsai: gnome的baobab（kde的filelight）的tui版本，旭日图那个</li>
<li>diskonaut: 类似treesize, wiztree的方格划分的</li>
<li>btrfs-heatmap: btrfs usage by hilbert curve</li>
<li>gparted</li>
</ul>
</li>
<li>
<p>systemd</p>
<ul>
<li>
</li>
<li>systemctl-tui</li>
<li>isd</li>
</ul>
</li>
<li>
<p>aconfmgr: A configuration manager for Arch Linux. Kind of like nixOS. 
</p>
</li>
<li>
<p>linux-firmware: Since <code>linux-firmware</code> is departed, only need some of them. Use <code>arch-checkfw</code> to find which.</p>
<p><code>linux-firmware</code> includes</p>
<details open>
    <summary>TEXT</summary><pre
        class="codeblock"
      ><code class="language-" data-lang="">Depends On      : linux-firmware-amdgpu  linux-firmware-atheros
                linux-firmware-broadcom  linux-firmware-cirrus  linux-firmware-intel
                linux-firmware-mediatek  linux-firmware-nvidia  linux-firmware-other
                linux-firmware-radeon  linux-firmware-realtek
Optional Deps   : linux-firmware-liquidio: Firmware for Cavium LiquidIO server adapters
                linux-firmware-marvell: Firmware for Marvell devices
                linux-firmware-mellanox: Firmware for Mellanox Spectrum switches
                linux-firmware-nfp: Firmware for Netronome Flow Processors
                linux-firmware-qcom: Firmware for Qualcomm SoCs
                linux-firmware-qlogic: Firmware for QLogic devices</code><button onclick="copyCode(this)" class="copybtn">copy</button></pre></details>

  <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>
<p>dracut: Alter for mkinitcpio</p>
</li>
<li>
<p>
 Alter for grub not support fo timeshift btrfs snap yet</p>
</li>
<li>
<p>
, another <code>snapper</code>, not support fo timeshift btrfs snap yet</p>
</li>
<li>
<p>kmscon alternative getty and tty, support unicode</p>
</li>
<li>
<p>for arch</p>
<ul>
<li>lostfiles find orphaned files not owned by Arch package</li>
<li>archstatus</li>
<li>arch-wiki-doc wikiman</li>
<li>pacfiles <code>pacman -F</code> alternative</li>
<li>pacman-contrib</li>
<li>
</li>
</ul>
</li>
</ul>
<h2 id="useful-tools">
  <a class="anchor inpage" href="#useful-tools">##</a>useful tools</h2>
<ul>
<li>
<p><strong>calendar, task, email, rss, etc</strong></p>
<ul>
<li>dstask</li>
<li>todo.txt</li>
<li>timewarrior</li>
<li>taskwarrior
<ul>
<li>tasknc</li>
<li>taskwarriortui</li>
</ul>
</li>
<li>todoman</li>
<li>vdirsyncer</li>
<li>khal</li>
<li>todoman</li>
<li>aerc</li>
<li>newsboat</li>
</ul>
</li>
<li>
<p>git and related</p>
<ul>
<li>lazygit: 最常用的</li>
<li>jujustu 
</li>
<li>gitlogue</li>
<li>serie</li>
<li>gitoxide 
 An idiomatic, lean, fast &amp; safe pure Rust implementation of Git</li>
<li>avc 
</li>
<li>github-cli</li>
<li>
</li>
</ul>
</li>
<li>
<p>cronboard :
</p>
</li>
<li>
<p>
 本地一键部署docker，似乎很好用</p>
</li>
<li>
<p>
 is a lightweight tool to locally create containers for multiple Linux distributions.</p>
</li>
<li>
<p>
 is a container wrapping layer that allows the user to install containerised versions of Linux that are different to the host while providing tight integration with the host allowing the use of binaries designed for one distribution to run on another. Distrobox itself is not a container manager and relies on Podman or Docker to create containers.</p>
</li>
<li>
<p>
 is a gui for <code>Distrobox</code>.</p>
</li>
<li>
<p>
</p>
</li>
<li>
<p>surge: tui download manager</p>
</li>
<li>
<p>darkhttpd</p>
</li>
<li>
<p>nginx</p>
</li>
<li>
<p>httrack</p>
</li>
<li>
<p>whois</p>
<details open>
    <summary>tldr</summary><pre
        class="codeblock"
      ><code class="language-tldr" data-lang="tldr">Command-line client for the WHOIS (RFC 3912) protocol.
More information: &lt;https://manned.org/whois&gt;.

Get information about a domain name:

    whois example.com

Get information about an IP address:

    whois 8.8.8.8

Get abuse contact for an IP address:

    whois -b 8.8.8.8</code><button onclick="copyCode(this)" class="copybtn">copy</button></pre></details>

  <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>
<p>stew-bin: install binary from github</p>
</li>
<li>
<p>for terminal and shell</p>
<ul>
<li>
 cat pdf or other</li>
<li>ripgrep-all: <code>rga</code> to match in pdf</li>
<li>lsix: list pictures by sixel</li>
<li>chafa: show pixels of pictures through sixel</li>
<li>gping: render in tui for ping
<ul>
<li>fv-cli show font in terminal using sixel iterm or kitty</li>
</ul>
</li>
</ul>
</li>
<li>
<p>ffcast</p>
</li>
<li>
<p>fbterm</p>
</li>
<li>
<p>drive</p>
<ul>
<li>
: Filesystem client based on SSH.</li>
<li>koofr</li>
<li>rclone</li>
</ul>
</li>
<li>
<p>hardware</p>
<ul>
<li>zmk-studio</li>
<li>librepod</li>
</ul>
</li>
</ul>
<details open>
    <summary>shell</summary><pre
        class="chroma codeblock"
      ><code class="language-shell" data-lang="shell"
          ><span style="display:flex;"><span>sshfs username@remote_host:remote_directory mountpoint
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span>umount mountpoint
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span><span style="color:#75715e"># Mount remote directory from server with specific port: -p</span>
</span></span><span style="display:flex;"><span><span style="color:#75715e"># Use compression: -C</span>
</span></span><span style="display:flex;"><span><span style="color:#75715e"># Follow symbolic links: -o follow_symlinks</span>
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span>sshfs -o follow_symlinks username@remote_host:remote_directory mountpoint -p <span style="color:#ae81ff">2222</span> -C</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="tui">
  <a class="anchor inpage" href="#tui">##</a>tui</h2>
<h2 id="interesting">
  <a class="anchor inpage" href="#interesting">##</a>Interesting</h2>
<ul>
<li>genect: 假装很忙的shell操作屏幕保护程序</li>
<li>pipes-rs: 屏幕保护程序</li>
<li>cmd-wrapped: summarize shell history</li>
<li>diagon draw things in ascii 
 
</li>
<li>gitmal: generate a site from a git repo</li>
<li>
 generate pictures of code snaps</li>
<li>
 Turn markdown with additional marks to pdf or html, like LaTeX. <figure>
  <a
    href="https://raw.githubusercontent.com/iamgio/quarkdown/project-files/images/code-paper.png"
    class="img-link"
    data-sub-html="paper"
    target="_blank"
  >
    <img
      src="https://raw.githubusercontent.com/iamgio/quarkdown/project-files/images/code-paper.png"
      alt="paper"loading="lazy"
    />
  </a><figcaption>paper</figcaption></figure>
 <figure>
  <a
    href="https://raw.githubusercontent.com/iamgio/quarkdown/project-files/images/code-chart.png"
    class="img-link"
    data-sub-html="chart"
    target="_blank"
  >
    <img
      src="https://raw.githubusercontent.com/iamgio/quarkdown/project-files/images/code-chart.png"
      alt="chart"loading="lazy"
    />
  </a><figcaption>chart</figcaption></figure>
</li>
<li>gowall: A tool to convert a wallpaper&rsquo;s colorscheme, like nord or onedark</li>
<li>activate-linux a watermark</li>
</ul>
<h2 id="serves">
  <a class="anchor inpage" href="#serves">##</a>serves</h2>
<ul>
<li>
 A modern, open-source, self-hosted knowledge management and note-taking platform designed for privacy-conscious users and organizations.<br>
但是开发很迅速，导致api乱七八糟，迷茫。而且似乎没有导出功能，只是能把附件存储在cloudflare上。还是要想办法备份一下。包括radicale也是。</li>
<li>
</li>
<li>
</li>
<li>openlist</li>
<li>radicale</li>
</ul>
]]></content:encoded></item><item><title>用btrfs做linux的快照备份</title><link>https://hiraethecho.github.io/docs/linux/btrfs/</link><pubDate>Mon, 01 Jan 0001 00:00:00 +0000</pubDate><author>wyz2016zxc@outlook.com(Hiraeth)</author><guid>https://hiraethecho.github.io/docs/linux/btrfs/</guid><description>&lt;h1 id="linux下的-btrfs"&gt;
&lt;a class="anchor inpage" href="#linux%e4%b8%8b%e7%9a%84-btrfs"&gt;#&lt;/a&gt;linux下的 btrfs&lt;/h1&gt;
&lt;h2 id="btrfs的功能"&gt;
&lt;a class="anchor inpage" href="#btrfs%e7%9a%84%e5%8a%9f%e8%83%bd"&gt;##&lt;/a&gt;btrfs的功能&lt;/h2&gt;
&lt;p&gt;写时复制 &lt;code&gt;copy on right&lt;/code&gt;功能使得非常时候做快照。&lt;/p&gt;
&lt;p&gt;子卷功能可以更方便的分区。以及添加新设备。&lt;/p&gt;
&lt;h2 id="官方手册"&gt;
&lt;a class="anchor inpage" href="#%e5%ae%98%e6%96%b9%e6%89%8b%e5%86%8c"&gt;##&lt;/a&gt;官方手册&lt;/h2&gt;
&lt;details open&gt;
&lt;summary&gt;man&lt;/summary&gt;&lt;pre
class="chroma codeblock"
&gt;&lt;code class="language-man" data-lang="man"
&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;BTRFS(8) BTRFS BTRFS(8)
&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;NAME
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; btrfs - a toolbox to manage btrfs filesystems
&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;SYNOPSIS
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; btrfs [global options] &amp;lt;group&amp;gt; [&amp;lt;group&amp;gt;...] &amp;lt;command&amp;gt; [options] [&amp;lt;args&amp;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;DESCRIPTION
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; The btrfs utility is a toolbox for managing btrfs filesystems. There
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; are command groups to work with subvolumes, devices, for whole filesys‐
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; tem or other specific actions. See section COMMANDS.
&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; There are also standalone tools for some tasks like btrfs-convert(8) or
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; btrfstune(8) that were separate historically and/or haven&amp;#39;t been merged
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; to the main utility. See section STANDALONE TOOLS for more details.
&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; For other topics (mount options, etc) please refer to the separate man‐
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; ual page btrfs(5).
&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;COMMAND SYNTAX
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; Any command name can be shortened so long as the shortened form is unam‐
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; biguous, however, it is recommended to use full command names in
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; scripts. All command groups have their manual page named btrfs-&amp;lt;group&amp;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; For example: it is possible to run btrfs sub snaps instead of btrfs sub‐
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; volume snapshot. But btrfs file s is not allowed, because file s may be
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; interpreted both as filesystem show and as filesystem sync.
&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; If the command name is ambiguous, the list of conflicting options is
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; printed.
&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; Sizes, both upon input and output, can be expressed in either SI or
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; IEC-I units (see numfmt(1)) with the suffix B appended. All numbers
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; will be formatted according to the rules of the C locale (ignoring the
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; shell locale, see locale(7)).
&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; For an overview of a given command use btrfs command --help or btrfs
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; [command...] help --full to print all available options for all com‐
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; mands.
&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; There are global options that are passed between btrfs and the group
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; name and affect behaviour not specific to the command, e.g. verbosity or
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; the type of the output:
&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; btrfs -q subvolume create ...
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; btrfs --dry-run subvolume create ...
&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; --format &amp;lt;format&amp;gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; if supported by the command, print subcommand output in that for‐
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; mat (text, json)
&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; -v|--verbose
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; increase verbosity of the subcommand
&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; -q|--quiet
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; print only errors
&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; --log &amp;lt;level&amp;gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; set log level (default, info, verbose, debug, quiet)
&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; The remaining options are relevant only for the main tool:
&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; --help print condensed help for all subcommands
&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; --version
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; print version string
&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;COMMANDS
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; balance
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; Balance btrfs filesystem chunks across single or several devices.
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; See btrfs-balance(8) for details.
&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; check Do off-line check on a btrfs filesystem. See btrfs-check(8) for
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; details.
&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; device Manage devices managed by btrfs, including add/delete/scan and so
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; on. See btrfs-device(8) for details.
&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; filesystem
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; Manage a btrfs filesystem, including label setting/sync and so
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; on. See btrfs-filesystem(8) for details.
&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; inspect-internal
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; Debug tools for developers/hackers. See
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; btrfs-inspect-internal(8) for details.
&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; property
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; Get/set a property from/to a btrfs object. See btrfs-property(8)
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; for details.
&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; qgroup Manage quota group(qgroup) for btrfs filesystem. See
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; btrfs-qgroup(8) for details.
&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; quota Manage quota on btrfs filesystem like enabling/rescan and etc.
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; See btrfs-quota(8) and btrfs-qgroup(8) for details.
&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; receive
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; Receive subvolume data from stdin/file for restore and etc. See
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; btrfs-receive(8) for details.
&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; replace
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; Replace btrfs devices. See btrfs-replace(8) for details.
&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; rescue Try to rescue damaged btrfs filesystem. See btrfs-rescue(8) for
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; details.
&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; restore
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; Try to restore files from a damaged btrfs filesystem. See
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; btrfs-restore(8) for details.
&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; scrub Scrub a btrfs filesystem. See btrfs-scrub(8) for details.
&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; send Send subvolume data to stdout/file for backup and etc. See
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; btrfs-send(8) for details.
&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; subvolume
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; Create/delete/list/manage btrfs subvolume. See
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; btrfs-subvolume(8) for details.
&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;STANDALONE TOOLS
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; New functionality could be provided using a standalone tool. If the
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; functionality proves to be useful, then the standalone tool is declared
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; obsolete and its functionality is copied to the main tool. Obsolete
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; tools are removed after a long (years) depreciation period.
&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; Tools that are still in active use without an equivalent in btrfs:
&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; btrfs-convert
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; in-place conversion from ext2/3/4 filesystems to btrfs
&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; btrfstune
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; tweak some filesystem properties on a unmounted filesystem
&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; btrfs-select-super
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; rescue tool to overwrite primary superblock from a spare copy
&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; btrfs-find-root
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; rescue helper to find tree roots in a filesystem
&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; For space-constrained environments, it&amp;#39;s possible to build a single bi‐
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; nary with functionality of several standalone tools. This is following
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; the concept of busybox where the file name selects the functionality.
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; This works for symlinks or hardlinks. The full list can be obtained by
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; btrfs help --box.
&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;EXIT STATUS
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; btrfs returns a zero exit status if it succeeds. Non zero is returned in
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; case of failure.
&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;AVAILABILITY
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; btrfs is part of btrfs-progs. Please refer to the documentation at ‐
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; https://btrfs.readthedocs.io.
&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;SEE ALSO
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; btrfs(5), btrfs-balance(8), btrfs-check(8), btrfs-convert(8),
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; btrfs-device(8), btrfs-filesystem(8), btrfs-inspect-internal(8),
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; btrfs-property(8), btrfs-qgroup(8), btrfs-quota(8), btrfs-receive(8),
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; btrfs-replace(8), btrfs-rescue(8), btrfs-restore(8), btrfs-scrub(8),
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; btrfs-send(8), btrfs-subvolume(8), btrfstune(8), mkfs.btrfs(8)
&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;6.14 Mar 27, 2025 BTRFS(8)&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="快照"&gt;
&lt;a class="anchor inpage" href="#%e5%bf%ab%e7%85%a7"&gt;##&lt;/a&gt;快照&lt;/h2&gt;
&lt;p&gt;用timeshift和snapper做快照。子卷布局&lt;/p&gt;</description><content:encoded><![CDATA[<h1 id="linux下的-btrfs">
  <a class="anchor inpage" href="#linux%e4%b8%8b%e7%9a%84-btrfs">#</a>linux下的 btrfs</h1>
<h2 id="btrfs的功能">
  <a class="anchor inpage" href="#btrfs%e7%9a%84%e5%8a%9f%e8%83%bd">##</a>btrfs的功能</h2>
<p>写时复制 <code>copy on right</code>功能使得非常时候做快照。</p>
<p>子卷功能可以更方便的分区。以及添加新设备。</p>
<h2 id="官方手册">
  <a class="anchor inpage" href="#%e5%ae%98%e6%96%b9%e6%89%8b%e5%86%8c">##</a>官方手册</h2>
<details open>
    <summary>man</summary><pre
        class="chroma codeblock"
      ><code class="language-man" data-lang="man"
          ><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span>BTRFS(8)                             BTRFS                             BTRFS(8)
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span>NAME
</span></span><span style="display:flex;"><span>       btrfs - a toolbox to manage btrfs filesystems
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span>SYNOPSIS
</span></span><span style="display:flex;"><span>       btrfs [global options] &lt;group&gt; [&lt;group&gt;...] &lt;command&gt; [options] [&lt;args&gt;]
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span>DESCRIPTION
</span></span><span style="display:flex;"><span>       The  btrfs  utility  is a toolbox for managing btrfs filesystems.  There
</span></span><span style="display:flex;"><span>       are command groups to work with subvolumes, devices, for whole  filesys‐
</span></span><span style="display:flex;"><span>       tem or other specific actions. See section COMMANDS.
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span>       There  are also standalone tools for some tasks like btrfs-convert(8) or
</span></span><span style="display:flex;"><span>       btrfstune(8) that were separate historically and/or haven&#39;t been  merged
</span></span><span style="display:flex;"><span>       to the main utility. See section STANDALONE TOOLS for more details.
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span>       For  other topics (mount options, etc) please refer to the separate man‐
</span></span><span style="display:flex;"><span>       ual page btrfs(5).
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span>COMMAND SYNTAX
</span></span><span style="display:flex;"><span>       Any command name can be shortened so long as the shortened form is unam‐
</span></span><span style="display:flex;"><span>       biguous, however, it  is  recommended  to  use  full  command  names  in
</span></span><span style="display:flex;"><span>       scripts.  All command groups have their manual page named btrfs-&lt;group&gt;.
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span>       For example: it is possible to run btrfs sub snaps instead of btrfs sub‐
</span></span><span style="display:flex;"><span>       volume snapshot.  But btrfs file s is not allowed, because file s may be
</span></span><span style="display:flex;"><span>       interpreted both as filesystem show and as filesystem sync.
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span>       If  the  command  name  is ambiguous, the list of conflicting options is
</span></span><span style="display:flex;"><span>       printed.
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span>       Sizes, both upon input and output, can be  expressed  in  either  SI  or
</span></span><span style="display:flex;"><span>       IEC-I  units  (see  numfmt(1))  with the suffix B appended.  All numbers
</span></span><span style="display:flex;"><span>       will be formatted according to the rules of the C locale  (ignoring  the
</span></span><span style="display:flex;"><span>       shell locale, see locale(7)).
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span>       For  an  overview  of  a given command use btrfs command --help or btrfs
</span></span><span style="display:flex;"><span>       [command...] help --full to print all available  options  for  all  com‐
</span></span><span style="display:flex;"><span>       mands.
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span>       There  are  global  options  that are passed between btrfs and the group
</span></span><span style="display:flex;"><span>       name and affect behaviour not specific to the command, e.g. verbosity or
</span></span><span style="display:flex;"><span>       the type of the output:
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span>          btrfs -q subvolume create ...
</span></span><span style="display:flex;"><span>          btrfs --dry-run subvolume create ...
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span>       --format &lt;format&gt;
</span></span><span style="display:flex;"><span>              if supported by the command, print subcommand output in that for‐
</span></span><span style="display:flex;"><span>              mat (text, json)
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span>       -v|--verbose
</span></span><span style="display:flex;"><span>              increase verbosity of the subcommand
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span>       -q|--quiet
</span></span><span style="display:flex;"><span>              print only errors
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span>       --log &lt;level&gt;
</span></span><span style="display:flex;"><span>              set log level (default, info, verbose, debug, quiet)
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span>       The remaining options are relevant only for the main tool:
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span>       --help print condensed help for all subcommands
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span>       --version
</span></span><span style="display:flex;"><span>              print version string
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span>COMMANDS
</span></span><span style="display:flex;"><span>       balance
</span></span><span style="display:flex;"><span>              Balance btrfs filesystem chunks across single or several devices.
</span></span><span style="display:flex;"><span>              See btrfs-balance(8) for details.
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span>       check  Do off-line check on a btrfs filesystem.  See btrfs-check(8)  for
</span></span><span style="display:flex;"><span>              details.
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span>       device Manage devices managed by btrfs, including add/delete/scan and so
</span></span><span style="display:flex;"><span>              on.  See btrfs-device(8) for details.
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span>       filesystem
</span></span><span style="display:flex;"><span>              Manage  a  btrfs  filesystem, including label setting/sync and so
</span></span><span style="display:flex;"><span>              on.  See btrfs-filesystem(8) for details.
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span>       inspect-internal
</span></span><span style="display:flex;"><span>              Debug       tools       for       developers/hackers.         See
</span></span><span style="display:flex;"><span>              btrfs-inspect-internal(8) for details.
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span>       property
</span></span><span style="display:flex;"><span>              Get/set a property from/to a btrfs object.  See btrfs-property(8)
</span></span><span style="display:flex;"><span>              for details.
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span>       qgroup Manage   quota   group(qgroup)   for   btrfs   filesystem.    See
</span></span><span style="display:flex;"><span>              btrfs-qgroup(8) for details.
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span>       quota  Manage quota on btrfs filesystem like  enabling/rescan  and  etc.
</span></span><span style="display:flex;"><span>              See btrfs-quota(8) and btrfs-qgroup(8) for details.
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span>       receive
</span></span><span style="display:flex;"><span>              Receive  subvolume data from stdin/file for restore and etc.  See
</span></span><span style="display:flex;"><span>              btrfs-receive(8) for details.
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span>       replace
</span></span><span style="display:flex;"><span>              Replace btrfs devices.  See btrfs-replace(8) for details.
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span>       rescue Try to rescue damaged btrfs filesystem.  See btrfs-rescue(8)  for
</span></span><span style="display:flex;"><span>              details.
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span>       restore
</span></span><span style="display:flex;"><span>              Try  to  restore  files  from  a  damaged  btrfs filesystem.  See
</span></span><span style="display:flex;"><span>              btrfs-restore(8) for details.
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span>       scrub  Scrub a btrfs filesystem.  See btrfs-scrub(8) for details.
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span>       send   Send subvolume data to  stdout/file  for  backup  and  etc.   See
</span></span><span style="display:flex;"><span>              btrfs-send(8) for details.
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span>       subvolume
</span></span><span style="display:flex;"><span>              Create/delete/list/manage       btrfs       subvolume.        See
</span></span><span style="display:flex;"><span>              btrfs-subvolume(8) for details.
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span>STANDALONE TOOLS
</span></span><span style="display:flex;"><span>       New functionality could be provided using  a  standalone  tool.  If  the
</span></span><span style="display:flex;"><span>       functionality  proves to be useful, then the standalone tool is declared
</span></span><span style="display:flex;"><span>       obsolete and its functionality is copied  to  the  main  tool.  Obsolete
</span></span><span style="display:flex;"><span>       tools are removed after a long (years) depreciation period.
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span>       Tools that are still in active use without an equivalent in btrfs:
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span>       btrfs-convert
</span></span><span style="display:flex;"><span>              in-place conversion from ext2/3/4 filesystems to btrfs
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span>       btrfstune
</span></span><span style="display:flex;"><span>              tweak some filesystem properties on a unmounted filesystem
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span>       btrfs-select-super
</span></span><span style="display:flex;"><span>              rescue tool to overwrite primary superblock from a spare copy
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span>       btrfs-find-root
</span></span><span style="display:flex;"><span>              rescue helper to find tree roots in a filesystem
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span>       For  space-constrained environments, it&#39;s possible to build a single bi‐
</span></span><span style="display:flex;"><span>       nary with functionality of several standalone tools. This  is  following
</span></span><span style="display:flex;"><span>       the  concept  of  busybox where the file name selects the functionality.
</span></span><span style="display:flex;"><span>       This works for symlinks or hardlinks. The full list can be  obtained  by
</span></span><span style="display:flex;"><span>       btrfs help --box.
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span>EXIT STATUS
</span></span><span style="display:flex;"><span>       btrfs returns a zero exit status if it succeeds. Non zero is returned in
</span></span><span style="display:flex;"><span>       case of failure.
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span>AVAILABILITY
</span></span><span style="display:flex;"><span>       btrfs  is  part  of btrfs-progs.  Please refer to the documentation at ‐
</span></span><span style="display:flex;"><span>       https://btrfs.readthedocs.io.
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span>SEE ALSO
</span></span><span style="display:flex;"><span>       btrfs(5),    btrfs-balance(8),     btrfs-check(8),     btrfs-convert(8),
</span></span><span style="display:flex;"><span>       btrfs-device(8),     btrfs-filesystem(8),     btrfs-inspect-internal(8),
</span></span><span style="display:flex;"><span>       btrfs-property(8),  btrfs-qgroup(8),  btrfs-quota(8),  btrfs-receive(8),
</span></span><span style="display:flex;"><span>       btrfs-replace(8),   btrfs-rescue(8),  btrfs-restore(8),  btrfs-scrub(8),
</span></span><span style="display:flex;"><span>       btrfs-send(8), btrfs-subvolume(8), btrfstune(8), mkfs.btrfs(8)
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span>6.14                              Mar 27, 2025                         BTRFS(8)</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="快照">
  <a class="anchor inpage" href="#%e5%bf%ab%e7%85%a7">##</a>快照</h2>
<p>用timeshift和snapper做快照。子卷布局</p>
<details open>
    <summary>TEXT</summary><pre
        class="codeblock"
      ><code class="language-" data-lang="">ID 257 gen 96108 top level 5 path @home
ID 318 gen 105959 top level 257 path @home/username
ID 268 gen 96108 top level 318 path @home/username/.snapshots
ID 269 gen 96108 top level 268 path @home/username/.snapshots/1/snapshot
ID 258 gen 105883 top level 5 path @root
ID 259 gen 105850 top level 5 path @cache
ID 260 gen 105959 top level 5 path @log
ID 261 gen 105942 top level 5 path @tmp
ID 262 gen 98722 top level 5 path @opt
ID 273 gen 96108 top level 262 path @opt/.snapshots
ID 274 gen 96108 top level 258 path @root/.snapshots
ID 285 gen 96433 top level 274 path @root/.snapshots/1/snapshot
ID 290 gen 105959 top level 5 path @
ID 519 gen 96445 top level 268 path @home/username/.snapshots/2/snapshot
ID 536 gen 103272 top level 5 path timeshift-btrfs/snapshots/2025-04-21_12-54-20/@
ID 537 gen 104133 top level 5 path timeshift-btrfs/snapshots/2025-04-21_20-12-43/@</code><button onclick="copyCode(this)" class="copybtn">copy</button></pre></details>

  <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>timeshift</code>备份，并且回滚过一次（从@的ID可以看出来，不是安装时创建的256），而<code>/home/username</code>,<code>/home/root</code>,<code>/home/opt</code>用<code>snapper</code>做了几个快照</p>
<h3 id="timeshift-备份根目录">
  <a class="anchor inpage" href="#timeshift-%e5%a4%87%e4%bb%bd%e6%a0%b9%e7%9b%ae%e5%bd%95">###</a>timeshift 备份根目录</h3>
<p>注意<code>btrfs</code>的子卷布局，根目录必须是<code>@</code>，例如</p>
<details open>
    <summary>TEXT</summary><pre
        class="codeblock"
      ><code class="language-" data-lang="">ID 257 gen 96108 top level 5 path @home
ID 258 gen 105883 top level 5 path @root
ID 259 gen 105850 top level 5 path @cache
ID 260 gen 105930 top level 5 path @log
ID 261 gen 105928 top level 5 path @tmp
ID 262 gen 98722 top level 5 path @opt
ID 290 gen 105929 top level 5 path @</code><button onclick="copyCode(this)" class="copybtn">copy</button></pre></details>

  <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="snapper-备份子卷">
  <a class="anchor inpage" href="#snapper-%e5%a4%87%e4%bb%bd%e5%ad%90%e5%8d%b7">###</a>snapper 备份子卷</h3>
<p>参考：</p>
<ul>
<li>
</li>
<li>
</li>
</ul>
<p>snapper更加灵活。首先创建一个snapper的配置文件</p>
<details open>
    <summary>sh</summary><pre
        class="chroma codeblock"
      ><code class="language-sh" data-lang="sh"
          ><span style="display:flex;"><span>sudo snapper -c <span style="color:#f92672">[</span>name of config<span style="color:#f92672">]</span> create-config <span style="color:#f92672">[</span>path-to-subvol<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>snapper</code>默认配置名是<code>root</code></p>
<details open>
    <summary>sh</summary><pre
        class="chroma codeblock"
      ><code class="language-sh" data-lang="sh"
          ><span style="display:flex;"><span>sudo snapper -c root create-config /</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>snapper</code>默认会创建子卷<code>/.snapshots</code>，似乎是<code>opensuse</code>风格的，把它调整成一般的布局</p>
<details open>
    <summary>TEXT</summary><pre
        class="codeblock"
      ><code class="language-" data-lang="">sudo umount /.snapshots
sudo rm -r /.snapshots
sudo btrfs subvolume delete /.snapshots
sudo mkdir /.snapshots
sudo mount -o subvol=/ /dev/nvme0n1p1 /mnt
sudo btrfs subvolume create /mnt/@snapshots</code><button onclick="copyCode(this)" class="copybtn">copy</button></pre></details>

  <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>/opt (@opt)</code>,<code>/root (@root)</code>。</p>
<p>对用户目录，首先有<code>@home</code>子卷挂载<code>/home</code>，然后用</p>
<details open>
    <summary>sh</summary><pre
        class="chroma codeblock"
      ><code class="language-sh" data-lang="sh"
          ><span style="display:flex;"><span>useradd
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span>Usage: useradd <span style="color:#f92672">[</span>options<span style="color:#f92672">]</span> LOGIN
</span></span><span style="display:flex;"><span>       useradd -D
</span></span><span style="display:flex;"><span>       useradd -D <span style="color:#f92672">[</span>options<span style="color:#f92672">]</span>
</span></span><span style="display:flex;"><span>Options:
</span></span><span style="display:flex;"><span>      --btrfs-subvolume-home    use BTRFS subvolume <span style="color:#66d9ef">for</span> home directory</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>@home/user_name</code>子卷挂载用户家目录<code>/home/user_name</code>。这样再用上述方法可以对特定用户的家目录做快照。子卷会像</p>
<h3 id="从快照中恢复">
  <a class="anchor inpage" href="#%e4%bb%8e%e5%bf%ab%e7%85%a7%e4%b8%ad%e6%81%a2%e5%a4%8d">###</a>从快照中恢复</h3>
<p>对snapper创建的<code>/</code>的快照，复杂的手动方法，要从live
USB开始，就是安装<code>arch</code>时的live系统</p>
<details open>
    <summary>sh</summary><pre
        class="chroma codeblock"
      ><code class="language-sh" data-lang="sh"
          ><span style="display:flex;"><span>sudo mount /dev/nvme0n1p6 /mnt
</span></span><span style="display:flex;"><span>cd /mnt
</span></span><span style="display:flex;"><span>sudo mv /mnt/@ /mnt/@.broken
</span></span><span style="display:flex;"><span>sudo btrfs subvolume snapshot /mnt/@snapshots/<span style="color:#f92672">{</span>number<span style="color:#f92672">}</span>/snapshot /mnt/@
</span></span><span style="display:flex;"><span>sudo btrfs subvolume delete /mnt/@.broken</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>不进入live系统的方法，看上去很危险，最好回滚后立刻重启</p>
<details open>
    <summary>sh</summary><pre
        class="chroma codeblock"
      ><code class="language-sh" data-lang="sh"
          ><span style="display:flex;"><span>sudo mount -o subvol<span style="color:#f92672">=</span>/ /dev/nvme0n1p1 /mnt
</span></span><span style="display:flex;"><span>sudo btrfs subvolume snapshot /mnt/@ /mnt/@bad
</span></span><span style="display:flex;"><span>sudo btrfs subvolume delete /mnt/@
</span></span><span style="display:flex;"><span>sudo btrfs subvolume snapshot /mnt/@snapshots/要恢复的快照号/snapshot /mnt/@</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>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>set -e
</span></span><span style="display:flex;"><span><span style="color:#66d9ef">if</span> <span style="color:#f92672">[[</span> x<span style="color:#e6db74">&#34;</span>$1<span style="color:#e6db74">&#34;</span> <span style="color:#f92672">==</span> x <span style="color:#f92672">]]</span>; <span style="color:#66d9ef">then</span>
</span></span><span style="display:flex;"><span>  echo <span style="color:#e6db74">&#34;No snapshot number given.&#34;</span> 1&gt;&amp;<span style="color:#ae81ff">2</span>
</span></span><span style="display:flex;"><span>  echo <span style="color:#e6db74">&#34;Usage: rollback [snapshot to rollback]&#34;</span> 1&gt;&amp;<span style="color:#ae81ff">2</span>
</span></span><span style="display:flex;"><span>  exit <span style="color:#ae81ff">1</span>
</span></span><span style="display:flex;"><span><span style="color:#66d9ef">fi</span>
</span></span><span style="display:flex;"><span>root_dev<span style="color:#f92672">=</span><span style="color:#e6db74">`</span>findmnt -n -o SOURCE / | sed <span style="color:#e6db74">&#39;s/\[.*\]//g&#39;</span><span style="color:#e6db74">`</span>
</span></span><span style="display:flex;"><span>root_subvol<span style="color:#f92672">=</span><span style="color:#e6db74">`</span>findmnt -n -o SOURCE / | sed <span style="color:#e6db74">&#39;s/.*\[\(.*\)\].*/\1/&#39;</span><span style="color:#e6db74">`</span>
</span></span><span style="display:flex;"><span>echo <span style="color:#e6db74">&#34;&gt;= Rollback to #</span>$1<span style="color:#e6db74"> on device </span>$root_dev<span style="color:#e6db74">&#34;</span>
</span></span><span style="display:flex;"><span><span style="color:#75715e"># create snapshot before</span>
</span></span><span style="display:flex;"><span>sudo snapper create --read-only --type single -d <span style="color:#e6db74">&#34;Before rollback to #</span>$1<span style="color:#e6db74">&#34;</span> --userdata important<span style="color:#f92672">=</span>yes
</span></span><span style="display:flex;"><span>sudo mount -o subvol<span style="color:#f92672">=</span>/ $root_dev /mnt
</span></span><span style="display:flex;"><span><span style="color:#75715e"># check enviornment</span>
</span></span><span style="display:flex;"><span><span style="color:#66d9ef">if</span> <span style="color:#f92672">[[</span> x<span style="color:#e6db74">&#34;</span>$root_subvol<span style="color:#e6db74">&#34;</span> <span style="color:#f92672">==</span> x/@ <span style="color:#f92672">]]</span>; <span style="color:#66d9ef">then</span>
</span></span><span style="display:flex;"><span>  echo <span style="color:#e6db74">&#34;Warning: Not run in a snapshot, a subvolume @old will be created. You should consider remove it after reboot.&#34;</span> 1&gt;&amp;<span style="color:#ae81ff">2</span>
</span></span><span style="display:flex;"><span>  <span style="color:#66d9ef">if</span> <span style="color:#f92672">[[</span> -d /mnt/@old <span style="color:#f92672">]]</span>; <span style="color:#66d9ef">then</span>
</span></span><span style="display:flex;"><span>    echo <span style="color:#e6db74">&#34;Found last @old, remove it.&#34;</span>
</span></span><span style="display:flex;"><span>    sudo btrfs subvolume delete /mnt/@old &gt;/dev/null
</span></span><span style="display:flex;"><span>  <span style="color:#66d9ef">fi</span>
</span></span><span style="display:flex;"><span>  sudo mv /mnt/@ /mnt/@old
</span></span><span style="display:flex;"><span><span style="color:#66d9ef">else</span>
</span></span><span style="display:flex;"><span>  sudo btrfs subvolume delete /mnt/@ &gt;/dev/null
</span></span><span style="display:flex;"><span><span style="color:#66d9ef">fi</span>
</span></span><span style="display:flex;"><span>sudo btrfs subvolume snapshot /mnt/@snapshots/$1/snapshot /mnt/@ &gt;/dev/null
</span></span><span style="display:flex;"><span>sudo umount /mnt</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>snapper</code>快照，直接用</p>
<details open>
    <summary>sh</summary><pre
        class="chroma codeblock"
      ><code class="language-sh" data-lang="sh"
          ><span style="display:flex;"><span>snapper -c <span style="color:#f92672">[</span>config<span style="color:#f92672">]</span> rollback <span style="color:#f92672">[</span>number<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>timeshift</code>，直接gui操作就行。</p>
<p>回滚后最好立刻重启。</p>
<h2 id="技巧">
  <a class="anchor inpage" href="#%e6%8a%80%e5%b7%a7">##</a>技巧</h2>
<details open>
    <summary>TEXT</summary><pre
        class="codeblock"
      ><code class="language-" data-lang="">btrfs filesystem du -s /path/to/subvolume</code><button onclick="copyCode(this)" class="copybtn">copy</button></pre></details>

  <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="reference">
  <a class="anchor inpage" href="#reference">##</a>Reference</h2>
<ol>
<li>
</li>
<li>
</li>
<li>
</li>
<li>
</li>
<li>
</li>
<li>
</li>
</ol>
]]></content:encoded></item></channel></rss>