<?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>GeekonDocs</title><link>https://hiraethecho.github.io/docs/tags/geek/</link><description>Recent contentinGeekonDocs</description><generator>Hugo --0.152.2</generator><language>en</language><managingEditor>wyz2016zxc@outlook.com(Hiraeth)</managingEditor><webMaster>wyz2016zxc@outlook.com(Hiraeth)</webMaster><lastBuildDate>Mon, 16 Mar 2026 15:39:39 +0800</lastBuildDate><atom:link href="https://hiraethecho.github.io/docs/tags/geek/index.xml" rel="self" type="application/rss+xml"/><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>一些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>大模型使用概览</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>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>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>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>豆瓣记录导入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>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>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>用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>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>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>折腾的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>双系统安装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>用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>